]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/powerpc/dl-machine.h
Update.
[thirdparty/glibc.git] / sysdeps / powerpc / dl-machine.h
CommitLineData
4cca6b86 1/* Machine-dependent ELF dynamic relocation inline functions. PowerPC version.
f4f8cd2c 2 Copyright (C) 1995-2000, 2001 Free Software Foundation, Inc.
4cca6b86
UD
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
1f205a47
UD
20#ifndef dl_machine_h
21#define dl_machine_h
22
4cca6b86
UD
23#define ELF_MACHINE_NAME "powerpc"
24
25#include <assert.h>
4cca6b86 26
ceb579a3 27/* Return nonzero iff ELF header is compatible with the running host. */
c2a32973 28static inline int
ceb579a3 29elf_machine_matches_host (const Elf32_Ehdr *ehdr)
4cca6b86 30{
ceb579a3 31 return ehdr->e_machine == EM_PPC;
4cca6b86
UD
32}
33
34
e61abf83
UD
35/* Return the link-time address of _DYNAMIC, stored as
36 the first value in the GOT. */
c2a32973 37static inline Elf32_Addr
4cca6b86
UD
38elf_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. */
47static inline Elf32_Addr
48elf_machine_load_address (void)
49{
c0282c06
UD
50 unsigned int *got;
51 unsigned int *branchaddr;
4cca6b86
UD
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 ;"
e61abf83
UD
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");
4cca6b86
UD
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. */
1f205a47 93 return ((Elf32_Addr)branchaddr - *got
d8cceb4f 94 + ((int)(*branchaddr << 6 & 0xffffff00) >> 6));
4cca6b86
UD
95}
96
97#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
98
1f205a47
UD
99/* The PLT uses Elf32_Rela relocs. */
100#define elf_machine_relplt elf_machine_rela
4cca6b86 101
0413b54c 102/* This code is used in dl-runtime.c to call the `fixup' function
9a0a462c
UD
103 and then redirect to the address it returns. It is called
104 from code built in the PLT by elf_machine_runtime_setup. */
33e25d26 105#if !defined PROF
c891b2df
UD
106#define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
107 .section \".text\" \n\
108 .align 2 \n\
109 .globl _dl_runtime_resolve \n\
110 .type _dl_runtime_resolve,@function \n\
111_dl_runtime_resolve: \n\
112 # We need to save the registers used to pass parameters, and register 0,\n\
113 # which is used by _mcount; the registers are saved in a stack frame.\n\
114 stwu 1,-64(1) \n\
115 stw 0,12(1) \n\
116 stw 3,16(1) \n\
117 stw 4,20(1) \n\
118 # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
119 mr 3,12 \n\
120 stw 5,24(1) \n\
121 mr 4,11 \n\
122 stw 6,28(1) \n\
123 mflr 0 \n\
124 # We also need to save some of the condition register fields.\n\
125 stw 7,32(1) \n\
126 stw 0,48(1) \n\
127 stw 8,36(1) \n\
128 mfcr 0 \n\
129 stw 9,40(1) \n\
130 stw 10,44(1) \n\
131 stw 0,8(1) \n\
132 bl fixup@local \n\
133 # 'fixup' returns the address we want to branch to.\n\
134 mtctr 3 \n\
135 # Put the registers back...\n\
136 lwz 0,48(1) \n\
137 lwz 10,44(1) \n\
138 lwz 9,40(1) \n\
139 mtlr 0 \n\
140 lwz 8,36(1) \n\
141 lwz 0,8(1) \n\
142 lwz 7,32(1) \n\
143 lwz 6,28(1) \n\
144 mtcrf 0xFF,0 \n\
145 lwz 5,24(1) \n\
146 lwz 4,20(1) \n\
147 lwz 3,16(1) \n\
148 lwz 0,12(1) \n\
149 # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
150 addi 1,1,64 \n\
151 bctr \n\
152 .size _dl_runtime_resolve,.-_dl_runtime_resolve \n\
153 \n\
154 .align 2 \n\
155 .globl _dl_prof_resolve \n\
156 .type _dl_prof_resolve,@function \n\
157_dl_prof_resolve: \n\
158 # We need to save the registers used to pass parameters, and register 0,\n\
159 # which is used by _mcount; the registers are saved in a stack frame.\n\
160 stwu 1,-64(1) \n\
161 stw 0,12(1) \n\
162 stw 3,16(1) \n\
163 stw 4,20(1) \n\
164 # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
165 mr 3,12 \n\
166 stw 5,24(1) \n\
167 mr 4,11 \n\
168 stw 6,28(1) \n\
169 mflr 5 \n\
170 # We also need to save some of the condition register fields.\n\
171 stw 7,32(1) \n\
172 stw 5,48(1) \n\
173 stw 8,36(1) \n\
174 mfcr 0 \n\
175 stw 9,40(1) \n\
176 stw 10,44(1) \n\
177 stw 0,8(1) \n\
178 bl profile_fixup@local \n\
179 # 'fixup' returns the address we want to branch to.\n\
180 mtctr 3 \n\
181 # Put the registers back...\n\
182 lwz 0,48(1) \n\
183 lwz 10,44(1) \n\
184 lwz 9,40(1) \n\
185 mtlr 0 \n\
186 lwz 8,36(1) \n\
187 lwz 0,8(1) \n\
188 lwz 7,32(1) \n\
189 lwz 6,28(1) \n\
190 mtcrf 0xFF,0 \n\
191 lwz 5,24(1) \n\
192 lwz 4,20(1) \n\
193 lwz 3,16(1) \n\
194 lwz 0,12(1) \n\
195 # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
196 addi 1,1,64 \n\
197 bctr \n\
198 .size _dl_prof_resolve,.-_dl_prof_resolve \n\
199 # Undo '.section text'.\n\
200 .previous \n\
1f205a47 201");
33e25d26
AJ
202#else
203# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
204 .section \".text\" \n\
205 .align 2 \n\
206 .globl _dl_runtime_resolve \n\
207 .globl _dl_prof_resolve \n\
208 .type _dl_runtime_resolve,@function \n\
209 .type _dl_prof_resolve,@function \n\
210_dl_runtime_resolve: \n\
211_dl_prof_resolve: \n\
212 # We need to save the registers used to pass parameters, and register 0,\n\
213 # which is used by _mcount; the registers are saved in a stack frame.\n\
214 stwu 1,-64(1) \n\
215 stw 0,12(1) \n\
216 stw 3,16(1) \n\
217 stw 4,20(1) \n\
218 # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
219 mr 3,12 \n\
220 stw 5,24(1) \n\
221 mr 4,11 \n\
222 stw 6,28(1) \n\
223 mflr 0 \n\
224 # We also need to save some of the condition register fields.\n\
225 stw 7,32(1) \n\
226 stw 0,48(1) \n\
227 stw 8,36(1) \n\
228 mfcr 0 \n\
229 stw 9,40(1) \n\
230 stw 10,44(1) \n\
231 stw 0,8(1) \n\
232 bl fixup@local \n\
233 # 'fixup' returns the address we want to branch to.\n\
234 mtctr 3 \n\
235 # Put the registers back...\n\
236 lwz 0,48(1) \n\
237 lwz 10,44(1) \n\
238 lwz 9,40(1) \n\
239 mtlr 0 \n\
240 lwz 8,36(1) \n\
241 lwz 0,8(1) \n\
242 lwz 7,32(1) \n\
243 lwz 6,28(1) \n\
244 mtcrf 0xFF,0 \n\
245 lwz 5,24(1) \n\
246 lwz 4,20(1) \n\
247 lwz 3,16(1) \n\
248 lwz 0,12(1) \n\
249 # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
250 addi 1,1,64 \n\
251 bctr \n\
252 .size _dl_runtime_resolve,.-_dl_runtime_resolve \n\
253");
254#endif
4cca6b86 255
052b6a6c
UD
256/* The actual _start code is in dl-start.S. Use a really
257 ugly bit of assembler to let dl-start.o see _dl_start. */
258#define RTLD_START asm (".globl _dl_start");
4cca6b86 259
052b6a6c
UD
260/* Decide where a relocatable object should be loaded. */
261extern ElfW(Addr)
262__elf_preferred_address(struct link_map *loader, size_t maplength,
263 ElfW(Addr) mapstartpref);
264#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \
265 __elf_preferred_address (loader, maplength, mapstartpref)
e61abf83 266
1f205a47
UD
267/* Nonzero iff TYPE should not be allowed to resolve to one of
268 the main executable's symbols, as for a COPY reloc. */
269#define elf_machine_lookup_noexec_p(type) ((type) == R_PPC_COPY)
4cca6b86 270
1f205a47
UD
271/* Nonzero iff TYPE describes relocation of a PLT entry, so
272 PLT entries should not be allowed to define the value. */
273/* We never want to use a PLT entry as the destination of a
274 reloc, when what is being relocated is a branch. This is
275 partly for efficiency, but mostly so we avoid loops. */
276#define elf_machine_lookup_noplt_p(type) ((type) == R_PPC_REL24 || \
277 (type) == R_PPC_ADDR24 || \
278 (type) == R_PPC_JMP_SLOT)
4cca6b86 279
1f205a47 280/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
a2b08ee5 281#define ELF_MACHINE_JMP_SLOT R_PPC_JMP_SLOT
4cca6b86 282
4839f592
AJ
283/* The PowerPC never uses REL relocations. */
284#define ELF_MACHINE_NO_REL 1
285
4cca6b86 286/* Set up the loaded object described by L so its unrelocated PLT
5929563f
UD
287 entries will jump to the on-demand fixup code in dl-runtime.c.
288 Also install a small trampoline to be used by entries that have
289 been relocated to an address too far away for a single branch. */
052b6a6c
UD
290extern int __elf_machine_runtime_setup (struct link_map *map,
291 int lazy, int profile);
292#define elf_machine_runtime_setup __elf_machine_runtime_setup
5929563f 293
c2a32973 294static inline void
421c80d2
RM
295elf_machine_lazy_rel (struct link_map *map,
296 Elf32_Addr l_addr, const Elf32_Rela *reloc)
4cca6b86 297{
4cca6b86
UD
298 /* elf_machine_runtime_setup handles this. */
299}
300
052b6a6c 301/* Change the PLT entry whose reloc is 'reloc' to call the actual routine. */
c0282c06
UD
302extern Elf32_Addr __elf_machine_fixup_plt (struct link_map *map,
303 const Elf32_Rela *reloc,
304 Elf32_Addr *reloc_addr,
305 Elf32_Addr finaladdr);
306
307static inline Elf32_Addr
b6299091 308elf_machine_fixup_plt (struct link_map *map, lookup_t t,
c0282c06 309 const Elf32_Rela *reloc,
b6299091 310 Elf32_Addr *reloc_addr, Elf64_Addr finaladdr)
c0282c06 311{
b6299091 312 return __elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
c0282c06 313}
a2b08ee5 314
dfd2257a 315/* Return the final value of a plt relocation. */
c2a32973 316static inline Elf32_Addr
dfd2257a
UD
317elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
318 Elf32_Addr value)
319{
320 return value + reloc->r_addend;
321}
322
1f205a47 323#endif /* dl_machine_h */
4cca6b86 324
1f205a47 325#ifdef RESOLVE
4cca6b86 326
052b6a6c
UD
327/* Do the actual processing of a reloc, once its target address
328 has been determined. */
329extern void __process_machine_rela (struct link_map *map,
330 const Elf32_Rela *reloc,
331 const Elf32_Sym *sym,
332 const Elf32_Sym *refsym,
333 Elf32_Addr *const reloc_addr,
334 Elf32_Addr finaladdr,
335 int rinfo);
336
1f205a47
UD
337/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
338 LOADADDR is the load address of the object; INFO is an array indexed
339 by DT_* of the .dynamic section info. */
4cca6b86 340
6e4c40ba 341inline void
1f205a47 342elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
3996f34b 343 const Elf32_Sym *sym, const struct r_found_version *version,
0413b54c 344 Elf32_Addr *const reloc_addr)
1f205a47
UD
345{
346 const Elf32_Sym *const refsym = sym;
1f205a47
UD
347 Elf32_Word loadbase, finaladdr;
348 const int rinfo = ELF32_R_TYPE (reloc->r_info);
4cca6b86 349
1f205a47
UD
350 if (rinfo == R_PPC_NONE)
351 return;
4cca6b86 352
1f205a47
UD
353 /* The condition on the next two lines is a hack around a bug in Solaris
354 tools on Sparc. It's not clear whether it should really be here at all,
355 but if not the binutils need to be changed. */
052b6a6c
UD
356 if (rinfo == R_PPC_RELATIVE
357 || (sym->st_shndx != SHN_UNDEF
358 && ELF32_ST_BIND (sym->st_info) == STB_LOCAL))
1f205a47
UD
359 {
360 /* Has already been relocated. */
361 loadbase = map->l_addr;
362 finaladdr = loadbase + reloc->r_addend;
363 }
364 else
365 {
366 loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version,
367 ELF32_R_TYPE(reloc->r_info)));
368 if (sym == NULL)
369 {
370 /* Weak symbol that wasn't actually defined anywhere. */
371 assert(loadbase == 0);
372 finaladdr = reloc->r_addend;
373 }
374 else
375 finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
376 + reloc->r_addend);
377 }
4cca6b86 378
052b6a6c
UD
379 /* A small amount of code is duplicated here for speed. In libc,
380 more than 90% of the relocs are R_PPC_RELATIVE; in the X11 shared
381 libraries, 60% are R_PPC_RELATIVE, 24% are R_PPC_GLOB_DAT or
382 R_PPC_ADDR32, and 16% are R_PPC_JMP_SLOT (which this routine
383 wouldn't usually handle). As an bonus, doing this here allows
384 the switch statement in __process_machine_rela to work. */
385 if (rinfo == R_PPC_RELATIVE
386 || rinfo == R_PPC_GLOB_DAT
387 || rinfo == R_PPC_ADDR32)
1f205a47
UD
388 {
389 *reloc_addr = finaladdr;
390 }
1f205a47 391 else
052b6a6c
UD
392 __process_machine_rela (map, reloc, sym, refsym,
393 reloc_addr, finaladdr, rinfo);
1f205a47
UD
394}
395
1f205a47 396
052b6a6c
UD
397/* The SVR4 ABI specifies that the JMPREL relocs must be inside the
398 DT_RELA table. */
399#define ELF_MACHINE_PLTREL_OVERLAP 1
400
650425ce 401#endif /* RESOLVE */