Replace FSF snail mail address with URLs.
[glibc.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
blob7c04757117fe9a09a49625f0df70015bb13f8369
1 /* Machine-dependent ELF dynamic relocation inline functions.
2 PowerPC64 version.
3 Copyright 1995-2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If
18 not, see <http://www.gnu.org/licenses/>. */
20 #ifndef dl_machine_h
21 #define dl_machine_h
23 #define ELF_MACHINE_NAME "powerpc64"
25 #include <assert.h>
26 #include <sys/param.h>
27 #include <dl-tls.h>
28 #include <sysdep.h>
30 /* Translate a processor specific dynamic tag to the index
31 in l_info array. */
32 #define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
34 /* A PowerPC64 function descriptor. The .plt (procedure linkage
35 table) and .opd (official procedure descriptor) sections are
36 arrays of these. */
37 typedef struct
39 Elf64_Addr fd_func;
40 Elf64_Addr fd_toc;
41 Elf64_Addr fd_aux;
42 } Elf64_FuncDesc;
44 #define ELF_MULT_MACHINES_SUPPORTED
46 /* Return nonzero iff ELF header is compatible with the running host. */
47 static inline int
48 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
50 return ehdr->e_machine == EM_PPC64;
53 /* Return nonzero iff ELF header is compatible with the running host,
54 but not this loader. */
55 static inline int
56 elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
58 return ehdr->e_machine == EM_PPC;
61 /* Return nonzero iff ELF header is compatible with the running host,
62 but not this loader. */
63 static inline int
64 elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
66 return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
70 /* Return the run-time load address of the shared object, assuming it
71 was originally linked at zero. */
72 static inline Elf64_Addr
73 elf_machine_load_address (void) __attribute__ ((const));
75 static inline Elf64_Addr
76 elf_machine_load_address (void)
78 Elf64_Addr ret;
80 /* The first entry in .got (and thus the first entry in .toc) is the
81 link-time TOC_base, ie. r2. So the difference between that and
82 the current r2 set by the kernel is how far the shared lib has
83 moved. */
84 asm ( " ld %0,-32768(2)\n"
85 " subf %0,%0,2\n"
86 : "=r" (ret));
87 return ret;
90 /* Return the link-time address of _DYNAMIC. */
91 static inline Elf64_Addr
92 elf_machine_dynamic (void)
94 Elf64_Addr runtime_dynamic;
95 /* It's easier to get the run-time address. */
96 asm ( " addis %0,2,_DYNAMIC@toc@ha\n"
97 " addi %0,%0,_DYNAMIC@toc@l\n"
98 : "=b" (runtime_dynamic));
99 /* Then subtract off the load address offset. */
100 return runtime_dynamic - elf_machine_load_address() ;
103 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
105 /* The PLT uses Elf64_Rela relocs. */
106 #define elf_machine_relplt elf_machine_rela
109 #ifdef HAVE_INLINED_SYSCALLS
110 /* We do not need _dl_starting_up. */
111 # define DL_STARTING_UP_DEF
112 #else
113 # define DL_STARTING_UP_DEF \
114 ".LC__dl_starting_up:\n" \
115 " .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n"
116 #endif
119 /* Initial entry point code for the dynamic linker. The C function
120 `_dl_start' is the real entry point; its return value is the user
121 program's entry point. */
122 #define RTLD_START \
123 asm (".pushsection \".text\"\n" \
124 " .align 2\n" \
125 " .type " BODY_PREFIX "_start,@function\n" \
126 " .pushsection \".opd\",\"aw\"\n" \
127 " .align 3\n" \
128 " .globl _start\n" \
129 " " ENTRY_2(_start) "\n" \
130 "_start:\n" \
131 " " OPD_ENT(_start) "\n" \
132 " .popsection\n" \
133 BODY_PREFIX "_start:\n" \
134 /* We start with the following on the stack, from top: \
135 argc (4 bytes); \
136 arguments for program (terminated by NULL); \
137 environment variables (terminated by NULL); \
138 arguments for the program loader. */ \
139 " mr 3,1\n" \
140 " li 4,0\n" \
141 " stdu 4,-128(1)\n" \
142 /* Call _dl_start with one parameter pointing at argc. */ \
143 " bl " DOT_PREFIX "_dl_start\n" \
144 " nop\n" \
145 /* Transfer control to _dl_start_user! */ \
146 " b " DOT_PREFIX "_dl_start_user\n" \
147 ".LT__start:\n" \
148 " .long 0\n" \
149 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
150 " .long .LT__start-" BODY_PREFIX "_start\n" \
151 " .short .LT__start_name_end-.LT__start_name_start\n" \
152 ".LT__start_name_start:\n" \
153 " .ascii \"_start\"\n" \
154 ".LT__start_name_end:\n" \
155 " .align 2\n" \
156 " " END_2(_start) "\n" \
157 " .globl _dl_start_user\n" \
158 " .pushsection \".opd\",\"aw\"\n" \
159 "_dl_start_user:\n" \
160 " " OPD_ENT(_dl_start_user) "\n" \
161 " .popsection\n" \
162 " .pushsection \".toc\",\"aw\"\n" \
163 DL_STARTING_UP_DEF \
164 ".LC__rtld_global:\n" \
165 " .tc _rtld_global[TC],_rtld_global\n" \
166 ".LC__dl_argc:\n" \
167 " .tc _dl_argc[TC],_dl_argc\n" \
168 ".LC__dl_argv:\n" \
169 " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
170 ".LC__dl_fini:\n" \
171 " .tc _dl_fini[TC],_dl_fini\n" \
172 " .popsection\n" \
173 " .type " BODY_PREFIX "_dl_start_user,@function\n" \
174 " " ENTRY_2(_dl_start_user) "\n" \
175 /* Now, we do our main work of calling initialisation procedures. \
176 The ELF ABI doesn't say anything about parameters for these, \
177 so we just pass argc, argv, and the environment. \
178 Changing these is strongly discouraged (not least because argc is \
179 passed by value!). */ \
180 BODY_PREFIX "_dl_start_user:\n" \
181 /* the address of _start in r30. */ \
182 " mr 30,3\n" \
183 /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
184 " ld 28,.LC__rtld_global@toc(2)\n" \
185 " ld 29,.LC__dl_argc@toc(2)\n" \
186 " ld 27,.LC__dl_argv@toc(2)\n" \
187 /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \
188 " ld 3,0(28)\n" \
189 " lwa 4,0(29)\n" \
190 " ld 5,0(27)\n" \
191 " sldi 6,4,3\n" \
192 " add 6,5,6\n" \
193 " addi 6,6,8\n" \
194 " bl " DOT_PREFIX "_dl_init\n" \
195 " nop\n" \
196 /* Now, to conform to the ELF ABI, we have to: \
197 Pass argc (actually _dl_argc) in r3; */ \
198 " lwa 3,0(29)\n" \
199 /* Pass argv (actually _dl_argv) in r4; */ \
200 " ld 4,0(27)\n" \
201 /* Pass argv+argc+1 in r5; */ \
202 " sldi 5,3,3\n" \
203 " add 6,4,5\n" \
204 " addi 5,6,8\n" \
205 /* Pass the auxilary vector in r6. This is passed to us just after \
206 _envp. */ \
207 "2: ldu 0,8(6)\n" \
208 " cmpdi 0,0\n" \
209 " bne 2b\n" \
210 " addi 6,6,8\n" \
211 /* Pass a termination function pointer (in this case _dl_fini) in \
212 r7. */ \
213 " ld 7,.LC__dl_fini@toc(2)\n" \
214 /* Pass the stack pointer in r1 (so far so good), pointing to a NULL \
215 value. This lets our startup code distinguish between a program \
216 linked statically, which linux will call with argc on top of the \
217 stack which will hopefully never be zero, and a dynamically linked \
218 program which will always have a NULL on the top of the stack. \
219 Take the opportunity to clear LR, so anyone who accidentally \
220 returns from _start gets SEGV. Also clear the next few words of \
221 the stack. */ \
222 " li 31,0\n" \
223 " std 31,0(1)\n" \
224 " mtlr 31\n" \
225 " std 31,8(1)\n" \
226 " std 31,16(1)\n" \
227 " std 31,24(1)\n" \
228 /* Now, call the start function descriptor at r30... */ \
229 " .globl ._dl_main_dispatch\n" \
230 "._dl_main_dispatch:\n" \
231 " ld 0,0(30)\n" \
232 " ld 2,8(30)\n" \
233 " mtctr 0\n" \
234 " ld 11,16(30)\n" \
235 " bctr\n" \
236 ".LT__dl_start_user:\n" \
237 " .long 0\n" \
238 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
239 " .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n" \
240 " .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
241 ".LT__dl_start_user_name_start:\n" \
242 " .ascii \"_dl_start_user\"\n" \
243 ".LT__dl_start_user_name_end:\n" \
244 " .align 2\n" \
245 " " END_2(_dl_start_user) "\n" \
246 " .popsection");
248 /* ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to
249 one of the main executable's symbols, as for a COPY reloc.
251 To make function pointer comparisons work on most targets, the
252 relevant ABI states that the address of a non-local function in a
253 dynamically linked executable is the address of the PLT entry for
254 that function. This is quite reasonable since using the real
255 function address in a non-PIC executable would typically require
256 dynamic relocations in .text, something to be avoided. For such
257 functions, the linker emits a SHN_UNDEF symbol in the executable
258 with value equal to the PLT entry address. Normally, SHN_UNDEF
259 symbols have a value of zero, so this is a clue to ld.so that it
260 should treat these symbols specially. For relocations not in
261 ELF_RTYPE_CLASS_PLT (eg. those on function pointers), ld.so should
262 use the value of the executable SHN_UNDEF symbol, ie. the PLT entry
263 address. For relocations in ELF_RTYPE_CLASS_PLT (eg. the relocs in
264 the PLT itself), ld.so should use the value of the corresponding
265 defined symbol in the object that defines the function, ie. the
266 real function address. This complicates ld.so in that there are
267 now two possible values for a given symbol, and it gets even worse
268 because protected symbols need yet another set of rules.
270 On PowerPC64 we don't need any of this. The linker won't emit
271 SHN_UNDEF symbols with non-zero values. ld.so can make all
272 relocations behave "normally", ie. always use the real address
273 like PLT relocations. So always set ELF_RTYPE_CLASS_PLT. */
275 #define elf_machine_type_class(type) \
276 (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
278 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
279 #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
281 /* The PowerPC never uses REL relocations. */
282 #define ELF_MACHINE_NO_REL 1
284 /* Stuff for the PLT. */
285 #define PLT_INITIAL_ENTRY_WORDS 3
286 #define GLINK_INITIAL_ENTRY_WORDS 8
288 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
289 #define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
290 #define PPC_DCBF(where) asm volatile ("dcbf 0,%0" : : "r"(where) : "memory")
291 #define PPC_SYNC asm volatile ("sync" : : : "memory")
292 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
293 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
294 #define PPC_DIE asm volatile ("tweq 0,0")
295 /* Use this when you've modified some code, but it won't be in the
296 instruction fetch queue (or when it doesn't matter if it is). */
297 #define MODIFIED_CODE_NOQUEUE(where) \
298 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
299 /* Use this when it might be in the instruction queue. */
300 #define MODIFIED_CODE(where) \
301 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
303 /* Set up the loaded object described by MAP so its unrelocated PLT
304 entries will jump to the on-demand fixup code in dl-runtime.c. */
305 static inline int __attribute__ ((always_inline))
306 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
308 if (map->l_info[DT_JMPREL])
310 Elf64_Word i;
311 Elf64_Word *glink = NULL;
312 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
313 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
314 / sizeof (Elf64_Rela));
315 Elf64_Addr l_addr = map->l_addr;
316 Elf64_Dyn **info = map->l_info;
317 char *p;
319 extern void _dl_runtime_resolve (void);
320 extern void _dl_profile_resolve (void);
322 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
323 elf_get_dynamic_info takes care of the standard entries but
324 doesn't know exactly what to do with processor specific
325 entires. */
326 if (info[DT_PPC64(GLINK)] != NULL)
327 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
329 if (lazy)
331 /* The function descriptor of the appropriate trampline
332 routine is used to set the 1st and 2nd doubleword of the
333 plt_reserve. */
334 Elf64_FuncDesc *resolve_fd;
335 Elf64_Word glink_offset;
336 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
337 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
338 Elf64_Word offset;
340 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
341 : _dl_runtime_resolve);
342 if (profile && GLRO(dl_profile) != NULL
343 && _dl_name_match_p (GLRO(dl_profile), map))
344 /* This is the object we are looking for. Say that we really
345 want profiling and the timers are started. */
346 GL(dl_profile_map) = map;
349 /* We need to stuff the address/TOC of _dl_runtime_resolve
350 into doublewords 0 and 1 of plt_reserve. Then we need to
351 stuff the map address into doubleword 2 of plt_reserve.
352 This allows the GLINK0 code to transfer control to the
353 correct trampoline which will transfer control to fixup
354 in dl-machine.c. */
355 plt_reserve->fd_func = resolve_fd->fd_func;
356 plt_reserve->fd_toc = resolve_fd->fd_toc;
357 plt_reserve->fd_aux = (Elf64_Addr) map;
358 #ifdef RTLD_BOOTSTRAP
359 /* When we're bootstrapping, the opd entry will not have
360 been relocated yet. */
361 plt_reserve->fd_func += l_addr;
362 plt_reserve->fd_toc += l_addr;
363 #endif
365 /* Set up the lazy PLT entries. */
366 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
367 offset = PLT_INITIAL_ENTRY_WORDS;
368 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
369 for (i = 0; i < num_plt_entries; i++)
372 plt[offset] = (Elf64_Xword) &glink[glink_offset];
373 offset += 3;
374 /* The first 32k entries of glink can set an index and
375 branch using two instructions; Past that point,
376 glink uses three instructions. */
377 if (i < 0x8000)
378 glink_offset += 2;
379 else
380 glink_offset += 3;
383 /* Now, we've modified data. We need to write the changes from
384 the data cache to a second-level unified cache, then make
385 sure that stale data in the instruction cache is removed.
386 (In a multiprocessor system, the effect is more complex.)
387 Most of the PLT shouldn't be in the instruction cache, but
388 there may be a little overlap at the start and the end.
390 Assumes that dcbst and icbi apply to lines of 16 bytes or
391 more. Current known line sizes are 16, 32, and 128 bytes. */
393 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
394 PPC_DCBST (p);
395 PPC_SYNC;
398 return lazy;
401 /* Change the PLT entry whose reloc is 'reloc' to call the actual
402 routine. */
403 static inline Elf64_Addr __attribute__ ((always_inline))
404 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
405 const Elf64_Rela *reloc,
406 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
408 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
409 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
410 Elf64_Addr offset = 0;
412 PPC_DCBT (&plt->fd_aux);
413 PPC_DCBT (&plt->fd_func);
414 PPC_DCBT (&rel->fd_aux);
415 PPC_DCBT (&rel->fd_func);
417 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
418 if (sym_map == NULL)
419 return 0;
421 /* If the opd entry is not yet relocated (because it's from a shared
422 object that hasn't been processed yet), then manually reloc it. */
423 if (map != sym_map && !sym_map->l_relocated
424 #if !defined RTLD_BOOTSTRAP && defined SHARED
425 /* Bootstrap map doesn't have l_relocated set for it. */
426 && sym_map != &GL(dl_rtld_map)
427 #endif
429 offset = sym_map->l_addr;
431 /* For PPC64, fixup_plt copies the function descriptor from opd
432 over the corresponding PLT entry.
433 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
434 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
435 so for thread safety we write them before changing fd_func. */
437 plt->fd_aux = rel->fd_aux + offset;
438 plt->fd_toc = rel->fd_toc + offset;
439 PPC_DCBF (&plt->fd_toc);
440 PPC_ISYNC;
442 plt->fd_func = rel->fd_func + offset;
443 PPC_DCBST (&plt->fd_func);
444 PPC_ISYNC;
446 return finaladdr;
449 static inline void __attribute__ ((always_inline))
450 elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
452 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
453 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
455 plt->fd_func = rel->fd_func;
456 plt->fd_aux = rel->fd_aux;
457 plt->fd_toc = rel->fd_toc;
458 PPC_DCBST (&plt->fd_func);
459 PPC_DCBST (&plt->fd_aux);
460 PPC_DCBST (&plt->fd_toc);
461 PPC_SYNC;
464 /* Return the final value of a plt relocation. */
465 static inline Elf64_Addr
466 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
467 Elf64_Addr value)
469 return value + reloc->r_addend;
473 /* Names of the architecture-specific auditing callback functions. */
474 #define ARCH_LA_PLTENTER ppc64_gnu_pltenter
475 #define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
477 #endif /* dl_machine_h */
479 #ifdef RESOLVE_MAP
481 #define PPC_LO(v) ((v) & 0xffff)
482 #define PPC_HI(v) (((v) >> 16) & 0xffff)
483 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
484 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
485 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
486 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
487 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
488 #define BIT_INSERT(var, val, mask) \
489 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
491 #define dont_expect(X) __builtin_expect ((X), 0)
493 extern void _dl_reloc_overflow (struct link_map *map,
494 const char *name,
495 Elf64_Addr *const reloc_addr,
496 const Elf64_Sym *refsym)
497 attribute_hidden;
499 auto inline void __attribute__ ((always_inline))
500 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
501 void *const reloc_addr_arg)
503 Elf64_Addr *const reloc_addr = reloc_addr_arg;
504 *reloc_addr = l_addr + reloc->r_addend;
507 /* This computes the value used by TPREL* relocs. */
508 auto inline Elf64_Addr __attribute__ ((always_inline, const))
509 elf_machine_tprel (struct link_map *map,
510 struct link_map *sym_map,
511 const Elf64_Sym *sym,
512 const Elf64_Rela *reloc)
514 #ifndef RTLD_BOOTSTRAP
515 if (sym_map)
517 CHECK_STATIC_TLS (map, sym_map);
518 #endif
519 return TLS_TPREL_VALUE (sym_map, sym, reloc);
520 #ifndef RTLD_BOOTSTRAP
522 #endif
523 return 0;
526 /* Call function at address VALUE (an OPD entry) to resolve ifunc relocs. */
527 auto inline Elf64_Addr __attribute__ ((always_inline))
528 resolve_ifunc (Elf64_Addr value,
529 const struct link_map *map, const struct link_map *sym_map)
531 #ifndef RESOLVE_CONFLICT_FIND_MAP
532 /* The function we are calling may not yet have its opd entry relocated. */
533 Elf64_FuncDesc opd;
534 if (map != sym_map
535 # if !defined RTLD_BOOTSTRAP && defined SHARED
536 /* Bootstrap map doesn't have l_relocated set for it. */
537 && sym_map != &GL(dl_rtld_map)
538 # endif
539 && !sym_map->l_relocated)
541 Elf64_FuncDesc *func = (Elf64_FuncDesc *) value;
542 opd.fd_func = func->fd_func + sym_map->l_addr;
543 opd.fd_toc = func->fd_toc + sym_map->l_addr;
544 opd.fd_aux = func->fd_aux;
545 value = (Elf64_Addr) &opd;
547 #endif
548 return ((Elf64_Addr (*) (void)) value) ();
551 /* Perform the relocation specified by RELOC and SYM (which is fully
552 resolved). MAP is the object containing the reloc. */
553 auto inline void __attribute__ ((always_inline))
554 elf_machine_rela (struct link_map *map,
555 const Elf64_Rela *reloc,
556 const Elf64_Sym *sym,
557 const struct r_found_version *version,
558 void *const reloc_addr_arg,
559 int skip_ifunc)
561 Elf64_Addr *const reloc_addr = reloc_addr_arg;
562 const int r_type = ELF64_R_TYPE (reloc->r_info);
563 const Elf64_Sym *const refsym = sym;
565 if (r_type == R_PPC64_RELATIVE)
567 *reloc_addr = map->l_addr + reloc->r_addend;
568 return;
571 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
572 return;
574 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
575 and STT_GNU_IFUNC. */
576 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
577 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
578 + reloc->r_addend);
580 if (sym != NULL
581 && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
582 && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
583 && __builtin_expect (!skip_ifunc, 1))
584 value = resolve_ifunc (value, map, sym_map);
586 /* For relocs that don't edit code, return.
587 For relocs that might edit instructions, break from the switch. */
588 switch (r_type)
590 case R_PPC64_ADDR64:
591 case R_PPC64_GLOB_DAT:
592 *reloc_addr = value;
593 return;
595 case R_PPC64_IRELATIVE:
596 if (__builtin_expect (!skip_ifunc, 1))
597 value = resolve_ifunc (value, map, sym_map);
598 *reloc_addr = value;
599 return;
601 case R_PPC64_JMP_IREL:
602 if (__builtin_expect (!skip_ifunc, 1))
603 value = resolve_ifunc (value, map, sym_map);
604 /* Fall thru */
605 case R_PPC64_JMP_SLOT:
606 #ifdef RESOLVE_CONFLICT_FIND_MAP
607 elf_machine_plt_conflict (reloc_addr, value);
608 #else
609 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
610 #endif
611 return;
613 case R_PPC64_DTPMOD64:
614 #ifdef RTLD_BOOTSTRAP
615 /* During startup the dynamic linker is always index 1. */
616 *reloc_addr = 1;
617 #else
618 /* Get the information from the link map returned by the
619 resolve function. */
620 if (sym_map != NULL)
621 *reloc_addr = sym_map->l_tls_modid;
622 #endif
623 return;
625 case R_PPC64_DTPREL64:
626 /* During relocation all TLS symbols are defined and used.
627 Therefore the offset is already correct. */
628 #ifndef RTLD_BOOTSTRAP
629 if (sym_map != NULL)
630 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
631 #endif
632 return;
634 case R_PPC64_TPREL64:
635 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
636 return;
638 case R_PPC64_TPREL16_LO_DS:
639 value = elf_machine_tprel (map, sym_map, sym, reloc);
640 if (dont_expect ((value & 3) != 0))
641 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
642 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
643 break;
645 case R_PPC64_TPREL16_DS:
646 value = elf_machine_tprel (map, sym_map, sym, reloc);
647 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
648 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
649 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
650 break;
652 case R_PPC64_TPREL16:
653 value = elf_machine_tprel (map, sym_map, sym, reloc);
654 if (dont_expect ((value + 0x8000) >= 0x10000))
655 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
656 *(Elf64_Half *) reloc_addr = PPC_LO (value);
657 break;
659 case R_PPC64_TPREL16_LO:
660 value = elf_machine_tprel (map, sym_map, sym, reloc);
661 *(Elf64_Half *) reloc_addr = PPC_LO (value);
662 break;
664 case R_PPC64_TPREL16_HI:
665 value = elf_machine_tprel (map, sym_map, sym, reloc);
666 *(Elf64_Half *) reloc_addr = PPC_HI (value);
667 break;
669 case R_PPC64_TPREL16_HA:
670 value = elf_machine_tprel (map, sym_map, sym, reloc);
671 *(Elf64_Half *) reloc_addr = PPC_HA (value);
672 break;
674 case R_PPC64_TPREL16_HIGHER:
675 value = elf_machine_tprel (map, sym_map, sym, reloc);
676 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
677 break;
679 case R_PPC64_TPREL16_HIGHEST:
680 value = elf_machine_tprel (map, sym_map, sym, reloc);
681 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
682 break;
684 case R_PPC64_TPREL16_HIGHERA:
685 value = elf_machine_tprel (map, sym_map, sym, reloc);
686 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
687 break;
689 case R_PPC64_TPREL16_HIGHESTA:
690 value = elf_machine_tprel (map, sym_map, sym, reloc);
691 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
692 break;
694 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
695 case R_PPC64_ADDR16_LO_DS:
696 if (dont_expect ((value & 3) != 0))
697 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
698 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
699 break;
701 case R_PPC64_ADDR16_LO:
702 *(Elf64_Half *) reloc_addr = PPC_LO (value);
703 break;
705 case R_PPC64_ADDR16_HI:
706 *(Elf64_Half *) reloc_addr = PPC_HI (value);
707 break;
709 case R_PPC64_ADDR16_HA:
710 *(Elf64_Half *) reloc_addr = PPC_HA (value);
711 break;
713 case R_PPC64_ADDR30:
715 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
716 if (dont_expect ((delta + 0x80000000) >= 0x10000000
717 || (delta & 3) != 0))
718 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
719 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
721 break;
723 case R_PPC64_COPY:
724 if (dont_expect (sym == NULL))
725 /* This can happen in trace mode when an object could not be found. */
726 return;
727 if (dont_expect (sym->st_size > refsym->st_size
728 || (GLRO(dl_verbose)
729 && sym->st_size < refsym->st_size)))
731 const char *strtab;
733 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
734 _dl_error_printf ("%s: Symbol `%s' has different size" \
735 " in shared object," \
736 " consider re-linking\n",
737 _dl_argv[0] ?: "<program name unknown>",
738 strtab + refsym->st_name);
740 memcpy (reloc_addr_arg, (char *) value,
741 MIN (sym->st_size, refsym->st_size));
742 return;
744 case R_PPC64_UADDR64:
745 /* We are big-endian. */
746 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
747 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
748 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
749 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
750 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
751 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
752 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
753 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
754 return;
756 case R_PPC64_UADDR32:
757 /* We are big-endian. */
758 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
759 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
760 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
761 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
762 return;
764 case R_PPC64_ADDR32:
765 if (dont_expect ((value + 0x80000000) >= 0x10000000))
766 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
767 *(Elf64_Word *) reloc_addr = value;
768 return;
770 case R_PPC64_ADDR24:
771 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
772 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
773 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
774 break;
776 case R_PPC64_ADDR16:
777 if (dont_expect ((value + 0x8000) >= 0x10000))
778 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
779 *(Elf64_Half *) reloc_addr = value;
780 break;
782 case R_PPC64_UADDR16:
783 if (dont_expect ((value + 0x8000) >= 0x10000))
784 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
785 /* We are big-endian. */
786 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
787 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
788 break;
790 case R_PPC64_ADDR16_DS:
791 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
792 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
793 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
794 break;
796 case R_PPC64_ADDR16_HIGHER:
797 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
798 break;
800 case R_PPC64_ADDR16_HIGHEST:
801 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
802 break;
804 case R_PPC64_ADDR16_HIGHERA:
805 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
806 break;
808 case R_PPC64_ADDR16_HIGHESTA:
809 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
810 break;
812 case R_PPC64_ADDR14:
813 case R_PPC64_ADDR14_BRTAKEN:
814 case R_PPC64_ADDR14_BRNTAKEN:
816 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
817 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
818 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
819 BIT_INSERT (insn, value, 0xfffc);
820 if (r_type != R_PPC64_ADDR14)
822 insn &= ~(1 << 21);
823 if (r_type == R_PPC64_ADDR14_BRTAKEN)
824 insn |= 1 << 21;
825 if ((insn & (0x14 << 21)) == (0x04 << 21))
826 insn |= 0x02 << 21;
827 else if ((insn & (0x14 << 21)) == (0x10 << 21))
828 insn |= 0x08 << 21;
830 *(Elf64_Word *) reloc_addr = insn;
832 break;
834 case R_PPC64_REL32:
835 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
836 return;
838 case R_PPC64_REL64:
839 *reloc_addr = value - (Elf64_Addr) reloc_addr;
840 return;
841 #endif /* !RTLD_BOOTSTRAP */
843 default:
844 _dl_reloc_bad_type (map, r_type, 0);
845 return;
847 MODIFIED_CODE_NOQUEUE (reloc_addr);
850 auto inline void __attribute__ ((always_inline))
851 elf_machine_lazy_rel (struct link_map *map,
852 Elf64_Addr l_addr, const Elf64_Rela *reloc,
853 int skip_ifunc)
855 /* elf_machine_runtime_setup handles this. */
859 #endif /* RESOLVE */