Add hidden_def.
[glibc.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
blob843737eb86cd7d41aa1babd0d5c8e8b1316c103d
1 /* Machine-dependent ELF dynamic relocation inline functions.
2 PowerPC64 version.
3 Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with the GNU C Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #ifndef dl_machine_h
23 #define dl_machine_h
25 #define ELF_MACHINE_NAME "powerpc64"
27 #include <assert.h>
28 #include <sys/param.h>
29 #include <dl-tls.h>
31 /* Translate a processor specific dynamic tag to the index
32 in l_info array. */
33 #define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
35 /* A PowerPC64 function descriptor. The .plt (procedure linkage
36 table) and .opd (official procedure descriptor) sections are
37 arrays of these. */
38 typedef struct
40 Elf64_Addr fd_func;
41 Elf64_Addr fd_toc;
42 Elf64_Addr fd_aux;
43 } Elf64_FuncDesc;
45 #define ELF_MULT_MACHINES_SUPPORTED
47 /* Return nonzero iff ELF header is compatible with the running host. */
48 static inline int
49 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
51 return ehdr->e_machine == EM_PPC64;
54 /* Return nonzero iff ELF header is compatible with the running host,
55 but not this loader. */
56 static inline int
57 elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
59 return ehdr->e_machine == EM_PPC;
62 /* Return nonzero iff ELF header is compatible with the running host,
63 but not this loader. */
64 static inline int
65 elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
67 return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
71 /* Return the run-time load address of the shared object, assuming it
72 was originally linked at zero. */
73 static inline Elf64_Addr
74 elf_machine_load_address (void) __attribute__ ((const));
76 static inline Elf64_Addr
77 elf_machine_load_address (void)
79 Elf64_Addr ret;
81 /* The first entry in .got (and thus the first entry in .toc) is the
82 link-time TOC_base, ie. r2. So the difference between that and
83 the current r2 set by the kernel is how far the shared lib has
84 moved. */
85 asm ( " ld %0,-32768(2)\n"
86 " subf %0,%0,2\n"
87 : "=r" (ret));
88 return ret;
91 /* Return the link-time address of _DYNAMIC. */
92 static inline Elf64_Addr
93 elf_machine_dynamic (void)
95 Elf64_Addr runtime_dynamic;
96 /* It's easier to get the run-time address. */
97 asm ( " addis %0,2,_DYNAMIC@toc@ha\n"
98 " addi %0,%0,_DYNAMIC@toc@l\n"
99 : "=b" (runtime_dynamic));
100 /* Then subtract off the load address offset. */
101 return runtime_dynamic - elf_machine_load_address() ;
104 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
106 /* The PLT uses Elf64_Rela relocs. */
107 #define elf_machine_relplt elf_machine_rela
109 /* This code gets called via a .glink stub which loads PLT0. It is
110 used in dl-runtime.c to call the `fixup' function and then redirect
111 to the address `fixup' returns.
113 Enter with r0 = plt reloc index,
114 r2 = ld.so tocbase,
115 r11 = ld.so link map. */
117 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
118 asm (".section \".text\"\n" \
119 " .align 2\n" \
120 " .globl ." #tramp_name "\n" \
121 " .type ." #tramp_name ",@function\n" \
122 " .section \".opd\",\"aw\"\n" \
123 " .align 3\n" \
124 " .globl " #tramp_name "\n" \
125 " .size " #tramp_name ",24\n" \
126 #tramp_name ":\n" \
127 " .quad ." #tramp_name ",.TOC.@tocbase,0\n" \
128 " .previous\n" \
129 "." #tramp_name ":\n" \
130 /* We need to save the registers used to pass parameters, ie. r3 thru \
131 r10; the registers are saved in a stack frame. */ \
132 " stdu 1,-128(1)\n" \
133 " std 3,48(1)\n" \
134 " mr 3,11\n" \
135 " std 4,56(1)\n" \
136 " sldi 4,0,1\n" \
137 " std 5,64(1)\n" \
138 " add 4,4,0\n" \
139 " std 6,72(1)\n" \
140 " sldi 4,4,3\n" \
141 " std 7,80(1)\n" \
142 " mflr 0\n" \
143 " std 8,88(1)\n" \
144 /* Store the LR in the LR Save area of the previous frame. */ \
145 " std 0,128+16(1)\n" \
146 " mfcr 0\n" \
147 " std 9,96(1)\n" \
148 " std 10,104(1)\n" \
149 /* I'm almost certain we don't have to save cr... be safe. */ \
150 " std 0,8(1)\n" \
151 " bl ." #fixup_name "\n" \
152 /* Put the registers back. */ \
153 " ld 0,128+16(1)\n" \
154 " ld 10,104(1)\n" \
155 " ld 9,96(1)\n" \
156 " ld 8,88(1)\n" \
157 " ld 7,80(1)\n" \
158 " mtlr 0\n" \
159 " ld 0,8(1)\n" \
160 " ld 6,72(1)\n" \
161 " ld 5,64(1)\n" \
162 " ld 4,56(1)\n" \
163 " mtcrf 0xFF,0\n" \
164 /* Load the target address, toc and static chain reg from the function \
165 descriptor returned by fixup. */ \
166 " ld 0,0(3)\n" \
167 " ld 2,8(3)\n" \
168 " mtctr 0\n" \
169 " ld 11,16(3)\n" \
170 " ld 3,48(1)\n" \
171 /* Unwind the stack frame, and jump. */ \
172 " addi 1,1,128\n" \
173 " bctr\n" \
174 ".LT_" #tramp_name ":\n" \
175 " .long 0\n" \
176 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
177 " .long .LT_" #tramp_name "-."#tramp_name "\n" \
178 " .short .LT_" #tramp_name "_name_end-.LT_" #tramp_name "_name_start\n" \
179 ".LT_" #tramp_name "_name_start:\n" \
180 " .ascii \"" #tramp_name "\"\n" \
181 ".LT_" #tramp_name "_name_end:\n" \
182 " .align 2\n" \
183 " .size ." #tramp_name ",. - ." #tramp_name "\n" \
184 " .previous");
186 #ifndef PROF
187 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
188 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
189 TRAMPOLINE_TEMPLATE (_dl_profile_resolve, profile_fixup);
190 #else
191 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
192 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
193 void _dl_runtime_resolve (void); \
194 strong_alias (_dl_runtime_resolve, _dl_profile_resolve);
195 #endif
198 /* Initial entry point code for the dynamic linker. The C function
199 `_dl_start' is the real entry point; its return value is the user
200 program's entry point. */
201 #define RTLD_START \
202 asm (".section \".text\"\n" \
203 " .align 2\n" \
204 " .globl ._start\n" \
205 " .type ._start,@function\n" \
206 " .section \".opd\",\"aw\"\n" \
207 " .align 3\n" \
208 " .globl _start\n" \
209 " .size _start,24\n" \
210 "_start:\n" \
211 " .quad ._start,.TOC.@tocbase,0\n" \
212 " .previous\n" \
213 "._start:\n" \
214 /* We start with the following on the stack, from top: \
215 argc (4 bytes); \
216 arguments for program (terminated by NULL); \
217 environment variables (terminated by NULL); \
218 arguments for the program loader. */ \
219 " mr 3,1\n" \
220 " li 4,0\n" \
221 " stdu 4,-128(1)\n" \
222 /* Call _dl_start with one parameter pointing at argc. */ \
223 " bl ._dl_start\n" \
224 " nop\n" \
225 /* Transfer control to _dl_start_user! */ \
226 " b ._dl_start_user\n" \
227 ".LT__start:\n" \
228 " .long 0\n" \
229 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
230 " .long .LT__start-._start\n" \
231 " .short .LT__start_name_end-.LT__start_name_start\n" \
232 ".LT__start_name_start:\n" \
233 " .ascii \"_start\"\n" \
234 ".LT__start_name_end:\n" \
235 " .align 2\n" \
236 " .size ._start,.-._start\n" \
237 " .globl _dl_start_user\n" \
238 " .section \".opd\",\"aw\"\n" \
239 "_dl_start_user:\n" \
240 " .quad ._dl_start_user, .TOC.@tocbase, 0\n" \
241 " .previous\n" \
242 " .section \".toc\",\"aw\"\n" \
243 ".LC__dl_starting_up:\n" \
244 " .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n" \
245 ".LC__rtld_global:\n" \
246 " .tc _rtld_global[TC],_rtld_global\n" \
247 ".LC__dl_argc:\n" \
248 " .tc _dl_argc[TC],_dl_argc\n" \
249 ".LC__dl_argv:\n" \
250 " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
251 ".LC__dl_fini:\n" \
252 " .tc _dl_fini[TC],_dl_fini\n" \
253 " .previous\n" \
254 " .globl ._dl_start_user\n" \
255 " .type ._dl_start_user,@function\n" \
256 /* Now, we do our main work of calling initialisation procedures. \
257 The ELF ABI doesn't say anything about parameters for these, \
258 so we just pass argc, argv, and the environment. \
259 Changing these is strongly discouraged (not least because argc is \
260 passed by value!). */ \
261 "._dl_start_user:\n" \
262 /* the address of _start in r30. */ \
263 " mr 30,3\n" \
264 /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
265 " ld 28,.LC__rtld_global@toc(2)\n" \
266 " ld 29,.LC__dl_argc@toc(2)\n" \
267 " ld 27,.LC__dl_argv@toc(2)\n" \
268 /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \
269 " ld 3,0(28)\n" \
270 " lwa 4,0(29)\n" \
271 " ld 5,0(27)\n" \
272 " sldi 6,4,3\n" \
273 " add 6,5,6\n" \
274 " addi 6,6,8\n" \
275 " bl ._dl_init\n" \
276 " nop\n" \
277 /* Now, to conform to the ELF ABI, we have to: \
278 Pass argc (actually _dl_argc) in r3; */ \
279 " lwa 3,0(29)\n" \
280 /* Pass argv (actually _dl_argv) in r4; */ \
281 " ld 4,0(27)\n" \
282 /* Pass argv+argc+1 in r5; */ \
283 " sldi 5,3,3\n" \
284 " add 6,4,5\n" \
285 " addi 5,6,8\n" \
286 /* Pass the auxilary vector in r6. This is passed to us just after \
287 _envp. */ \
288 "2: ldu 0,8(6)\n" \
289 " cmpdi 0,0\n" \
290 " bne 2b\n" \
291 " addi 6,6,8\n" \
292 /* Pass a termination function pointer (in this case _dl_fini) in \
293 r7. */ \
294 " ld 7,.LC__dl_fini@toc(2)\n" \
295 " ld 26,.LC__dl_starting_up@toc(2)\n" \
296 /* Pass the stack pointer in r1 (so far so good), pointing to a NULL \
297 value. This lets our startup code distinguish between a program \
298 linked statically, which linux will call with argc on top of the \
299 stack which will hopefully never be zero, and a dynamically linked \
300 program which will always have a NULL on the top of the stack. \
301 Take the opportunity to clear LR, so anyone who accidentally \
302 returns from _start gets SEGV. Also clear the next few words of \
303 the stack. */ \
304 " li 31,0\n" \
305 " std 31,0(1)\n" \
306 " mtlr 31\n" \
307 " std 31,8(1)\n" \
308 " std 31,16(1)\n" \
309 " std 31,24(1)\n" \
310 /* Clear _dl_starting_up. */ \
311 " stw 31,0(26)\n" \
312 /* Now, call the start function descriptor at r30... */ \
313 " .globl ._dl_main_dispatch\n" \
314 "._dl_main_dispatch:\n" \
315 " ld 0,0(30)\n" \
316 " ld 2,8(30)\n" \
317 " mtctr 0\n" \
318 " ld 11,16(30)\n" \
319 " bctr\n" \
320 ".LT__dl_start_user:\n" \
321 " .long 0\n" \
322 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
323 " .long .LT__dl_start_user-._dl_start_user\n" \
324 " .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
325 ".LT__dl_start_user_name_start:\n" \
326 " .ascii \"_dl_start_user\"\n" \
327 ".LT__dl_start_user_name_end:\n" \
328 " .align 2\n" \
329 " .size ._dl_start_user,.-._dl_start_user\n" \
330 " .previous");
332 /* Nonzero iff TYPE should not be allowed to resolve to one of
333 the main executable's symbols, as for a COPY reloc. */
334 #define elf_machine_lookup_noexec_p(type) ((type) == R_PPC64_COPY)
336 /* Nonzero iff TYPE describes relocation of a PLT entry, so
337 PLT entries should not be allowed to define the value. */
338 #define elf_machine_lookup_noplt_p(type) ((type) == R_PPC64_JMP_SLOT)
340 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
341 PLT entries should not be allowed to define the value.
342 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
343 of the main executable's symbols, as for a COPY reloc. */
345 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
346 #define elf_machine_type_class(type) \
347 /* This covers all the TLS relocs, though most won't appear. */ \
348 (((((type) >= R_PPC64_DTPMOD64 && (type) <= R_PPC64_TPREL16_HIGHESTA) \
349 || (type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
350 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
351 #else
352 #define elf_machine_type_class(type) \
353 ((((type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
354 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
355 #endif
357 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
358 #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
360 /* The PowerPC never uses REL relocations. */
361 #define ELF_MACHINE_NO_REL 1
363 /* Stuff for the PLT. */
364 #define PLT_INITIAL_ENTRY_WORDS 3
365 #define GLINK_INITIAL_ENTRY_WORDS 8
367 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
368 #define PPC_SYNC asm volatile ("sync" : : : "memory")
369 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
370 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
371 #define PPC_DIE asm volatile ("tweq 0,0")
372 /* Use this when you've modified some code, but it won't be in the
373 instruction fetch queue (or when it doesn't matter if it is). */
374 #define MODIFIED_CODE_NOQUEUE(where) \
375 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
376 /* Use this when it might be in the instruction queue. */
377 #define MODIFIED_CODE(where) \
378 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
380 /* Set up the loaded object described by MAP so its unrelocated PLT
381 entries will jump to the on-demand fixup code in dl-runtime.c. */
382 static inline int
383 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
385 if (map->l_info[DT_JMPREL])
387 Elf64_Word i;
388 Elf64_Word *glink = NULL;
389 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
390 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
391 / sizeof (Elf64_Rela));
392 Elf64_Addr l_addr = map->l_addr;
393 Elf64_Dyn **info = map->l_info;
394 char *p;
396 extern void _dl_runtime_resolve (void);
397 extern void _dl_profile_resolve (void);
399 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
400 elf_get_dynamic_info takes care of the standard entries but
401 doesn't know exactly what to do with processor specific
402 entires. */
403 if (info[DT_PPC64(GLINK)] != NULL)
404 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
406 if (lazy)
408 /* The function descriptor of the appropriate trampline
409 routine is used to set the 1st and 2nd doubleword of the
410 plt_reserve. */
411 Elf64_FuncDesc *resolve_fd;
412 Elf64_Word glink_offset;
413 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
414 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
415 Elf64_Word offset;
417 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
418 : _dl_runtime_resolve);
419 if (profile && _dl_name_match_p (GL(dl_profile), map))
420 /* This is the object we are looking for. Say that we really
421 want profiling and the timers are started. */
422 GL(dl_profile_map) = map;
425 /* We need to stuff the address/TOC of _dl_runtime_resolve
426 into doublewords 0 and 1 of plt_reserve. Then we need to
427 stuff the map address into doubleword 2 of plt_reserve.
428 This allows the GLINK0 code to transfer control to the
429 correct trampoline which will transfer control to fixup
430 in dl-machine.c. */
431 plt_reserve->fd_func = resolve_fd->fd_func;
432 plt_reserve->fd_toc = resolve_fd->fd_toc;
433 plt_reserve->fd_aux = (Elf64_Addr) map;
434 #ifdef RTLD_BOOTSTRAP
435 /* When we're bootstrapping, the opd entry will not have
436 been relocated yet. */
437 plt_reserve->fd_func += l_addr;
438 plt_reserve->fd_toc += l_addr;
439 #endif
441 /* Set up the lazy PLT entries. */
442 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
443 offset = PLT_INITIAL_ENTRY_WORDS;
444 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
445 for (i = 0; i < num_plt_entries; i++)
448 plt[offset] = (Elf64_Xword) &glink[glink_offset];
449 offset += 3;
450 /* The first 32k entries of glink can set an index and
451 branch using two instructions; Past that point,
452 glink uses three instructions. */
453 if (i < 0x8000)
454 glink_offset += 2;
455 else
456 glink_offset += 3;
459 /* Now, we've modified data. We need to write the changes from
460 the data cache to a second-level unified cache, then make
461 sure that stale data in the instruction cache is removed.
462 (In a multiprocessor system, the effect is more complex.)
463 Most of the PLT shouldn't be in the instruction cache, but
464 there may be a little overlap at the start and the end.
466 Assumes that dcbst and icbi apply to lines of 16 bytes or
467 more. Current known line sizes are 16, 32, and 128 bytes. */
469 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
470 PPC_DCBST (p);
471 PPC_SYNC;
474 return lazy;
477 /* Change the PLT entry whose reloc is 'reloc' to call the actual
478 routine. */
479 static inline Elf64_Addr
480 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
481 const Elf64_Rela *reloc,
482 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
484 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
485 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
486 Elf64_Addr offset = 0;
488 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
489 if (sym_map == NULL)
490 return 0;
492 /* If the opd entry is not yet relocated (because it's from a shared
493 object that hasn't been processed yet), then manually reloc it. */
494 if (map != sym_map && !sym_map->l_relocated
495 #if !defined RTLD_BOOTSTRAP && defined SHARED
496 /* Bootstrap map doesn't have l_relocated set for it. */
497 && sym_map != &GL(dl_rtld_map)
498 #endif
500 offset = sym_map->l_addr;
502 /* For PPC64, fixup_plt copies the function descriptor from opd
503 over the corresponding PLT entry.
504 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
505 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
506 so for thread safety we write them before changing fd_func. */
508 plt->fd_aux = rel->fd_aux + offset;
509 plt->fd_toc = rel->fd_toc + offset;
510 PPC_DCBST (&plt->fd_aux);
511 PPC_DCBST (&plt->fd_toc);
512 PPC_SYNC;
514 plt->fd_func = rel->fd_func + offset;
515 PPC_DCBST (&plt->fd_func);
516 PPC_SYNC;
518 return finaladdr;
521 static inline void
522 elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
524 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
525 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
527 plt->fd_func = rel->fd_func;
528 plt->fd_aux = rel->fd_aux;
529 plt->fd_toc = rel->fd_toc;
530 PPC_DCBST (&plt->fd_func);
531 PPC_DCBST (&plt->fd_aux);
532 PPC_DCBST (&plt->fd_toc);
533 PPC_SYNC;
536 /* Return the final value of a plt relocation. */
537 static inline Elf64_Addr
538 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
539 Elf64_Addr value)
541 return value + reloc->r_addend;
544 #endif /* dl_machine_h */
546 #ifdef RESOLVE_MAP
548 #define PPC_LO(v) ((v) & 0xffff)
549 #define PPC_HI(v) (((v) >> 16) & 0xffff)
550 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
551 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
552 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
553 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
554 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
555 #define BIT_INSERT(var, val, mask) \
556 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
558 #define dont_expect(X) __builtin_expect ((X), 0)
560 extern void _dl_reloc_overflow (struct link_map *map,
561 const char *name,
562 Elf64_Addr *const reloc_addr,
563 const Elf64_Sym *refsym)
564 attribute_hidden;
566 static inline void
567 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
568 void *const reloc_addr_arg)
570 Elf64_Addr *const reloc_addr = reloc_addr_arg;
571 *reloc_addr = l_addr + reloc->r_addend;
574 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
575 /* This computes the value used by TPREL* relocs. */
576 static Elf64_Addr __attribute__ ((const))
577 elf_machine_tprel (struct link_map *map,
578 struct link_map *sym_map,
579 const Elf64_Sym *sym,
580 const Elf64_Rela *reloc)
582 # ifndef RTLD_BOOTSTRAP
583 if (sym_map)
585 CHECK_STATIC_TLS (map, sym_map);
586 # endif
587 return TLS_TPREL_VALUE (sym_map, sym, reloc);
588 # ifndef RTLD_BOOTSTRAP
590 # endif
591 return 0;
593 #endif
595 /* Perform the relocation specified by RELOC and SYM (which is fully
596 resolved). MAP is the object containing the reloc. */
597 static inline void
598 elf_machine_rela (struct link_map *map,
599 const Elf64_Rela *reloc,
600 const Elf64_Sym *sym,
601 const struct r_found_version *version,
602 void *const reloc_addr_arg)
604 Elf64_Addr *const reloc_addr = reloc_addr_arg;
605 const int r_type = ELF64_R_TYPE (reloc->r_info);
606 #ifndef RTLD_BOOTSTRAP
607 const Elf64_Sym *const refsym = sym;
608 #endif
610 if (r_type == R_PPC64_RELATIVE)
612 *reloc_addr = map->l_addr + reloc->r_addend;
613 return;
616 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
617 return;
619 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt. */
620 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
621 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
622 + reloc->r_addend);
624 /* For relocs that don't edit code, return.
625 For relocs that might edit instructions, break from the switch. */
626 switch (r_type)
628 case R_PPC64_ADDR64:
629 case R_PPC64_GLOB_DAT:
630 *reloc_addr = value;
631 return;
633 case R_PPC64_JMP_SLOT:
634 #ifdef RESOLVE_CONFLICT_FIND_MAP
635 elf_machine_plt_conflict (reloc_addr, value);
636 #else
637 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
638 #endif
639 return;
641 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
642 case R_PPC64_DTPMOD64:
643 # ifdef RTLD_BOOTSTRAP
644 /* During startup the dynamic linker is always index 1. */
645 *reloc_addr = 1;
646 # else
647 /* Get the information from the link map returned by the
648 resolve function. */
649 if (sym_map != NULL)
650 *reloc_addr = sym_map->l_tls_modid;
651 # endif
652 return;
654 case R_PPC64_DTPREL64:
655 /* During relocation all TLS symbols are defined and used.
656 Therefore the offset is already correct. */
657 # ifndef RTLD_BOOTSTRAP
658 if (sym_map != NULL)
659 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
660 # endif
661 return;
663 case R_PPC64_TPREL64:
664 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
665 return;
667 case R_PPC64_TPREL16_LO_DS:
668 value = elf_machine_tprel (map, sym_map, sym, reloc);
669 if (dont_expect ((value & 3) != 0))
670 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
671 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
672 value, 0xfffc);
673 break;
675 case R_PPC64_TPREL16_DS:
676 value = elf_machine_tprel (map, sym_map, sym, reloc);
677 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
678 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
679 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
680 value, 0xfffc);
681 break;
683 case R_PPC64_TPREL16:
684 value = elf_machine_tprel (map, sym_map, sym, reloc);
685 if (dont_expect ((value + 0x8000) >= 0x10000))
686 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
687 *(Elf64_Half *) reloc_addr = PPC_LO (value);
688 break;
690 case R_PPC64_TPREL16_LO:
691 value = elf_machine_tprel (map, sym_map, sym, reloc);
692 *(Elf64_Half *) reloc_addr = PPC_LO (value);
693 break;
695 case R_PPC64_TPREL16_HI:
696 value = elf_machine_tprel (map, sym_map, sym, reloc);
697 *(Elf64_Half *) reloc_addr = PPC_HI (value);
698 break;
700 case R_PPC64_TPREL16_HA:
701 value = elf_machine_tprel (map, sym_map, sym, reloc);
702 *(Elf64_Half *) reloc_addr = PPC_HA (value);
703 break;
705 case R_PPC64_TPREL16_HIGHER:
706 value = elf_machine_tprel (map, sym_map, sym, reloc);
707 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
708 break;
710 case R_PPC64_TPREL16_HIGHEST:
711 value = elf_machine_tprel (map, sym_map, sym, reloc);
712 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
713 break;
715 case R_PPC64_TPREL16_HIGHERA:
716 value = elf_machine_tprel (map, sym_map, sym, reloc);
717 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
718 break;
720 case R_PPC64_TPREL16_HIGHESTA:
721 value = elf_machine_tprel (map, sym_map, sym, reloc);
722 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
723 break;
724 #endif /* USE_TLS etc. */
726 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
727 case R_PPC64_ADDR16_LO_DS:
728 if (dont_expect ((value & 3) != 0))
729 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
730 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
731 break;
733 case R_PPC64_ADDR16_LO:
734 *(Elf64_Half *) reloc_addr = PPC_LO (value);
735 break;
737 case R_PPC64_ADDR16_HI:
738 *(Elf64_Half *) reloc_addr = PPC_HI (value);
739 break;
741 case R_PPC64_ADDR16_HA:
742 *(Elf64_Half *) reloc_addr = PPC_HA (value);
743 break;
745 case R_PPC64_ADDR30:
747 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
748 if (dont_expect ((delta + 0x80000000) >= 0x10000000
749 || (delta & 3) != 0))
750 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
751 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
753 break;
755 case R_PPC64_COPY:
756 if (dont_expect (sym == NULL))
757 /* This can happen in trace mode when an object could not be found. */
758 return;
759 if (dont_expect (sym->st_size > refsym->st_size
760 || (GL(dl_verbose) && sym->st_size < refsym->st_size)))
762 const char *strtab;
764 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
765 _dl_error_printf ("%s: Symbol `%s' has different size" \
766 " in shared object," \
767 " consider re-linking\n",
768 _dl_argv[0] ?: "<program name unknown>",
769 strtab + refsym->st_name);
771 memcpy (reloc_addr_arg, (char *) value,
772 MIN (sym->st_size, refsym->st_size));
773 return;
775 case R_PPC64_UADDR64:
776 /* We are big-endian. */
777 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
778 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
779 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
780 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
781 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
782 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
783 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
784 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
785 return;
787 case R_PPC64_UADDR32:
788 /* We are big-endian. */
789 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
790 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
791 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
792 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
793 return;
795 case R_PPC64_ADDR32:
796 if (dont_expect ((value + 0x80000000) >= 0x10000000))
797 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
798 *(Elf64_Word *) reloc_addr = value;
799 return;
801 case R_PPC64_ADDR24:
802 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
803 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
804 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
805 break;
807 case R_PPC64_ADDR16:
808 if (dont_expect ((value + 0x8000) >= 0x10000))
809 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
810 *(Elf64_Half *) reloc_addr = value;
811 break;
813 case R_PPC64_UADDR16:
814 if (dont_expect ((value + 0x8000) >= 0x10000))
815 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
816 /* We are big-endian. */
817 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
818 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
819 break;
821 case R_PPC64_ADDR16_DS:
822 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
823 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
824 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
825 break;
827 case R_PPC64_ADDR16_HIGHER:
828 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
829 break;
831 case R_PPC64_ADDR16_HIGHEST:
832 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
833 break;
835 case R_PPC64_ADDR16_HIGHERA:
836 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
837 break;
839 case R_PPC64_ADDR16_HIGHESTA:
840 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
841 break;
843 case R_PPC64_ADDR14:
844 case R_PPC64_ADDR14_BRTAKEN:
845 case R_PPC64_ADDR14_BRNTAKEN:
847 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
848 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
849 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
850 BIT_INSERT (insn, value, 0xfffc);
851 if (r_type != R_PPC64_ADDR14)
853 insn &= ~(1 << 21);
854 if (r_type == R_PPC64_ADDR14_BRTAKEN)
855 insn |= 1 << 21;
856 if ((insn & (0x14 << 21)) == (0x04 << 21))
857 insn |= 0x02 << 21;
858 else if ((insn & (0x14 << 21)) == (0x10 << 21))
859 insn |= 0x08 << 21;
861 *(Elf64_Word *) reloc_addr = insn;
863 break;
865 case R_PPC64_REL32:
866 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
867 return;
869 case R_PPC64_REL64:
870 *reloc_addr = value - (Elf64_Addr) reloc_addr;
871 return;
872 #endif /* !RTLD_BOOTSTRAP */
874 default:
875 _dl_reloc_bad_type (map, r_type, 0);
876 return;
878 MODIFIED_CODE_NOQUEUE (reloc_addr);
881 static inline void
882 elf_machine_lazy_rel (struct link_map *map,
883 Elf64_Addr l_addr, const Elf64_Rela *reloc)
885 /* elf_machine_runtime_setup handles this. */
888 #endif /* RESOLVE */