2003-03-02 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / sysdeps / powerpc / powerpc32 / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  PowerPC version.
2    Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #ifndef dl_machine_h
21 #define dl_machine_h
22
23 #define ELF_MACHINE_NAME "powerpc"
24
25 #include <assert.h>
26 #include <dl-tls.h>
27
28 /* Return nonzero iff ELF header is compatible with the running host.  */
29 static inline int
30 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
31 {
32   return ehdr->e_machine == EM_PPC;
33 }
34
35
36 /* Return the link-time address of _DYNAMIC, stored as
37    the first value in the GOT. */
38 static inline Elf32_Addr
39 elf_machine_dynamic (void)
40 {
41   Elf32_Addr *got;
42   asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
43        : "=l"(got));
44   return *got;
45 }
46
47 /* Return the run-time load address of the shared object.  */
48 static inline Elf32_Addr
49 elf_machine_load_address (void)
50 {
51   unsigned int *got;
52   unsigned int *branchaddr;
53
54   /* This is much harder than you'd expect.  Possibly I'm missing something.
55      The 'obvious' way:
56
57        Apparently, "bcl 20,31,$+4" is what should be used to load LR
58        with the address of the next instruction.
59        I think this is so that machines that do bl/blr pairing don't
60        get confused.
61
62      asm ("bcl 20,31,0f ;"
63           "0: mflr 0 ;"
64           "lis %0,0b@ha;"
65           "addi %0,%0,0b@l;"
66           "subf %0,%0,0"
67           : "=b" (addr) : : "r0", "lr");
68
69      doesn't work, because the linker doesn't have to (and in fact doesn't)
70      update the @ha and @l references; the loader (which runs after this
71      code) will do that.
72
73      Instead, we use the following trick:
74
75      The linker puts the _link-time_ address of _DYNAMIC at the first
76      word in the GOT. We could branch to that address, if we wanted,
77      by using an @local reloc; the linker works this out, so it's safe
78      to use now. We can't, of course, actually branch there, because
79      we'd cause an illegal instruction exception; so we need to compute
80      the address ourselves. That gives us the following code: */
81
82   /* Get address of the 'b _DYNAMIC@local'...  */
83   asm ("bl 0f ;"
84        "b _DYNAMIC@local;"
85        "0:"
86        : "=l"(branchaddr));
87
88   /* ... and the address of the GOT.  */
89   asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
90        : "=l"(got));
91
92   /* So now work out the difference between where the branch actually points,
93      and the offset of that location in memory from the start of the file.  */
94   return ((Elf32_Addr)branchaddr - *got
95           + ((int)(*branchaddr << 6 & 0xffffff00) >> 6));
96 }
97
98 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
99
100 /* The PLT uses Elf32_Rela relocs.  */
101 #define elf_machine_relplt elf_machine_rela
102
103 /* This code is used in dl-runtime.c to call the `fixup' function
104    and then redirect to the address it returns.  It is called
105    from code built in the PLT by elf_machine_runtime_setup.  */
106 #if !defined PROF
107 #define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
108         .section \".text\"      \n\
109         .align 2        \n\
110         .globl _dl_runtime_resolve      \n\
111         .type _dl_runtime_resolve,@function     \n\
112 _dl_runtime_resolve:    \n\
113  # We need to save the registers used to pass parameters, and register 0,\n\
114  # which is used by _mcount; the registers are saved in a stack frame.\n\
115         stwu 1,-64(1)   \n\
116         stw 0,12(1)     \n\
117         stw 3,16(1)     \n\
118         stw 4,20(1)     \n\
119  # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
120         mr 3,12 \n\
121         stw 5,24(1)     \n\
122         mr 4,11 \n\
123         stw 6,28(1)     \n\
124         mflr 0  \n\
125  # We also need to save some of the condition register fields.\n\
126         stw 7,32(1)     \n\
127         stw 0,48(1)     \n\
128         stw 8,36(1)     \n\
129         mfcr 0  \n\
130         stw 9,40(1)     \n\
131         stw 10,44(1)    \n\
132         stw 0,8(1)      \n\
133         bl fixup@local  \n\
134  # 'fixup' returns the address we want to branch to.\n\
135         mtctr 3 \n\
136  # Put the registers back...\n\
137         lwz 0,48(1)     \n\
138         lwz 10,44(1)    \n\
139         lwz 9,40(1)     \n\
140         mtlr 0  \n\
141         lwz 8,36(1)     \n\
142         lwz 0,8(1)      \n\
143         lwz 7,32(1)     \n\
144         lwz 6,28(1)     \n\
145         mtcrf 0xFF,0    \n\
146         lwz 5,24(1)     \n\
147         lwz 4,20(1)     \n\
148         lwz 3,16(1)     \n\
149         lwz 0,12(1)     \n\
150  # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
151         addi 1,1,64     \n\
152         bctr    \n\
153         .size    _dl_runtime_resolve,.-_dl_runtime_resolve      \n\
154         \n\
155         .align 2        \n\
156         .globl _dl_prof_resolve \n\
157         .type _dl_prof_resolve,@function        \n\
158 _dl_prof_resolve:       \n\
159  # We need to save the registers used to pass parameters, and register 0,\n\
160  # which is used by _mcount; the registers are saved in a stack frame.\n\
161         stwu 1,-64(1)   \n\
162         stw 0,12(1)     \n\
163         stw 3,16(1)     \n\
164         stw 4,20(1)     \n\
165  # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
166         mr 3,12 \n\
167         stw 5,24(1)     \n\
168         mr 4,11 \n\
169         stw 6,28(1)     \n\
170         mflr 5  \n\
171  # We also need to save some of the condition register fields.\n\
172         stw 7,32(1)     \n\
173         stw 5,48(1)     \n\
174         stw 8,36(1)     \n\
175         mfcr 0  \n\
176         stw 9,40(1)     \n\
177         stw 10,44(1)    \n\
178         stw 0,8(1)      \n\
179         bl profile_fixup@local  \n\
180  # 'fixup' returns the address we want to branch to.\n\
181         mtctr 3 \n\
182  # Put the registers back...\n\
183         lwz 0,48(1)     \n\
184         lwz 10,44(1)    \n\
185         lwz 9,40(1)     \n\
186         mtlr 0  \n\
187         lwz 8,36(1)     \n\
188         lwz 0,8(1)      \n\
189         lwz 7,32(1)     \n\
190         lwz 6,28(1)     \n\
191         mtcrf 0xFF,0    \n\
192         lwz 5,24(1)     \n\
193         lwz 4,20(1)     \n\
194         lwz 3,16(1)     \n\
195         lwz 0,12(1)     \n\
196  # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
197         addi 1,1,64     \n\
198         bctr    \n\
199         .size    _dl_prof_resolve,.-_dl_prof_resolve    \n\
200  # Undo '.section text'.\n\
201         .previous       \n\
202 ");
203 #else
204 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
205         .section \".text\"      \n\
206         .align 2        \n\
207         .globl _dl_runtime_resolve      \n\
208         .globl _dl_prof_resolve \n\
209         .type _dl_runtime_resolve,@function     \n\
210         .type _dl_prof_resolve,@function        \n\
211 _dl_runtime_resolve:    \n\
212 _dl_prof_resolve:       \n\
213  # We need to save the registers used to pass parameters, and register 0,\n\
214  # which is used by _mcount; the registers are saved in a stack frame.\n\
215         stwu 1,-64(1)   \n\
216         stw 0,12(1)     \n\
217         stw 3,16(1)     \n\
218         stw 4,20(1)     \n\
219  # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
220         mr 3,12 \n\
221         stw 5,24(1)     \n\
222         mr 4,11 \n\
223         stw 6,28(1)     \n\
224         mflr 0  \n\
225  # We also need to save some of the condition register fields.\n\
226         stw 7,32(1)     \n\
227         stw 0,48(1)     \n\
228         stw 8,36(1)     \n\
229         mfcr 0  \n\
230         stw 9,40(1)     \n\
231         stw 10,44(1)    \n\
232         stw 0,8(1)      \n\
233         bl fixup@local  \n\
234  # 'fixup' returns the address we want to branch to.\n\
235         mtctr 3 \n\
236  # Put the registers back...\n\
237         lwz 0,48(1)     \n\
238         lwz 10,44(1)    \n\
239         lwz 9,40(1)     \n\
240         mtlr 0  \n\
241         lwz 8,36(1)     \n\
242         lwz 0,8(1)      \n\
243         lwz 7,32(1)     \n\
244         lwz 6,28(1)     \n\
245         mtcrf 0xFF,0    \n\
246         lwz 5,24(1)     \n\
247         lwz 4,20(1)     \n\
248         lwz 3,16(1)     \n\
249         lwz 0,12(1)     \n\
250  # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
251         addi 1,1,64     \n\
252         bctr    \n\
253         .size    _dl_runtime_resolve,.-_dl_runtime_resolve      \n\
254 ");
255 #endif
256
257 /* Mask identifying addresses reserved for the user program,
258    where the dynamic linker should not map anything.  */
259 #define ELF_MACHINE_USER_ADDRESS_MASK   0xf0000000UL
260
261 /* The actual _start code is in dl-start.S.  Use a really
262    ugly bit of assembler to let dl-start.o see _dl_start.  */
263 #define RTLD_START asm (".globl _dl_start");
264
265 /* Decide where a relocatable object should be loaded.  */
266 extern ElfW(Addr)
267 __elf_preferred_address(struct link_map *loader, size_t maplength,
268                         ElfW(Addr) mapstartpref);
269 #define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \
270   __elf_preferred_address (loader, maplength, mapstartpref)
271
272 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
273    PLT entries should not be allowed to define the value.
274    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
275    of the main executable's symbols, as for a COPY reloc.  */
276 /* We never want to use a PLT entry as the destination of a
277    reloc, when what is being relocated is a branch. This is
278    partly for efficiency, but mostly so we avoid loops.  */
279 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
280 #define elf_machine_type_class(type)                    \
281   ((((type) == R_PPC_JMP_SLOT                           \
282     || (type) == R_PPC_REL24                            \
283     || (type) == R_PPC_DTPMOD32                         \
284     || (type) == R_PPC_DTPREL32                         \
285     || (type) == R_PPC_TPREL32                          \
286     || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT)   \
287    | (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
288 #else
289 #define elf_machine_type_class(type) \
290   ((((type) == R_PPC_JMP_SLOT                           \
291     || (type) == R_PPC_REL24                            \
292     || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT)   \
293    | (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
294 #endif
295
296 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
297 #define ELF_MACHINE_JMP_SLOT    R_PPC_JMP_SLOT
298
299 /* The PowerPC never uses REL relocations.  */
300 #define ELF_MACHINE_NO_REL 1
301
302 /* Set up the loaded object described by L so its unrelocated PLT
303    entries will jump to the on-demand fixup code in dl-runtime.c.
304    Also install a small trampoline to be used by entries that have
305    been relocated to an address too far away for a single branch.  */
306 extern int __elf_machine_runtime_setup (struct link_map *map,
307                                         int lazy, int profile);
308 #define elf_machine_runtime_setup __elf_machine_runtime_setup
309
310 /* Change the PLT entry whose reloc is 'reloc' to call the actual routine.  */
311 extern Elf32_Addr __elf_machine_fixup_plt (struct link_map *map,
312                                            const Elf32_Rela *reloc,
313                                            Elf32_Addr *reloc_addr,
314                                            Elf32_Addr finaladdr);
315
316 static inline Elf32_Addr
317 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
318                        const Elf32_Rela *reloc,
319                        Elf32_Addr *reloc_addr, Elf64_Addr finaladdr)
320 {
321   return __elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
322 }
323
324 /* Return the final value of a plt relocation.  */
325 static inline Elf32_Addr
326 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
327                        Elf32_Addr value)
328 {
329   return value + reloc->r_addend;
330 }
331
332 #endif /* dl_machine_h */
333
334 #ifdef RESOLVE
335
336 /* Do the actual processing of a reloc, once its target address
337    has been determined.  */
338 extern void __process_machine_rela (struct link_map *map,
339                                     const Elf32_Rela *reloc,
340                                     const Elf32_Sym *sym,
341                                     const Elf32_Sym *refsym,
342                                     Elf32_Addr *const reloc_addr,
343                                     Elf32_Addr finaladdr,
344                                     int rinfo);
345
346 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
347    LOADADDR is the load address of the object; INFO is an array indexed
348    by DT_* of the .dynamic section info.  */
349
350 inline void
351 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
352                   const Elf32_Sym *sym, const struct r_found_version *version,
353                   Elf32_Addr *const reloc_addr)
354 {
355   const Elf32_Sym *const refsym = sym;
356   Elf32_Addr value;
357   const int r_type = ELF32_R_TYPE (reloc->r_info);
358
359   if (r_type == R_PPC_RELATIVE)
360     {
361       *reloc_addr = map->l_addr + reloc->r_addend;
362       return;
363     }
364
365   if (__builtin_expect (r_type == R_PPC_NONE, 0))
366     return;
367
368 #if defined USE_TLS && !defined RTLD_BOOTSTRAP
369   struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
370   value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
371 #else
372   value = RESOLVE (&sym, version, r_type);
373 # ifndef RTLD_BOOTSTRAP
374   if (sym != NULL)
375 # endif
376     value += sym->st_value;
377 #endif
378   value += reloc->r_addend;
379
380   /* A small amount of code is duplicated here for speed.  In libc,
381      more than 90% of the relocs are R_PPC_RELATIVE; in the X11 shared
382      libraries, 60% are R_PPC_RELATIVE, 24% are R_PPC_GLOB_DAT or
383      R_PPC_ADDR32, and 16% are R_PPC_JMP_SLOT (which this routine
384      wouldn't usually handle).  As an bonus, doing this here allows
385      the switch statement in __process_machine_rela to work.  */
386   switch (r_type)
387     {
388     case R_PPC_GLOB_DAT:
389     case R_PPC_ADDR32:
390       *reloc_addr = value;
391       break;
392
393 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
394     case R_PPC_DTPMOD32:
395 # ifdef RTLD_BOOTSTRAP
396       /* During startup the dynamic linker is always index 1.  */
397       *reloc_addr = 1;
398 # else
399       /* Get the information from the link map returned by the
400          RESOLVE_MAP function.  */
401       if (sym_map != NULL)
402         *reloc_addr = sym_map->l_tls_modid;
403 # endif
404       break;
405     case R_PPC_DTPREL32:
406       /* During relocation all TLS symbols are defined and used.
407          Therefore the offset is already correct.  */
408 # ifndef RTLD_BOOTSTRAP
409       *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
410 # endif
411       break;
412     case R_PPC_TPREL32:
413 # ifndef RTLD_BOOTSTRAP
414       if (sym_map)
415         {
416           CHECK_STATIC_TLS (map, sym_map);
417 # endif
418           *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
419 # ifndef RTLD_BOOTSTRAP
420         }
421 # endif
422       break;
423 #endif /* USE_TLS etc. */
424
425 #ifdef RESOLVE_CONFLICT_FIND_MAP
426     case R_PPC_JMP_SLOT:
427       RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
428       /* FALLTHROUGH */
429 #endif
430
431     default:
432       __process_machine_rela (map, reloc, sym, refsym,
433                               reloc_addr, value, r_type);
434     }
435 }
436
437 static inline void
438 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
439                            Elf32_Addr *const reloc_addr)
440 {
441   *reloc_addr = l_addr + reloc->r_addend;
442 }
443
444 static inline void
445 elf_machine_lazy_rel (struct link_map *map,
446                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
447 {
448   /* elf_machine_runtime_setup handles this. */
449 }
450
451 /* The SVR4 ABI specifies that the JMPREL relocs must be inside the
452    DT_RELA table.  */
453 #define ELF_MACHINE_PLTREL_OVERLAP 1
454
455 #endif /* RESOLVE */