]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/uclibc/uclibc-0.9.28/thumb-resolve.patch
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / uclibc / uclibc-0.9.28 / thumb-resolve.patch
1 # This change reimplements the ARM _dl_linux_resolve entry point - this is
2 # called to resolve DLL PLT entries.  The assembler is changed to be thumb
3 # compatible and slightly faster, the C function, _dl_linux_resolver (note
4 # the extra r) is changed to take a byte address in place of an 8 byte
5 # count (faster in caller and callee, and slightly easier to understand).
6 #
7 --- uClibc-0.9.28/.pc/thumb-resolve.patch/ldso/ldso/arm/elfinterp.c     2005-08-17 15:49:41.000000000 -0700
8 +++ uClibc-0.9.28/ldso/ldso/arm/elfinterp.c     2005-09-17 12:55:26.379172744 -0700
9 @@ -55,7 +55,7 @@
10  
11         rel_addr = (ELF_RELOC *) tpnt->dynamic_info[DT_JMPREL];
12  
13 -       this_reloc = rel_addr + (reloc_entry >> 3);
14 +       this_reloc = rel_addr + reloc_entry;
15         reloc_type = ELF32_R_TYPE(this_reloc->r_info);
16         symtab_index = ELF32_R_SYM(this_reloc->r_info);
17  
18 @@ -84,7 +84,9 @@
19                 _dl_exit(1);
20         };
21  #if defined (__SUPPORT_LD_DEBUG__)
22 +#if !defined __SUPPORT_LD_DEBUG_EARLY__
23         if ((unsigned long) got_addr < 0x40000000)
24 +#endif
25         {
26                 if (_dl_debug_bindings)
27                 {
28 --- uClibc-0.9.28/.pc/thumb-resolve.patch/ldso/ldso/arm/resolve.S       2005-08-17 15:49:41.000000000 -0700
29 +++ uClibc-0.9.28/ldso/ldso/arm/resolve.S       2005-09-17 11:02:27.860627464 -0700
30 @@ -1,43 +1,163 @@
31  /*
32 - * This function is _not_ called directly.  It is jumped to (so no return
33 - * address is on the stack) when attempting to use a symbol that has not yet
34 - * been resolved.  The first time a jump symbol (such as a function call inside
35 - * a shared library) is used (before it gets resolved) it will jump here to
36 - * _dl_linux_resolve.  When we get called the stack looks like this:
37 - *     reloc_entry
38 - *     tpnt
39 - *
40 - * This function saves all the registers, puts a copy of reloc_entry and tpnt
41 - * on the stack (as function arguments) then make the function call
42 - * _dl_linux_resolver(tpnt, reloc_entry).  _dl_linux_resolver() figures out
43 - * where the jump symbol is _really_ supposed to have jumped to and returns
44 - * that to us.  Once we have that, we overwrite tpnt with this fixed up
45 - * address. We then clean up after ourselves, put all the registers back how we
46 - * found them, then we jump to the fixed up address, which is where the jump
47 - * symbol that got us here really wanted to jump to in the first place.
48 - *  -Erik Andersen
49 + * On ARM the PLT contains the following three instructions (for ARM calls):
50 + *
51 + *     add   ip, pc, #0xNN00000
52 + *     add   ip, ip, #0xNN000
53 + *     ldr   pc, [ip, #0xNNN]!
54 + *
55 + * So that, effectively, causes the following to happen:
56 + *
57 + *     ip := pc+0x0NNNNNNN
58 + *     pc := *ip
59 + *
60 + * For thumb the above fragment is preceded by "bx pc, nop" to switch to ARM
61 + * mode and the thumb 'bl' must go to PLT-4 - the PLT entry is expanded by
62 + * four bytes to accomodate the trampoline code.
63 + *
64 + * 0x0NNNNNNN is the offset of the GOT entry for this function relative to
65 + * the PLT entry for this function (where the code is).  So the code in the
66 + * PLT causes a branch to whatever is in the GOT, leaving the actual address
67 + * of the GOT entry in ip.  (Note that the GOT must follow the PLT - the
68 + * added value is 28 bit unsigned).
69 + *
70 + * ip is a pointer to the GOT entry for this function, the first time round
71 + * *ip points to this code:
72 + *
73 + *     str   lr, [sp, #-4]!    @ save lr
74 + *     ldr   lr, [pc, #4]      @ lr := *dat (&GOT_TABLE[0]-.)
75 + *     add   lr, pc, lr        @ lr += &dat (so lr == &GOT_TABLE[0])
76 + *     ldr   pc, [lr, #8]!     @ pc := GOT_TABLE[2]
77 + *dat: .long &GOT_TABLE[0] - .
78 + *
79 + * (this code is actually held in the first entry of the PLT).  The code
80 + * preserves lr then uses it as a scratch register (this preserves the ip
81 + * value calculated above).  GOT_TABLE[2] is initialized by INIT_GOT in
82 + * dl-sysdep.h to point to _dl_linux_resolve - this function.  The first
83 + * three entries in the GOT are reserved, then they are followed by the
84 + * entries for the PLT entries, in order.
85 + *
86 + * The linker initialises the following (non-reserved) GOT entries to
87 + * the offset of the PLT with an associated relocation so that on load
88 + * the entry is relocated to point to the PLT - the above code.
89 + *
90 + * The net effect of all this is that on the first call to an external (as
91 + * yet unresolved) function all seven of the above instructions are
92 + * executed in sequence and the program ends up executing _dl_linux_resolve
93 + * with the following important values in registers:
94 + *
95 + *     ip - a pointer to the GOT entry for the as yet unresolved function
96 + *     lr - &GOT_TABLE[2]
97 + *
98 + * GOT_TABLE[2] has already been initialised to _dl_linux_resolve, and
99 + * GOT_TABLE[1] is a pointer to the (elf_resolve*) from INIT_GOT.
100 + * _dl_linux_resolve unfrobnicates the ip and lr values to obtain arguments
101 + * for a call to _dl_linux_resolver (not the additional 'r' on the end) -
102 + * this is in elfinterp.c in this directory.  The call takes arguments:
103 + *
104 + *     _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
105 + *
106 + * And returns the address of the function, it also overwrites the GOT
107 + * table entry so that the next time round only the first code fragment will
108 + * be executed - it will call the function directly.
109 + *
110 + * [[Of course, this simply doesn't work on ARM 4T with a thumb target - because
111 + * 4T did not do the thumb/arm change on ldr pc!  It can be made to work by
112 + * changing _dl_linux_resolver to return __%s_from_arm for an STT_TFUNC, but
113 + * this hasn't been done, and there is no guarantee that the linker generated
114 + * that glue anyway.]]
115 + *
116 + * _dl_linux_resolve gets the arguments to call the resolver as follows:
117 + *
118 + *     tpnt            GOT_TABLE[1], [lr-4]
119 + *     reloc-entry     &GOT-&GOT_TABLE[3], (ip - lr - 4)/4
120 + *
121 + * (I.e. 'GOT' means the table entry for this function, the thing for which
122 + * ip holds the address.)  The reloc-entry is passed as an index, since
123 + * since the GOT table has 4 byte entries the code needs to divide this by 4
124 + * to get the actual index.
125 + *
126 + * John Bowler, August 13, 2005 - determined by experiment and examination
127 + * of generated ARM code (there was no documentation...)
128 + *
129 + * This code is all ARM code - not thumb - _dl_linux_resolver may, itself,
130 + * be thumb, in which case the linker will insert the appropriate glue.  A
131 + * call from thumb to the PLT hits the trampoline code described above.
132 + * This code (now) builds a proper stack frame.
133 + *
134 + * The code does *not* set sb (r9,v6) - to do that the basic PLT instructions
135 + * would need to save sb and load the new value and that would require
136 + * support in the linker since it generates those instructions.  (Also note
137 + * that linux/uclibc seems to be using r10 - sl - as a PIC base register - see
138 + * dl-startup.c).
139   */
140 -
141 -#define sl r10
142 -#define fp r11
143 -#define ip r12
144 +#include <sys/syscall.h>
145  
146  .text
147 +.align 4       @ 16 byte boundary and there are 32 bytes below (arm case)
148 +#if !defined(__thumb__)
149 +.arm
150  .globl _dl_linux_resolve
151  .type _dl_linux_resolve,%function
152 -.align 4;
153  
154  _dl_linux_resolve:
155 -       stmdb sp!, {r0, r1, r2, r3, sl, fp}
156 -       sub r1, ip, lr
157 -       sub r1, r1, #4
158 -       add r1, r1, r1
159 -       ldr r0, [lr, #-4]
160 -       mov r3,r0
161 +       @ _dl_linux_resolver is a standard subroutine call, therefore it
162 +       @ preserves everything except r0-r3 (a1-a4), ip and lr.  This
163 +       @ function must branch to the real function, and that expects
164 +       @ r0-r3 and lr to be as they were before the whole PLT stuff -
165 +       @ ip can be trashed.
166 +       stmdb sp!, {r0-r3}
167 +       ldr r0, [lr, #-4]       @ r0 := [lr-4] (GOT_TABLE[1])
168 +       sub r1, lr, ip          @ r1 := (lr-ip) (a multple of 4)
169 +       mvn r1, r1, ASR #2      @ r1 := ~((lr-ip)>>2), since -x = (1+~x)
170 +                               @ ~x = -x-1, therefore ~(r1>>2) = (-((lr-ip)>>2)-1)
171 +                               @ = - ((lr-ip)/4) - 1 = (ip - lr - 4)/4, as required
172  
173         bl _dl_linux_resolver
174  
175 -       mov ip, r0
176 -       ldmia sp!, {r0, r1, r2, r3, sl, fp, lr}
177 -       mov pc,ip
178 +       mov   ip, r0
179 +       ldmia sp!, {r0-r3, lr}
180 +#if defined(__THUMB_INTERWORK__)
181 +       bx    ip
182 +#else
183 +       mov   pc, ip
184 +#endif
185 +.size _dl_linux_resolve, .-_dl_linux_resolve
186 +#else
187 +       @ In the thumb case _dl_linux_resolver is thumb.  If a bl is used
188 +       @ from arm code the linker will insert a stub call which, with
189 +       @ binutils 2.16, is not PIC.  Since this code is accessed by an
190 +       @ ldr pc the reasonable fix is to make _dl_linux_resolve thumb too.
191 +.thumb
192 +.globl _dl_linux_resolve
193 +.thumb_func
194 +.type _dl_linux_resolve,%function
195 +
196 +_dl_linux_resolve:
197 +       @ _dl_linux_resolver is a standard subroutine call, therefore it
198 +       @ preserves everything except r0-r3 (a1-a4), ip and lr.  This
199 +       @ function must branch to the real function, and that expects
200 +       @ r0-r3 and lr to be as they were before the whole PLT stuff -
201 +       @ ip can be trashed.
202 +       push    {r0-r3}
203 +       mov     r1, lr          @ &GOT_TABLE[2]
204 +       sub     r0, r1, #4
205 +       mov     r2, ip          @ &GOT[n]
206 +       ldr     r0, [r0]        @ r0 := GOT_TABLE[1]
207 +       @ for the function call r1 := n-3
208 +       sub     r1, r2
209 +       asr     r1, r1, #2
210 +       mvn     r1, r1          @ exactly as in the arm code above
211 +
212 +       bl      _dl_linux_resolver
213 +
214 +       @ r0 contains the branch address, the return address is above
215 +       @ the saved r0..r3
216 +       mov     ip, r0
217 +       ldr     r1, [sp, #16]
218 +       mov     lr, r1
219 +       pop     {r0-r3}
220 +       add     sp, #4
221 +       bx      ip
222 +
223  .size _dl_linux_resolve, .-_dl_linux_resolve
224 +#endif
225 --- uClibc-0.9.28/.pc/thumb-resolve.patch/ldso/ldso/dl-hash.c   2005-08-17 15:49:41.000000000 -0700
226 +++ uClibc-0.9.28/ldso/ldso/dl-hash.c   2005-09-21 18:56:31.181689732 -0700
227 @@ -182,28 +182,52 @@
228                 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
229  
230                 for (si = tpnt->elf_buckets[hn]; si != STN_UNDEF; si = tpnt->chains[si]) {
231 +                       char *result;
232                         sym = &symtab[si];
233  
234 -                       if (type_class & (sym->st_shndx == SHN_UNDEF))
235 +                       if (sym->st_shndx == SHN_UNDEF)
236                                 continue;
237 -                       if (_dl_strcmp(strtab + sym->st_name, name) != 0)
238 +                       if (ELF_ST_TYPE(sym->st_info) > STT_FUNC
239 +#if defined(__arm__) || defined(__thumb__)
240 +                               /* On ARM (only) STT_ARM_TFUNC is a function
241 +                                * and has a value >STT_FUNC, so this must
242 +                                * be checked specially.
243 +                                */
244 +                               && ELF_ST_TYPE(sym->st_info) != STT_ARM_TFUNC
245 +#endif
246 +                          )
247                                 continue;
248 -                       if (sym->st_value == 0)
249 +                       if (_dl_strcmp(strtab + sym->st_name, name) != 0)
250                                 continue;
251 -                       if (ELF_ST_TYPE(sym->st_info) > STT_FUNC)
252 +#if 0
253 +                       /* I don't know how to write this test - need to test shndx
254 +                        * to see if it is the PLT for this module.
255 +                        */
256 +                       if ((type_class & ELF_RTYPE_CLASS_PLT) && some test)
257                                 continue;
258 +#endif
259  
260 +#if defined(__arm__) || defined(__thumb__)
261 +                       /* On ARM the caller needs to know that STT_ARM_TFUNC
262 +                        * is a thumb function call, this is now indicated by
263 +                        * setting the low bit of the value (and newer binutils
264 +                        * will do this and record STT_FUNC).
265 +                        */
266 +                       result = (char*)tpnt->loadaddr + (sym->st_value |
267 +                               (ELF_ST_TYPE(sym->st_info) == STT_ARM_TFUNC));
268 +#else
269 +                       result = (char*)tpnt->loadaddr + sym->st_value;
270 +#endif
271                         switch (ELF_ST_BIND(sym->st_info)) {
272                         case STB_WEAK:
273 -#if 0
274 -/* Perhaps we should support old style weak symbol handling
275 - * per what glibc does when you export LD_DYNAMIC_WEAK */
276 +                               /* Record for use later if we can't find a global. */
277                                 if (!weak_result)
278 -                                       weak_result = (char *)tpnt->loadaddr + sym->st_value;
279 +                                       weak_result = result;
280                                 break;
281 -#endif
282 +
283                         case STB_GLOBAL:
284 -                               return (char*)tpnt->loadaddr + sym->st_value;
285 +                               return result;
286 +
287                         default:        /* Local symbols not handled here */
288                                 break;
289                         }