1 /* vi: set sw=4 ts=4: */
3 * Architecture specific code used by dl-startup.c
4 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
6 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
10 #include <bits/arm_bx.h>
12 #if !defined(__thumb__)
16 " .type _start,%function\n"
19 " @ at start time, all the args are on the stack\n"
22 " @ returns user entry point in r0\n"
24 " @ we are PIC code, so get global offset table\n"
25 " ldr sl, .L_GET_GOT\n"
28 " @ See if we were run as a command with the executable file\n"
29 " @ name as an extra leading argument.\n"
30 " ldr r4, .L_SKIP_ARGS\n"
32 " @ get the original arg count\n"
34 " @ subtract _dl_skip_args from it\n"
36 " @ adjust the stack pointer to skip them\n"
37 " add sp, sp, r4, lsl #2\n"
38 " @ get the argv address\n"
40 " @ store the new argc in the new stack location\n"
43 " add r3, r2, r1, lsl #2\n"
46 " @ load the finalizer function\n"
47 " ldr r0, .L_FINI_PROC\n"
49 " @ jump to the user_s entry point\n"
50 #if defined(__USE_BX__)
56 " .word _GLOBAL_OFFSET_TABLE_ - .L_GOT_GOT - 4\n"
58 " .word _dl_skip_args(GOTOFF)\n"
60 " .word _dl_fini(GOT)\n"
62 " .size _start,.-_start\n"
70 " .type _start,%function\n"
72 " @ dumb: can't persuade the linker to make the start address\n"
73 " @ odd, so use an arm function and change to thumb (_dl_start\n"
75 " adr r0, __dl_thumb_start+1\n"
79 " .globl __dl_thumb_start\n"
81 " .type __dl_thumb_start,%function\n"
83 " @ at start time, all the args are on the stack\n"
86 " @ returns user entry point in r0\n"
88 " @ we are PIC code, so get global offset table\n"
89 " ldr r7, .L_GET_GOT\n"
92 " @ See if we were run as a command with the executable file\n"
93 " @ name as an extra leading argument.\n"
94 " ldr r4, .L_SKIP_ARGS\n"
96 " @ get the original arg count\n"
98 " @ subtract _dl_skip_args from it\n"
100 " @ adjust the stack pointer to skip them\n"
103 " @ get the argv address\n"
105 " @ store the new argc in the new stack location\n"
112 " @ load the finalizer function\n"
113 " ldr r0, .L_FINI_PROC\n"
114 " ldr r0, [r7, r0]\n"
115 " @ jump to the user_s entry point\n"
116 #if defined(__USE_BX__)
123 " .word _GLOBAL_OFFSET_TABLE_ - .L_GOT_GOT - 4\n"
125 " .word _dl_skip_args(GOTOFF)\n"
127 " .word _dl_fini(GOT)\n"
129 " .size _start,.-_start\n"
135 /* Get a pointer to the argv array. On many platforms this can be just
136 * the address of the first argument, on other platforms we need to
137 * do something a little more subtle here. */
138 #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*)ARGS)+1)
140 /* Handle relocation of the symbols in the dynamic loader. */
141 static __always_inline
142 void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
143 unsigned long symbol_addr, unsigned long load_addr, Elf32_Sym *symtab)
145 switch (ELF_R_TYPE(rpnt->r_info)) {
149 *reloc_addr += symbol_addr;
153 unsigned long addend;
154 long newvalue, topbits;
156 addend = *reloc_addr & 0x00ffffff;
157 if (addend & 0x00800000) addend |= 0xff000000;
159 newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
160 topbits = newvalue & 0xfe000000;
161 if (topbits != 0xfe000000 && topbits != 0x00000000)
164 /* Don't bother with this during ldso initilization... */
165 newvalue = fix_bad_pc24(reloc_addr, symbol_addr)
166 - (unsigned long)reloc_addr + (addend << 2);
167 topbits = newvalue & 0xfe000000;
168 if (unlikely(topbits != 0xfe000000 && topbits != 0x00000000))
170 SEND_STDERR("R_ARM_PC24 relocation out of range\n");
174 SEND_STDERR("R_ARM_PC24 relocation out of range\n");
179 symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
180 *reloc_addr = symbol_addr;
184 case R_ARM_JUMP_SLOT:
185 *reloc_addr = symbol_addr;
188 *reloc_addr += load_addr;
193 SEND_STDERR("Unsupported relocation type\n");