View of xos/usr/lib/ld-so/start.c


XOS | Parent Directory | View | Download

/* Code de demarrage. */
/* Copyright (C) 2008  Emmanuel Varoquaux
 
   This file is part of XOS.
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
#include <elf_sysv4.h>
 
#include <stdlib.h>
#include <unistd.h>
 
typedef void (main_t)(int, char **, char **, unsigned long *);
 
extern Elf32_Addr global_offset_table[] asm ("_GLOBAL_OFFSET_TABLE_") __attribute__ ((visibility ("hidden")));
extern Elf32_Dyn dynamic_array[] asm ("_DYNAMIC") __attribute__ ((visibility ("hidden")));
 
void __libc_init(int argc, char **argv, char **envp);
void __libc_fini();
void main(int argc, char **argv, char **envp, unsigned long *auxv);
 
void _start();
 
asm (".text\n"
     ".align 4\n"
     "0:\tmovl (%esp),%ebx\n\t"
     "ret\n"
     ".globl _start\n"
     ".align 4\n"
     "_start:\n\t"              /* point d'entree de l'editeur de liens dynamique */
     "pushl %esp\n\t"
     "call start\n\t"           /* demarrage de l'editeur de liens dynamique */
     "addl $4, %esp\n\t"
     "call 0b\n\t"
     "addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\t" /* %ebx pointe sur la GOT */
     "movl program_skip_args@GOTOFF(%ebx), %eax\n\t" /* nombre d'arguments a ignorer */
     "popl %edx\n\t"            /* depilement du nombre d'arguments initial */
     "leal (%esp,%eax,4), %esp\n\t" /* ajustement du tableau des arguments */
     "subl %eax, %edx\n\t"      /* ajustement du nombre d'arguments */
     "pushl %edx\n\t"           /* empilement du nouveau nombre d'arguments */
     "pushl %esp\n\t"
     "xorl %ebp, %ebp\n\t"
     "call initialize_shared_objects@PLT\n\t" /* fonction d'initialisation des bibliotheques */
     "addl $4, %esp\n\t"
     "movl program_entry_point@GOTOFF(%ebx), %eax\n\t" /* point d'entree */
     "leal finalize_shared_objects@GOTOFF(%ebx), %edx\n\t" /* fonction de terminaison */
     "jmp *%eax");              /* transfert du controle au programme */
 
static void start_bottom_half(void *initial_stack_ptr)
{
  int argc;
  char **argv;
  char **envp;
  unsigned long *auxv;
  void *p;
 
  p = initial_stack_ptr;
  argc = *(int *)p;
  p += sizeof (int);
  argv = p;
  p += (argc + 1) * sizeof (char *);
  envp = p;
  while (*(char **)p)
    p += sizeof (char *);
  p += sizeof (char *);
  auxv = p;
  __libc_init(argc, argv, envp);
  atexit(__libc_fini);
  return main(argc, argv, envp, auxv);
}
 
static inline void __attribute__ ((always_inline)) relocate(const Elf32_Rel *relocation_table, int relocation_table_size, void *base_address, const Elf32_Sym *symbol_table)
{
  int i;
  const Elf32_Rel *rel_entry;
  Elf32_Addr *rel_field;
 
  for (i = 0; i < relocation_table_size; i++) {
    rel_entry = &relocation_table[i];
    rel_field = base_address + rel_entry->r_offset;
    switch (ELF32_R_TYPE(rel_entry->r_info)) {
    case R_386_GLOB_DAT:
    case R_386_JMP_SLOT:
      *rel_field = (Elf32_Addr)(base_address + symbol_table[ELF32_R_SYM(rel_entry->r_info)].st_value);
      break;
    case R_386_RELATIVE:
      *rel_field += (Elf32_Addr)base_address;
      break;
    }
  }
}
 
static void __attribute__ ((used)) start(void *initial_stack_ptr)
{
  void *base_address;
  const Elf32_Sym *symbol_table;
  const Elf32_Rel *relocation_table;
  int relocation_table_size;
  const Elf32_Rel *plt_relocation_table;
  int plt_relocation_table_size;
  const Elf32_Dyn *dyn_entry;
 
  /* adresse de base */
  base_address = (void *)dynamic_array - global_offset_table[0];
 
  /* lecture des informations d'edition de liens dynamique */
  symbol_table = NULL;
  relocation_table = NULL;
  relocation_table_size = 0;
  plt_relocation_table = NULL;
  plt_relocation_table_size = 0;
  for (dyn_entry = dynamic_array; dyn_entry->d_tag != DT_NULL; dyn_entry++)
    switch (dyn_entry->d_tag) {
    case DT_PLTRELSZ:
      plt_relocation_table_size = dyn_entry->d_un.d_val / sizeof (Elf32_Rel);
      break;
    case DT_SYMTAB:
      symbol_table = base_address + dyn_entry->d_un.d_ptr;
      break;
    case DT_REL:
      relocation_table = base_address + dyn_entry->d_un.d_ptr;
      break;
    case DT_RELSZ:
      relocation_table_size = dyn_entry->d_un.d_val / sizeof (Elf32_Rel);
      break;
    case DT_JMPREL:
      plt_relocation_table = base_address + dyn_entry->d_un.d_ptr;
      break;
    }
 
  /* relocations */
  relocate(relocation_table, relocation_table_size, base_address, symbol_table);
  relocate(plt_relocation_table, plt_relocation_table_size, base_address, symbol_table);
 
  start_bottom_half(initial_stack_ptr);
}