123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- /* vi: set sw=4 ts=4: */
- /*
- * Architecture specific code used by dl-startup.c
- * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
- */
- asm(
- " .text\n"
- " .globl _start\n"
- " .type _start,%function\n"
- "_start:\n"
- " @ at start time, all the args are on the stack\n"
- " mov r0, sp\n"
- " bl _dl_start\n"
- " @ returns user entry point in r0\n"
- " mov r6, r0\n"
- " @ we are PIC code, so get global offset table\n"
- " ldr sl, .L_GET_GOT\n"
- " add sl, pc, sl\n"
- ".L_GOT_GOT:\n"
- " @ See if we were run as a command with the executable file\n"
- " @ name as an extra leading argument.\n"
- " ldr r4, .L_SKIP_ARGS\n"
- " ldr r4, [sl, r4]\n"
- " @ get the original arg count\n"
- " ldr r1, [sp]\n"
- " @ subtract _dl_skip_args from it\n"
- " sub r1, r1, r4\n"
- " @ adjust the stack pointer to skip them\n"
- " add sp, sp, r4, lsl #2\n"
- " @ get the argv address\n"
- " add r2, sp, #4\n"
- " @ store the new argc in the new stack location\n"
- " str r1, [sp]\n"
- " @ compute envp\n"
- " add r3, r2, r1, lsl #2\n"
- " add r3, r3, #4\n"
- "\n\n"
- " @ load the finalizer function\n"
- " ldr r0, .L_FINI_PROC\n"
- " ldr r0, [sl, r0]\n"
- " @ jump to the user_s entry point\n"
- " mov pc, r6\n"
- ".L_GET_GOT:\n"
- " .word _GLOBAL_OFFSET_TABLE_ - .L_GOT_GOT - 4\n"
- ".L_SKIP_ARGS:\n"
- " .word _dl_skip_args(GOTOFF)\n"
- ".L_FINI_PROC:\n"
- " .word _dl_fini(GOT)\n"
- "\n\n"
- " .size _start,.-_start\n"
- ".previous\n"
- );
- /* Get a pointer to the argv array. On many platforms this can be just
- * the address if the first argument, on other platforms we need to
- * do something a little more subtle here. */
- #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*)ARGS)+1)
- /* Handle relocation of the symbols in the dynamic loader. */
- static inline
- void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
- unsigned long symbol_addr, unsigned long load_addr, Elf32_Sym *symtab)
- {
- switch (ELF32_R_TYPE(rpnt->r_info)) {
- case R_ARM_NONE:
- break;
- case R_ARM_ABS32:
- *reloc_addr += symbol_addr;
- break;
- case R_ARM_PC24:
- {
- unsigned long addend;
- long newvalue, topbits;
- addend = *reloc_addr & 0x00ffffff;
- if (addend & 0x00800000) addend |= 0xff000000;
- newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
- topbits = newvalue & 0xfe000000;
- if (topbits != 0xfe000000 && topbits != 0x00000000)
- {
- #if 0
- // Don't bother with this during ldso initilization...
- newvalue = fix_bad_pc24(reloc_addr, symbol_addr)
- - (unsigned long)reloc_addr + (addend << 2);
- topbits = newvalue & 0xfe000000;
- if (unlikely(topbits != 0xfe000000 && topbits != 0x00000000))
- {
- SEND_STDERR("R_ARM_PC24 relocation out of range\n");
- _dl_exit(1);
- }
- #else
- SEND_STDERR("R_ARM_PC24 relocation out of range\n");
- _dl_exit(1);
- #endif
- }
- newvalue >>= 2;
- symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
- *reloc_addr = symbol_addr;
- break;
- }
- case R_ARM_GLOB_DAT:
- case R_ARM_JUMP_SLOT:
- *reloc_addr = symbol_addr;
- break;
- case R_ARM_RELATIVE:
- *reloc_addr += load_addr;
- break;
- case R_ARM_COPY:
- break;
- default:
- SEND_STDERR("Unsupported relocation type\n");
- _dl_exit(1);
- }
- }
- /* Transfer control to the user's application, once the dynamic loader is
- * done. This routine has to exit the current function, then call the
- * _dl_elf_main function. */
- #define START() return _dl_elf_main;
|