]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/ldso/ldso/arm/dl-startup.h
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / ldso / ldso / arm / dl-startup.h
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Architecture specific code used by dl-startup.c
4  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
5  *
6  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
7  */
8
9 #include <features.h>
10 #include <bits/arm_bx.h>
11
12 #if !defined(__thumb__)
13 __asm__(
14     "   .text\n"
15     "   .globl  _start\n"
16     "   .type   _start,%function\n"
17         "       .hidden _start\n"
18         "_start:\n"
19         "       @ at start time, all the args are on the stack\n"
20         "       mov     r0, sp\n"
21         "       bl      _dl_start\n"
22         "       @ returns user entry point in r0\n"
23         "       mov     r6, r0\n"
24         "       @ we are PIC code, so get global offset table\n"
25         "       ldr     sl, .L_GET_GOT\n"
26         "       add     sl, pc, sl\n"
27         ".L_GOT_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"
31         "       ldr     r4, [sl, r4]\n"
32         "       @ get the original arg count\n"
33         "       ldr     r1, [sp]\n"
34         "       @ subtract _dl_skip_args from it\n"
35         "       sub     r1, r1, r4\n"
36         "       @ adjust the stack pointer to skip them\n"
37         "       add     sp, sp, r4, lsl #2\n"
38         "       @ get the argv address\n"
39         "       add     r2, sp, #4\n"
40         "       @ store the new argc in the new stack location\n"
41         "       str     r1, [sp]\n"
42         "       @ compute envp\n"
43         "       add     r3, r2, r1, lsl #2\n"
44         "       add     r3, r3, #4\n"
45         "\n\n"
46         "       @ load the finalizer function\n"
47         "       ldr     r0, .L_FINI_PROC\n"
48         "       ldr     r0, [sl, r0]\n"
49         "       @ jump to the user_s entry point\n"
50 #if defined(__USE_BX__)
51         "       bx      r6\n"
52 #else
53         "       mov     pc, r6\n"
54 #endif
55         ".L_GET_GOT:\n"
56         "       .word   _GLOBAL_OFFSET_TABLE_ - .L_GOT_GOT - 4\n"
57         ".L_SKIP_ARGS:\n"
58         "       .word   _dl_skip_args(GOTOFF)\n"
59         ".L_FINI_PROC:\n"
60         "       .word   _dl_fini(GOT)\n"
61         "\n\n"
62     "   .size   _start,.-_start\n"
63         ".previous\n"
64 );
65 #else
66 __asm__(
67     "   .text\n"
68     "   .arm\n"
69     "   .globl  _start\n"
70     "   .type   _start,%function\n"
71         "_start:\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"
74         "       @ is thumb)\n"
75         "       adr     r0, __dl_thumb_start+1\n"
76         "       bx      r0\n"
77         "\n\n"
78     "   .thumb\n"
79     "   .globl  __dl_thumb_start\n"
80     "   .thumb_func\n"
81     "   .type   __dl_thumb_start,%function\n"
82         "__dl_thumb_start:\n"
83         "       @ at start time, all the args are on the stack\n"
84         "       mov     r0, sp\n"
85         "       bl      _dl_start\n"
86         "       @ returns user entry point in r0\n"
87         "       mov     r6, r0\n"
88         "       @ we are PIC code, so get global offset table\n"
89         "       ldr     r7, .L_GET_GOT\n"
90         ".L_GOT_GOT:\n"
91         "       add     r7, pc\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"
95         "       ldr     r4, [r7, r4]\n"
96         "       @ get the original arg count\n"
97         "       ldr     r1, [sp]\n"
98         "       @ subtract _dl_skip_args from it\n"
99         "       sub     r1, r1, r4\n"
100         "       @ adjust the stack pointer to skip them\n"
101         "       lsl     r4, r4, #2\n"
102         "       add     sp, r4\n"
103         "       @ get the argv address\n"
104         "       add     r2, sp, #4\n"
105         "       @ store the new argc in the new stack location\n"
106         "       str     r1, [sp]\n"
107         "       @ compute envp\n"
108         "       lsl     r3, r1, #2\n"
109         "       add     r3, r3, r2\n"
110         "       add     r3, #4\n"
111         "\n\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__)
117         "       bx      r6\n"
118 #else
119         "       mov     pc, r6\n"
120 #endif
121         "\n\n"
122         ".L_GET_GOT:\n"
123         "       .word   _GLOBAL_OFFSET_TABLE_ - .L_GOT_GOT - 4\n"
124         ".L_SKIP_ARGS:\n"
125         "       .word   _dl_skip_args(GOTOFF)\n"
126         ".L_FINI_PROC:\n"
127         "       .word   _dl_fini(GOT)\n"
128         "\n\n"
129     "   .size   _start,.-_start\n"
130         ".previous\n"
131 );
132 #endif
133
134
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)
139
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)
144 {
145         switch (ELF_R_TYPE(rpnt->r_info)) {
146                 case R_ARM_NONE:
147                         break;
148                 case R_ARM_ABS32:
149                         *reloc_addr += symbol_addr;
150                         break;
151                 case R_ARM_PC24:
152                         {
153                                 unsigned long addend;
154                                 long newvalue, topbits;
155
156                                 addend = *reloc_addr & 0x00ffffff;
157                                 if (addend & 0x00800000) addend |= 0xff000000;
158
159                                 newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
160                                 topbits = newvalue & 0xfe000000;
161                                 if (topbits != 0xfe000000 && topbits != 0x00000000)
162                                 {
163 #if 0
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))
169                                         {
170                                                 SEND_STDERR("R_ARM_PC24 relocation out of range\n");
171                                                 _dl_exit(1);
172                                         }
173 #else
174                                         SEND_STDERR("R_ARM_PC24 relocation out of range\n");
175                                         _dl_exit(1);
176 #endif
177                                 }
178                                 newvalue >>= 2;
179                                 symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
180                                 *reloc_addr = symbol_addr;
181                                 break;
182                         }
183                 case R_ARM_GLOB_DAT:
184                 case R_ARM_JUMP_SLOT:
185                         *reloc_addr = symbol_addr;
186                         break;
187                 case R_ARM_RELATIVE:
188                         *reloc_addr += load_addr;
189                         break;
190                 case R_ARM_COPY:
191                         break;
192                 default:
193                         SEND_STDERR("Unsupported relocation type\n");
194                         _dl_exit(1);
195         }
196 }