1 /* Machine-dependent ELF dynamic relocation inline functions.
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. */
25 #define ELF_MACHINE_NAME "powerpc64"
28 #include <sys/param.h>
31 /* Translate a processor specific dynamic tag to the index
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
45 #define ELF_MULT_MACHINES_SUPPORTED
47 /* Return nonzero iff ELF header is compatible with the running host. */
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. */
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. */
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)
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
85 asm ( " ld %0,-32768(2)\n"
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,
115 r11 = ld.so link map. */
117 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
118 asm (".section \".text\"\n" \
120 " .globl ." #tramp_name "\n" \
121 " .type ." #tramp_name ",@function\n" \
122 " .section \".opd\",\"aw\"\n" \
124 " .globl " #tramp_name "\n" \
125 " .size " #tramp_name ",24\n" \
127 " .quad ." #tramp_name ",.TOC.@tocbase,0\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" \
144 /* Store the LR in the LR Save area of the previous frame. */ \
145 " std 0,128+16(1)\n" \
149 /* I'm almost certain we don't have to save cr... be safe. */ \
151 " bl ." #fixup_name "\n" \
152 /* Put the registers back. */ \
153 " ld 0,128+16(1)\n" \
164 /* Load the target address, toc and static chain reg from the function \
165 descriptor returned by fixup. */ \
171 /* Unwind the stack frame, and jump. */ \
174 ".LT_" #tramp_name ":\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" \
183 " .size ." #tramp_name ",. - ." #tramp_name "\n" \
187 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
188 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
189 TRAMPOLINE_TEMPLATE (_dl_profile_resolve, profile_fixup);
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);
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. */
202 asm (".section \".text\"\n" \
204 " .globl ._start\n" \
205 " .type ._start,@function\n" \
206 " .section \".opd\",\"aw\"\n" \
209 " .size _start,24\n" \
211 " .quad ._start,.TOC.@tocbase,0\n" \
214 /* We start with the following on the stack, from top: \
216 arguments for program (terminated by NULL); \
217 environment variables (terminated by NULL); \
218 arguments for the program loader. */ \
221 " stdu 4,-128(1)\n" \
222 /* Call _dl_start with one parameter pointing at argc. */ \
225 /* Transfer control to _dl_start_user! */ \
226 " b ._dl_start_user\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" \
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" \
242 " .globl ._dl_start_user\n" \
243 " .type ._dl_start_user,@function\n" \
244 /* Now, we do our main work of calling initialisation procedures. \
245 The ELF ABI doesn't say anything about parameters for these, \
246 so we just pass argc, argv, and the environment. \
247 Changing these is strongly discouraged (not least because argc is \
248 passed by value!). */ \
249 "._dl_start_user:\n" \
250 /* the address of _start in r30. */ \
252 /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
253 " ld 28,_rtld_global@got(2)\n" \
254 " ld 29,_dl_argc@got(2)\n" \
255 " ld 27,_dl_argv@got(2)\n" \
256 /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \
265 /* Now, to conform to the ELF ABI, we have to: \
266 Pass argc (actually _dl_argc) in r3; */ \
268 /* Pass argv (actually _dl_argv) in r4; */ \
270 /* Pass argv+argc+1 in r5; */ \
274 /* Pass the auxilary vector in r6. This is passed to us just after \
280 /* Pass a termination function pointer (in this case _dl_fini) in \
282 " ld 7,_dl_fini@got(2)\n" \
283 " ld 26,_dl_starting_up@got(2)\n" \
284 /* Pass the stack pointer in r1 (so far so good), pointing to a NULL \
285 value. This lets our startup code distinguish between a program \
286 linked statically, which linux will call with argc on top of the \
287 stack which will hopefully never be zero, and a dynamically linked \
288 program which will always have a NULL on the top of the stack. \
289 Take the opportunity to clear LR, so anyone who accidentally \
290 returns from _start gets SEGV. Also clear the next few words of \
298 /* Clear _dl_starting_up. */ \
300 /* Now, call the start function descriptor at r30... */ \
301 " .globl ._dl_main_dispatch\n" \
302 "._dl_main_dispatch:\n" \
308 ".LT__dl_start_user:\n" \
310 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
311 " .long .LT__dl_start_user-._dl_start_user\n" \
312 " .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
313 ".LT__dl_start_user_name_start:\n" \
314 " .ascii \"_dl_start_user\"\n" \
315 ".LT__dl_start_user_name_end:\n" \
317 " .size ._dl_start_user,.-._dl_start_user\n" \
320 /* Nonzero iff TYPE should not be allowed to resolve to one of
321 the main executable's symbols, as for a COPY reloc. */
322 #define elf_machine_lookup_noexec_p(type) ((type) == R_PPC64_COPY)
324 /* Nonzero iff TYPE describes relocation of a PLT entry, so
325 PLT entries should not be allowed to define the value. */
326 #define elf_machine_lookup_noplt_p(type) ((type) == R_PPC64_JMP_SLOT)
328 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
329 PLT entries should not be allowed to define the value.
330 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
331 of the main executable's symbols, as for a COPY reloc. */
333 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
334 #define elf_machine_type_class(type) \
335 /* This covers all the TLS relocs, though most won't appear. */ \
336 (((((type) >= R_PPC64_DTPMOD64 && (type) <= R_PPC64_TPREL16_HIGHESTA) \
337 || (type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
338 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
340 #define elf_machine_type_class(type) \
341 ((((type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
342 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
345 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
346 #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
348 /* The PowerPC never uses REL relocations. */
349 #define ELF_MACHINE_NO_REL 1
351 /* Stuff for the PLT. */
352 #define PLT_INITIAL_ENTRY_WORDS 3
353 #define GLINK_INITIAL_ENTRY_WORDS 8
355 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
356 #define PPC_SYNC asm volatile ("sync" : : : "memory")
357 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
358 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
359 #define PPC_DIE asm volatile ("tweq 0,0")
360 /* Use this when you've modified some code, but it won't be in the
361 instruction fetch queue (or when it doesn't matter if it is). */
362 #define MODIFIED_CODE_NOQUEUE(where) \
363 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
364 /* Use this when it might be in the instruction queue. */
365 #define MODIFIED_CODE(where) \
366 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
368 /* Set up the loaded object described by MAP so its unrelocated PLT
369 entries will jump to the on-demand fixup code in dl-runtime.c. */
371 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
373 if (map->l_info[DT_JMPREL])
376 Elf64_Word *glink = NULL;
377 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
378 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
379 / sizeof (Elf64_Rela));
380 Elf64_Addr l_addr = map->l_addr;
381 Elf64_Dyn **info = map->l_info;
384 extern void _dl_runtime_resolve (void);
385 extern void _dl_profile_resolve (void);
387 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
388 elf_get_dynamic_info takes care of the standard entries but
389 doesn't know exactly what to do with processor specific
391 if (info[DT_PPC64(GLINK)] != NULL)
392 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
396 /* The function descriptor of the appropriate trampline
397 routine is used to set the 1st and 2nd doubleword of the
399 Elf64_FuncDesc *resolve_fd;
400 Elf64_Word glink_offset;
401 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
402 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
405 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
406 : _dl_runtime_resolve);
407 if (profile && _dl_name_match_p (GL(dl_profile), map))
408 /* This is the object we are looking for. Say that we really
409 want profiling and the timers are started. */
410 GL(dl_profile_map) = map;
413 /* We need to stuff the address/TOC of _dl_runtime_resolve
414 into doublewords 0 and 1 of plt_reserve. Then we need to
415 stuff the map address into doubleword 2 of plt_reserve.
416 This allows the GLINK0 code to transfer control to the
417 correct trampoline which will transfer control to fixup
419 plt_reserve->fd_func = resolve_fd->fd_func;
420 plt_reserve->fd_toc = resolve_fd->fd_toc;
421 plt_reserve->fd_aux = (Elf64_Addr) map;
422 #ifdef RTLD_BOOTSTRAP
423 /* When we're bootstrapping, the opd entry will not have
424 been relocated yet. */
425 plt_reserve->fd_func += l_addr;
426 plt_reserve->fd_toc += l_addr;
429 /* Set up the lazy PLT entries. */
430 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
431 offset = PLT_INITIAL_ENTRY_WORDS;
432 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
433 for (i = 0; i < num_plt_entries; i++)
436 plt[offset] = (Elf64_Xword) &glink[glink_offset];
438 /* The first 32k entries of glink can set an index and
439 branch using two instructions; Past that point,
440 glink uses three instructions. */
447 /* Now, we've modified data. We need to write the changes from
448 the data cache to a second-level unified cache, then make
449 sure that stale data in the instruction cache is removed.
450 (In a multiprocessor system, the effect is more complex.)
451 Most of the PLT shouldn't be in the instruction cache, but
452 there may be a little overlap at the start and the end.
454 Assumes that dcbst and icbi apply to lines of 16 bytes or
455 more. Current known line sizes are 16, 32, and 128 bytes. */
457 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
465 /* Change the PLT entry whose reloc is 'reloc' to call the actual
467 static inline Elf64_Addr
468 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
469 const Elf64_Rela *reloc,
470 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
472 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
473 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
474 Elf64_Addr offset = 0;
476 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
480 /* If the opd entry is not yet relocated (because it's from a shared
481 object that hasn't been processed yet), then manually reloc it. */
482 if (map != sym_map && !sym_map->l_relocated
483 #if !defined RTLD_BOOTSTRAP && defined SHARED
484 /* Bootstrap map doesn't have l_relocated set for it. */
485 && sym_map != &GL(dl_rtld_map)
488 offset = sym_map->l_addr;
490 /* For PPC64, fixup_plt copies the function descriptor from opd
491 over the corresponding PLT entry.
492 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
493 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
494 so for thread safety we write them before changing fd_func. */
496 plt->fd_aux = rel->fd_aux + offset;
497 plt->fd_toc = rel->fd_toc + offset;
498 PPC_DCBST (&plt->fd_aux);
499 PPC_DCBST (&plt->fd_toc);
502 plt->fd_func = rel->fd_func + offset;
503 PPC_DCBST (&plt->fd_func);
509 /* Return the final value of a plt relocation. */
510 static inline Elf64_Addr
511 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
514 return value + reloc->r_addend;
517 #endif /* dl_machine_h */
521 #define PPC_LO(v) ((v) & 0xffff)
522 #define PPC_HI(v) (((v) >> 16) & 0xffff)
523 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
524 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
525 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
526 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
527 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
528 #define BIT_INSERT(var, val, mask) \
529 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
531 #define dont_expect(X) __builtin_expect ((X), 0)
533 extern void _dl_reloc_overflow (struct link_map *map,
535 Elf64_Addr *const reloc_addr,
536 const Elf64_Sym *sym,
537 const Elf64_Sym *refsym)
541 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
542 Elf64_Addr *const reloc_addr)
544 *reloc_addr = l_addr + reloc->r_addend;
547 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
548 /* This computes the value used by TPREL* relocs. */
549 static Elf64_Addr __attribute__ ((const))
550 elf_machine_tprel (struct link_map *map,
551 struct link_map *sym_map,
552 const Elf64_Sym *sym,
553 const Elf64_Rela *reloc)
555 # ifndef RTLD_BOOTSTRAP
558 CHECK_STATIC_TLS (map, sym_map);
560 return TLS_TPREL_VALUE (sym_map, sym, reloc);
561 # ifndef RTLD_BOOTSTRAP
568 /* Perform the relocation specified by RELOC and SYM (which is fully
569 resolved). MAP is the object containing the reloc. */
571 elf_machine_rela (struct link_map *map,
572 const Elf64_Rela *reloc,
573 const Elf64_Sym *sym,
574 const struct r_found_version *version,
575 Elf64_Addr *const reloc_addr)
577 const int r_type = ELF64_R_TYPE (reloc->r_info);
578 #ifndef RTLD_BOOTSTRAP
579 const Elf64_Sym *const refsym = sym;
582 if (r_type == R_PPC64_RELATIVE)
584 *reloc_addr = map->l_addr + reloc->r_addend;
588 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
591 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt. */
592 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
593 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
596 /* For relocs that don't edit code, return.
597 For relocs that might edit instructions, break from the switch. */
601 case R_PPC64_GLOB_DAT:
605 case R_PPC64_JMP_SLOT:
606 #ifdef RESOLVE_CONFLICT_FIND_MAP
607 RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
609 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
612 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
613 case R_PPC64_DTPMOD64:
614 # ifdef RTLD_BOOTSTRAP
615 /* During startup the dynamic linker is always index 1. */
618 /* Get the information from the link map returned by the
621 *reloc_addr = sym_map->l_tls_modid;
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 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
633 case R_PPC64_TPREL64:
634 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
637 case R_PPC64_TPREL16_LO_DS:
638 value = elf_machine_tprel (map, sym_map, sym, reloc);
639 if (dont_expect ((value & 3) != 0))
640 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS",
641 reloc_addr, sym, refsym);
642 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
646 case R_PPC64_TPREL16_DS:
647 value = elf_machine_tprel (map, sym_map, sym, reloc);
648 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
649 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr,
651 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
655 case R_PPC64_TPREL16:
656 value = elf_machine_tprel (map, sym_map, sym, reloc);
657 if (dont_expect ((value + 0x8000) >= 0x10000))
658 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr,
660 *(Elf64_Half *) reloc_addr = PPC_LO (value);
663 case R_PPC64_TPREL16_LO:
664 value = elf_machine_tprel (map, sym_map, sym, reloc);
665 *(Elf64_Half *) reloc_addr = PPC_LO (value);
668 case R_PPC64_TPREL16_HI:
669 value = elf_machine_tprel (map, sym_map, sym, reloc);
670 *(Elf64_Half *) reloc_addr = PPC_HI (value);
673 case R_PPC64_TPREL16_HA:
674 value = elf_machine_tprel (map, sym_map, sym, reloc);
675 *(Elf64_Half *) reloc_addr = PPC_HA (value);
678 case R_PPC64_TPREL16_HIGHER:
679 value = elf_machine_tprel (map, sym_map, sym, reloc);
680 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
683 case R_PPC64_TPREL16_HIGHEST:
684 value = elf_machine_tprel (map, sym_map, sym, reloc);
685 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
688 case R_PPC64_TPREL16_HIGHERA:
689 value = elf_machine_tprel (map, sym_map, sym, reloc);
690 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
693 case R_PPC64_TPREL16_HIGHESTA:
694 value = elf_machine_tprel (map, sym_map, sym, reloc);
695 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
697 #endif /* USE_TLS etc. */
699 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
700 case R_PPC64_ADDR16_LO_DS:
701 if (dont_expect ((value & 3) != 0))
702 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS",
703 reloc_addr, sym, refsym);
704 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
707 case R_PPC64_ADDR16_LO:
708 *(Elf64_Half *) reloc_addr = PPC_LO (value);
711 case R_PPC64_ADDR16_HI:
712 *(Elf64_Half *) reloc_addr = PPC_HI (value);
715 case R_PPC64_ADDR16_HA:
716 *(Elf64_Half *) reloc_addr = PPC_HA (value);
721 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
722 if (dont_expect ((delta + 0x80000000) >= 0x10000000
723 || (delta & 3) != 0))
724 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, sym, refsym);
725 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
730 if (dont_expect (sym == NULL))
731 /* This can happen in trace mode when an object could not be found. */
733 if (dont_expect (sym->st_size > refsym->st_size
734 || (GL(dl_verbose) && sym->st_size < refsym->st_size)))
738 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
739 _dl_error_printf ("%s: Symbol `%s' has different size" \
740 " in shared object," \
741 " consider re-linking\n",
742 _dl_argv[0] ?: "<program name unknown>",
743 strtab + refsym->st_name);
745 memcpy (reloc_addr, (char *) value, MIN (sym->st_size, refsym->st_size));
748 case R_PPC64_UADDR64:
749 /* We are big-endian. */
750 ((char *) reloc_addr)[0] = (value >> 56) & 0xff;
751 ((char *) reloc_addr)[1] = (value >> 48) & 0xff;
752 ((char *) reloc_addr)[2] = (value >> 40) & 0xff;
753 ((char *) reloc_addr)[3] = (value >> 32) & 0xff;
754 ((char *) reloc_addr)[4] = (value >> 24) & 0xff;
755 ((char *) reloc_addr)[5] = (value >> 16) & 0xff;
756 ((char *) reloc_addr)[6] = (value >> 8) & 0xff;
757 ((char *) reloc_addr)[7] = (value >> 0) & 0xff;
760 case R_PPC64_UADDR32:
761 /* We are big-endian. */
762 ((char *) reloc_addr)[0] = (value >> 24) & 0xff;
763 ((char *) reloc_addr)[1] = (value >> 16) & 0xff;
764 ((char *) reloc_addr)[2] = (value >> 8) & 0xff;
765 ((char *) reloc_addr)[3] = (value >> 0) & 0xff;
769 if (dont_expect ((value + 0x80000000) >= 0x10000000))
770 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, sym, refsym);
771 *(Elf64_Word *) reloc_addr = value;
775 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
776 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, sym, refsym);
777 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
781 if (dont_expect ((value + 0x8000) >= 0x10000))
782 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, sym, refsym);
783 *(Elf64_Half *) reloc_addr = value;
786 case R_PPC64_UADDR16:
787 if (dont_expect ((value + 0x8000) >= 0x10000))
788 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, sym, refsym);
789 /* We are big-endian. */
790 ((char *) reloc_addr)[0] = (value >> 8) & 0xff;
791 ((char *) reloc_addr)[1] = (value >> 0) & 0xff;
794 case R_PPC64_ADDR16_DS:
795 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
796 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, sym, refsym);
797 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
800 case R_PPC64_ADDR16_HIGHER:
801 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
804 case R_PPC64_ADDR16_HIGHEST:
805 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
808 case R_PPC64_ADDR16_HIGHERA:
809 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
812 case R_PPC64_ADDR16_HIGHESTA:
813 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
817 case R_PPC64_ADDR14_BRTAKEN:
818 case R_PPC64_ADDR14_BRNTAKEN:
820 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
821 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, sym, refsym);
822 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
823 BIT_INSERT (insn, value, 0xfffc);
824 if (r_type != R_PPC64_ADDR14)
827 if (r_type == R_PPC64_ADDR14_BRTAKEN)
829 if ((insn & (0x14 << 21)) == (0x04 << 21))
831 else if ((insn & (0x14 << 21)) == (0x10 << 21))
834 *(Elf64_Word *) reloc_addr = insn;
839 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
843 *reloc_addr = value - (Elf64_Addr) reloc_addr;
845 #endif /* !RTLD_BOOTSTRAP */
848 _dl_reloc_bad_type (map, r_type, 0);
851 MODIFIED_CODE_NOQUEUE (reloc_addr);
855 elf_machine_lazy_rel (struct link_map *map,
856 Elf64_Addr l_addr, const Elf64_Rela *reloc)
858 /* elf_machine_runtime_setup handles this. */