/* 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 . */ #include #include #include 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); }