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