Update.
[kopensolaris-gnu/glibc.git] / sysdeps / powerpc / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  PowerPC version.
2    Copyright (C) 1995-2000, 2001 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 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
27 /* Return nonzero iff ELF header is compatible with the running host.  */
28 static inline int
29 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
30 {
31   return ehdr->e_machine == EM_PPC;
32 }
33
34
35 /* Return the link-time address of _DYNAMIC, stored as
36    the first value in the GOT. */
37 static inline Elf32_Addr
38 elf_machine_dynamic (void)
39 {
40   Elf32_Addr *got;
41   asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
42        : "=l"(got));
43   return *got;
44 }
45
46 /* Return the run-time load address of the shared object.  */
47 static inline Elf32_Addr
48 elf_machine_load_address (void)
49 {
50   unsigned int *got;
51   unsigned int *branchaddr;
52
53   /* This is much harder than you'd expect.  Possibly I'm missing something.
54      The 'obvious' way:
55
56        Apparently, "bcl 20,31,$+4" is what should be used to load LR
57        with the address of the next instruction.
58        I think this is so that machines that do bl/blr pairing don't
59        get confused.
60
61      asm ("bcl 20,31,0f ;"
62           "0: mflr 0 ;"
63           "lis %0,0b@ha;"
64           "addi %0,%0,0b@l;"
65           "subf %0,%0,0"
66           : "=b" (addr) : : "r0", "lr");
67
68      doesn't work, because the linker doesn't have to (and in fact doesn't)
69      update the @ha and @l references; the loader (which runs after this
70      code) will do that.
71
72      Instead, we use the following trick:
73
74      The linker puts the _link-time_ address of _DYNAMIC at the first
75      word in the GOT. We could branch to that address, if we wanted,
76      by using an @local reloc; the linker works this out, so it's safe
77      to use now. We can't, of course, actually branch there, because
78      we'd cause an illegal instruction exception; so we need to compute
79      the address ourselves. That gives us the following code: */
80
81   /* Get address of the 'b _DYNAMIC@local'...  */
82   asm ("bl 0f ;"
83        "b _DYNAMIC@local;"
84        "0:"
85        : "=l"(branchaddr));
86
87   /* ... and the address of the GOT.  */
88   asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
89        : "=l"(got));
90
91   /* So now work out the difference between where the branch actually points,
92      and the offset of that location in memory from the start of the file.  */
93   return ((Elf32_Addr)branchaddr - *got
94           + ((int)(*branchaddr << 6 & 0xffffff00) >> 6));
95 }
96
97 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
98
99 /* The PLT uses Elf32_Rela relocs.  */
100 #define elf_machine_relplt elf_machine_rela
101
102 /* This code is used in dl-runtime.c to call the `fixup' function
103    and then redirect to the address it returns.  It is called
104    from code built in the PLT by elf_machine_runtime_setup.  */
105 #define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
106         .section \".text\"      \n\
107         .align 2        \n\
108         .globl _dl_runtime_resolve      \n\
109         .type _dl_runtime_resolve,@function     \n\
110 _dl_runtime_resolve:    \n\
111  # We need to save the registers used to pass parameters, and register 0,\n\
112  # which is used by _mcount; the registers are saved in a stack frame.\n\
113         stwu 1,-64(1)   \n\
114         stw 0,12(1)     \n\
115         stw 3,16(1)     \n\
116         stw 4,20(1)     \n\
117  # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
118         mr 3,12 \n\
119         stw 5,24(1)     \n\
120         mr 4,11 \n\
121         stw 6,28(1)     \n\
122         mflr 0  \n\
123  # We also need to save some of the condition register fields.\n\
124         stw 7,32(1)     \n\
125         stw 0,48(1)     \n\
126         stw 8,36(1)     \n\
127         mfcr 0  \n\
128         stw 9,40(1)     \n\
129         stw 10,44(1)    \n\
130         stw 0,8(1)      \n\
131         bl fixup@local  \n\
132  # 'fixup' returns the address we want to branch to.\n\
133         mtctr 3 \n\
134  # Put the registers back...\n\
135         lwz 0,48(1)     \n\
136         lwz 10,44(1)    \n\
137         lwz 9,40(1)     \n\
138         mtlr 0  \n\
139         lwz 8,36(1)     \n\
140         lwz 0,8(1)      \n\
141         lwz 7,32(1)     \n\
142         lwz 6,28(1)     \n\
143         mtcrf 0xFF,0    \n\
144         lwz 5,24(1)     \n\
145         lwz 4,20(1)     \n\
146         lwz 3,16(1)     \n\
147         lwz 0,12(1)     \n\
148  # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
149         addi 1,1,64     \n\
150         bctr    \n\
151         .size    _dl_runtime_resolve,.-_dl_runtime_resolve      \n\
152         \n\
153         .align 2        \n\
154         .globl _dl_prof_resolve \n\
155         .type _dl_prof_resolve,@function        \n\
156 _dl_prof_resolve:       \n\
157  # We need to save the registers used to pass parameters, and register 0,\n\
158  # which is used by _mcount; the registers are saved in a stack frame.\n\
159         stwu 1,-64(1)   \n\
160         stw 0,12(1)     \n\
161         stw 3,16(1)     \n\
162         stw 4,20(1)     \n\
163  # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
164         mr 3,12 \n\
165         stw 5,24(1)     \n\
166         mr 4,11 \n\
167         stw 6,28(1)     \n\
168         mflr 5  \n\
169  # We also need to save some of the condition register fields.\n\
170         stw 7,32(1)     \n\
171         stw 5,48(1)     \n\
172         stw 8,36(1)     \n\
173         mfcr 0  \n\
174         stw 9,40(1)     \n\
175         stw 10,44(1)    \n\
176         stw 0,8(1)      \n\
177         bl profile_fixup@local  \n\
178  # 'fixup' returns the address we want to branch to.\n\
179         mtctr 3 \n\
180  # Put the registers back...\n\
181         lwz 0,48(1)     \n\
182         lwz 10,44(1)    \n\
183         lwz 9,40(1)     \n\
184         mtlr 0  \n\
185         lwz 8,36(1)     \n\
186         lwz 0,8(1)      \n\
187         lwz 7,32(1)     \n\
188         lwz 6,28(1)     \n\
189         mtcrf 0xFF,0    \n\
190         lwz 5,24(1)     \n\
191         lwz 4,20(1)     \n\
192         lwz 3,16(1)     \n\
193         lwz 0,12(1)     \n\
194  # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
195         addi 1,1,64     \n\
196         bctr    \n\
197         .size    _dl_prof_resolve,.-_dl_prof_resolve    \n\
198  # Undo '.section text'.\n\
199         .previous       \n\
200 ");
201
202 /* The actual _start code is in dl-start.S.  Use a really
203    ugly bit of assembler to let dl-start.o see _dl_start.  */
204 #define RTLD_START asm (".globl _dl_start");
205
206 /* Decide where a relocatable object should be loaded.  */
207 extern ElfW(Addr)
208 __elf_preferred_address(struct link_map *loader, size_t maplength,
209                         ElfW(Addr) mapstartpref);
210 #define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \
211   __elf_preferred_address (loader, maplength, mapstartpref)
212
213 /* Nonzero iff TYPE should not be allowed to resolve to one of
214    the main executable's symbols, as for a COPY reloc.  */
215 #define elf_machine_lookup_noexec_p(type) ((type) == R_PPC_COPY)
216
217 /* Nonzero iff TYPE describes relocation of a PLT entry, so
218    PLT entries should not be allowed to define the value.  */
219 /* We never want to use a PLT entry as the destination of a
220    reloc, when what is being relocated is a branch. This is
221    partly for efficiency, but mostly so we avoid loops.  */
222 #define elf_machine_lookup_noplt_p(type) ((type) == R_PPC_REL24 ||            \
223                                           (type) == R_PPC_ADDR24 ||           \
224                                           (type) == R_PPC_JMP_SLOT)
225
226 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
227 #define ELF_MACHINE_JMP_SLOT    R_PPC_JMP_SLOT
228
229 /* The PowerPC never uses REL relocations.  */
230 #define ELF_MACHINE_NO_REL 1
231
232 /* Set up the loaded object described by L so its unrelocated PLT
233    entries will jump to the on-demand fixup code in dl-runtime.c.
234    Also install a small trampoline to be used by entries that have
235    been relocated to an address too far away for a single branch.  */
236 extern int __elf_machine_runtime_setup (struct link_map *map,
237                                         int lazy, int profile);
238 #define elf_machine_runtime_setup __elf_machine_runtime_setup
239
240 static inline void
241 elf_machine_lazy_rel (struct link_map *map,
242                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
243 {
244   /* elf_machine_runtime_setup handles this. */
245 }
246
247 /* Change the PLT entry whose reloc is 'reloc' to call the actual routine.  */
248 extern Elf32_Addr __elf_machine_fixup_plt (struct link_map *map,
249                                            const Elf32_Rela *reloc,
250                                            Elf32_Addr *reloc_addr,
251                                            Elf32_Addr finaladdr);
252
253 static inline Elf32_Addr
254 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
255                        const Elf32_Rela *reloc,
256                        Elf32_Addr *reloc_addr, Elf64_Addr finaladdr)
257 {
258   return __elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
259 }
260
261 /* Return the final value of a plt relocation.  */
262 static inline Elf32_Addr
263 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
264                        Elf32_Addr value)
265 {
266   return value + reloc->r_addend;
267 }
268
269 #endif /* dl_machine_h */
270
271 #ifdef RESOLVE
272
273 /* Do the actual processing of a reloc, once its target address
274    has been determined.  */
275 extern void __process_machine_rela (struct link_map *map,
276                                     const Elf32_Rela *reloc,
277                                     const Elf32_Sym *sym,
278                                     const Elf32_Sym *refsym,
279                                     Elf32_Addr *const reloc_addr,
280                                     Elf32_Addr finaladdr,
281                                     int rinfo);
282
283 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
284    LOADADDR is the load address of the object; INFO is an array indexed
285    by DT_* of the .dynamic section info.  */
286
287 inline void
288 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
289                   const Elf32_Sym *sym, const struct r_found_version *version,
290                   Elf32_Addr *const reloc_addr)
291 {
292   const Elf32_Sym *const refsym = sym;
293   Elf32_Word loadbase, finaladdr;
294   const int rinfo = ELF32_R_TYPE (reloc->r_info);
295
296   if (rinfo == R_PPC_NONE)
297     return;
298
299   /* The condition on the next two lines is a hack around a bug in Solaris
300      tools on Sparc.  It's not clear whether it should really be here at all,
301      but if not the binutils need to be changed.  */
302   if (rinfo == R_PPC_RELATIVE
303       || (sym->st_shndx != SHN_UNDEF
304           && ELF32_ST_BIND (sym->st_info) == STB_LOCAL))
305     {
306       /* Has already been relocated.  */
307       loadbase = map->l_addr;
308       finaladdr = loadbase + reloc->r_addend;
309     }
310   else
311     {
312       loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version,
313                                                  ELF32_R_TYPE(reloc->r_info)));
314       if (sym == NULL)
315         {
316           /* Weak symbol that wasn't actually defined anywhere.  */
317           assert(loadbase == 0);
318           finaladdr = reloc->r_addend;
319         }
320       else
321         finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
322                      + reloc->r_addend);
323     }
324
325   /* A small amount of code is duplicated here for speed.  In libc,
326      more than 90% of the relocs are R_PPC_RELATIVE; in the X11 shared
327      libraries, 60% are R_PPC_RELATIVE, 24% are R_PPC_GLOB_DAT or
328      R_PPC_ADDR32, and 16% are R_PPC_JMP_SLOT (which this routine
329      wouldn't usually handle).  As an bonus, doing this here allows
330      the switch statement in __process_machine_rela to work.  */
331   if (rinfo == R_PPC_RELATIVE
332       || rinfo == R_PPC_GLOB_DAT
333       || rinfo == R_PPC_ADDR32)
334     {
335       *reloc_addr = finaladdr;
336     }
337   else
338     __process_machine_rela (map, reloc, sym, refsym,
339                             reloc_addr, finaladdr, rinfo);
340 }
341
342
343 /* The SVR4 ABI specifies that the JMPREL relocs must be inside the
344    DT_RELA table.  */
345 #define ELF_MACHINE_PLTREL_OVERLAP 1
346
347 #endif /* RESOLVE */