#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"
"pushl %esp\n\t"
"call start\n\t"
"addl $4, %esp\n\t"
"call 0b\n\t"
"addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\t"
"movl program_skip_args@GOTOFF(%ebx), %eax\n\t"
"popl %edx\n\t"
"leal (%esp,%eax,4), %esp\n\t"
"subl %eax, %edx\n\t"
"pushl %edx\n\t"
"pushl %esp\n\t"
"xorl %ebp, %ebp\n\t"
"call initialize_shared_objects@PLT\n\t"
"addl $4, %esp\n\t"
"movl program_entry_point@GOTOFF(%ebx), %eax\n\t"
"leal finalize_shared_objects@GOTOFF(%ebx), %edx\n\t"
"jmp *%eax");
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;
base_address = (void *)dynamic_array - global_offset_table[0];
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;
}
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);
}