1 /* Machine-dependent ELF dynamic relocation inline functions.
3 Copyright 1995-2005, 2006, 2008 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 not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
24 #define ELF_MACHINE_NAME "powerpc64"
27 #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
110 #ifdef HAVE_INLINED_SYSCALLS
111 /* We do not need _dl_starting_up. */
112 # define DL_STARTING_UP_DEF
114 # define DL_STARTING_UP_DEF \
115 ".LC__dl_starting_up:\n" \
116 " .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n"
120 /* Initial entry point code for the dynamic linker. The C function
121 `_dl_start' is the real entry point; its return value is the user
122 program's entry point. */
124 asm (".pushsection \".text\"\n" \
126 " .type " BODY_PREFIX "_start,@function\n" \
127 " .pushsection \".opd\",\"aw\"\n" \
130 " " ENTRY_2(_start) "\n" \
132 " " OPD_ENT(_start) "\n" \
134 BODY_PREFIX "_start:\n" \
135 /* We start with the following on the stack, from top: \
137 arguments for program (terminated by NULL); \
138 environment variables (terminated by NULL); \
139 arguments for the program loader. */ \
142 " stdu 4,-128(1)\n" \
143 /* Call _dl_start with one parameter pointing at argc. */ \
144 " bl " DOT_PREFIX "_dl_start\n" \
146 /* Transfer control to _dl_start_user! */ \
147 " b " DOT_PREFIX "_dl_start_user\n" \
150 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
151 " .long .LT__start-" BODY_PREFIX "_start\n" \
152 " .short .LT__start_name_end-.LT__start_name_start\n" \
153 ".LT__start_name_start:\n" \
154 " .ascii \"_start\"\n" \
155 ".LT__start_name_end:\n" \
157 " " END_2(_start) "\n" \
158 " .globl _dl_start_user\n" \
159 " .pushsection \".opd\",\"aw\"\n" \
160 "_dl_start_user:\n" \
161 " " OPD_ENT(_dl_start_user) "\n" \
163 " .pushsection \".toc\",\"aw\"\n" \
165 ".LC__rtld_global:\n" \
166 " .tc _rtld_global[TC],_rtld_global\n" \
168 " .tc _dl_argc[TC],_dl_argc\n" \
170 " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
172 " .tc _dl_fini[TC],_dl_fini\n" \
174 " .type " BODY_PREFIX "_dl_start_user,@function\n" \
175 " " ENTRY_2(_dl_start_user) "\n" \
176 /* Now, we do our main work of calling initialisation procedures. \
177 The ELF ABI doesn't say anything about parameters for these, \
178 so we just pass argc, argv, and the environment. \
179 Changing these is strongly discouraged (not least because argc is \
180 passed by value!). */ \
181 BODY_PREFIX "_dl_start_user:\n" \
182 /* the address of _start in r30. */ \
184 /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
185 " ld 28,.LC__rtld_global@toc(2)\n" \
186 " ld 29,.LC__dl_argc@toc(2)\n" \
187 " ld 27,.LC__dl_argv@toc(2)\n" \
188 /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \
195 " bl " DOT_PREFIX "_dl_init\n" \
197 /* Now, to conform to the ELF ABI, we have to: \
198 Pass argc (actually _dl_argc) in r3; */ \
200 /* Pass argv (actually _dl_argv) in r4; */ \
202 /* Pass argv+argc+1 in r5; */ \
206 /* Pass the auxilary vector in r6. This is passed to us just after \
212 /* Pass a termination function pointer (in this case _dl_fini) in \
214 " ld 7,.LC__dl_fini@toc(2)\n" \
215 /* Pass the stack pointer in r1 (so far so good), pointing to a NULL \
216 value. This lets our startup code distinguish between a program \
217 linked statically, which linux will call with argc on top of the \
218 stack which will hopefully never be zero, and a dynamically linked \
219 program which will always have a NULL on the top of the stack. \
220 Take the opportunity to clear LR, so anyone who accidentally \
221 returns from _start gets SEGV. Also clear the next few words of \
229 /* Now, call the start function descriptor at r30... */ \
230 " .globl ._dl_main_dispatch\n" \
231 "._dl_main_dispatch:\n" \
237 ".LT__dl_start_user:\n" \
239 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
240 " .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n" \
241 " .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
242 ".LT__dl_start_user_name_start:\n" \
243 " .ascii \"_dl_start_user\"\n" \
244 ".LT__dl_start_user_name_end:\n" \
246 " " END_2(_dl_start_user) "\n" \
249 /* ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to
250 one of the main executable's symbols, as for a COPY reloc.
252 To make function pointer comparisons work on most targets, the
253 relevant ABI states that the address of a non-local function in a
254 dynamically linked executable is the address of the PLT entry for
255 that function. This is quite reasonable since using the real
256 function address in a non-PIC executable would typically require
257 dynamic relocations in .text, something to be avoided. For such
258 functions, the linker emits a SHN_UNDEF symbol in the executable
259 with value equal to the PLT entry address. Normally, SHN_UNDEF
260 symbols have a value of zero, so this is a clue to ld.so that it
261 should treat these symbols specially. For relocations not in
262 ELF_RTYPE_CLASS_PLT (eg. those on function pointers), ld.so should
263 use the value of the executable SHN_UNDEF symbol, ie. the PLT entry
264 address. For relocations in ELF_RTYPE_CLASS_PLT (eg. the relocs in
265 the PLT itself), ld.so should use the value of the corresponding
266 defined symbol in the object that defines the function, ie. the
267 real function address. This complicates ld.so in that there are
268 now two possible values for a given symbol, and it gets even worse
269 because protected symbols need yet another set of rules.
271 On PowerPC64 we don't need any of this. The linker won't emit
272 SHN_UNDEF symbols with non-zero values. ld.so can make all
273 relocations behave "normally", ie. always use the real address
274 like PLT relocations. So always set ELF_RTYPE_CLASS_PLT. */
276 #define elf_machine_type_class(type) \
277 (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
279 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
280 #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
282 /* The PowerPC never uses REL relocations. */
283 #define ELF_MACHINE_NO_REL 1
285 /* Stuff for the PLT. */
286 #define PLT_INITIAL_ENTRY_WORDS 3
287 #define GLINK_INITIAL_ENTRY_WORDS 8
289 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
290 #define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
291 #define PPC_DCBF(where) asm volatile ("dcbf 0,%0" : : "r"(where) : "memory")
292 #define PPC_SYNC asm volatile ("sync" : : : "memory")
293 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
294 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
295 #define PPC_DIE asm volatile ("tweq 0,0")
296 /* Use this when you've modified some code, but it won't be in the
297 instruction fetch queue (or when it doesn't matter if it is). */
298 #define MODIFIED_CODE_NOQUEUE(where) \
299 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
300 /* Use this when it might be in the instruction queue. */
301 #define MODIFIED_CODE(where) \
302 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
304 /* Set up the loaded object described by MAP so its unrelocated PLT
305 entries will jump to the on-demand fixup code in dl-runtime.c. */
306 static inline int __attribute__ ((always_inline
))
307 elf_machine_runtime_setup (struct link_map
*map
, int lazy
, int profile
)
309 if (map
->l_info
[DT_JMPREL
])
312 Elf64_Word
*glink
= NULL
;
313 Elf64_Xword
*plt
= (Elf64_Xword
*) D_PTR (map
, l_info
[DT_PLTGOT
]);
314 Elf64_Word num_plt_entries
= (map
->l_info
[DT_PLTRELSZ
]->d_un
.d_val
315 / sizeof (Elf64_Rela
));
316 Elf64_Addr l_addr
= map
->l_addr
;
317 Elf64_Dyn
**info
= map
->l_info
;
320 extern void _dl_runtime_resolve (void);
321 extern void _dl_profile_resolve (void);
323 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
324 elf_get_dynamic_info takes care of the standard entries but
325 doesn't know exactly what to do with processor specific
327 if (info
[DT_PPC64(GLINK
)] != NULL
)
328 info
[DT_PPC64(GLINK
)]->d_un
.d_ptr
+= l_addr
;
332 /* The function descriptor of the appropriate trampline
333 routine is used to set the 1st and 2nd doubleword of the
335 Elf64_FuncDesc
*resolve_fd
;
336 Elf64_Word glink_offset
;
337 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
338 Elf64_FuncDesc
*plt_reserve
= (Elf64_FuncDesc
*) plt
;
341 resolve_fd
= (Elf64_FuncDesc
*) (profile
? _dl_profile_resolve
342 : _dl_runtime_resolve
);
343 if (profile
&& GLRO(dl_profile
) != NULL
344 && _dl_name_match_p (GLRO(dl_profile
), map
))
345 /* This is the object we are looking for. Say that we really
346 want profiling and the timers are started. */
347 GL(dl_profile_map
) = map
;
350 /* We need to stuff the address/TOC of _dl_runtime_resolve
351 into doublewords 0 and 1 of plt_reserve. Then we need to
352 stuff the map address into doubleword 2 of plt_reserve.
353 This allows the GLINK0 code to transfer control to the
354 correct trampoline which will transfer control to fixup
356 plt_reserve
->fd_func
= resolve_fd
->fd_func
;
357 plt_reserve
->fd_toc
= resolve_fd
->fd_toc
;
358 plt_reserve
->fd_aux
= (Elf64_Addr
) map
;
359 #ifdef RTLD_BOOTSTRAP
360 /* When we're bootstrapping, the opd entry will not have
361 been relocated yet. */
362 plt_reserve
->fd_func
+= l_addr
;
363 plt_reserve
->fd_toc
+= l_addr
;
366 /* Set up the lazy PLT entries. */
367 glink
= (Elf64_Word
*) D_PTR (map
, l_info
[DT_PPC64(GLINK
)]);
368 offset
= PLT_INITIAL_ENTRY_WORDS
;
369 glink_offset
= GLINK_INITIAL_ENTRY_WORDS
;
370 for (i
= 0; i
< num_plt_entries
; i
++)
373 plt
[offset
] = (Elf64_Xword
) &glink
[glink_offset
];
375 /* The first 32k entries of glink can set an index and
376 branch using two instructions; Past that point,
377 glink uses three instructions. */
384 /* Now, we've modified data. We need to write the changes from
385 the data cache to a second-level unified cache, then make
386 sure that stale data in the instruction cache is removed.
387 (In a multiprocessor system, the effect is more complex.)
388 Most of the PLT shouldn't be in the instruction cache, but
389 there may be a little overlap at the start and the end.
391 Assumes that dcbst and icbi apply to lines of 16 bytes or
392 more. Current known line sizes are 16, 32, and 128 bytes. */
394 for (p
= (char *) plt
; p
< (char *) &plt
[offset
]; p
+= 16)
402 /* Change the PLT entry whose reloc is 'reloc' to call the actual
404 static inline Elf64_Addr
__attribute__ ((always_inline
))
405 elf_machine_fixup_plt (struct link_map
*map
, lookup_t sym_map
,
406 const Elf64_Rela
*reloc
,
407 Elf64_Addr
*reloc_addr
, Elf64_Addr finaladdr
)
409 Elf64_FuncDesc
*plt
= (Elf64_FuncDesc
*) reloc_addr
;
410 Elf64_FuncDesc
*rel
= (Elf64_FuncDesc
*) finaladdr
;
411 Elf64_Addr offset
= 0;
413 PPC_DCBT (&plt
->fd_aux
);
414 PPC_DCBT (&plt
->fd_func
);
415 PPC_DCBT (&rel
->fd_aux
);
416 PPC_DCBT (&rel
->fd_func
);
418 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
422 /* If the opd entry is not yet relocated (because it's from a shared
423 object that hasn't been processed yet), then manually reloc it. */
424 if (map
!= sym_map
&& !sym_map
->l_relocated
425 #if !defined RTLD_BOOTSTRAP && defined SHARED
426 /* Bootstrap map doesn't have l_relocated set for it. */
427 && sym_map
!= &GL(dl_rtld_map
)
430 offset
= sym_map
->l_addr
;
432 /* For PPC64, fixup_plt copies the function descriptor from opd
433 over the corresponding PLT entry.
434 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
435 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
436 so for thread safety we write them before changing fd_func. */
438 plt
->fd_aux
= rel
->fd_aux
+ offset
;
439 plt
->fd_toc
= rel
->fd_toc
+ offset
;
440 PPC_DCBF (&plt
->fd_toc
);
443 plt
->fd_func
= rel
->fd_func
+ offset
;
444 PPC_DCBST (&plt
->fd_func
);
450 static inline void __attribute__ ((always_inline
))
451 elf_machine_plt_conflict (Elf64_Addr
*reloc_addr
, Elf64_Addr finaladdr
)
453 Elf64_FuncDesc
*plt
= (Elf64_FuncDesc
*) reloc_addr
;
454 Elf64_FuncDesc
*rel
= (Elf64_FuncDesc
*) finaladdr
;
456 plt
->fd_func
= rel
->fd_func
;
457 plt
->fd_aux
= rel
->fd_aux
;
458 plt
->fd_toc
= rel
->fd_toc
;
459 PPC_DCBST (&plt
->fd_func
);
460 PPC_DCBST (&plt
->fd_aux
);
461 PPC_DCBST (&plt
->fd_toc
);
465 /* Return the final value of a plt relocation. */
466 static inline Elf64_Addr
467 elf_machine_plt_value (struct link_map
*map
, const Elf64_Rela
*reloc
,
470 return value
+ reloc
->r_addend
;
474 /* Names of the architecture-specific auditing callback functions. */
475 #define ARCH_LA_PLTENTER ppc64_gnu_pltenter
476 #define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
478 #endif /* dl_machine_h */
482 #define PPC_LO(v) ((v) & 0xffff)
483 #define PPC_HI(v) (((v) >> 16) & 0xffff)
484 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
485 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
486 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
487 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
488 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
489 #define BIT_INSERT(var, val, mask) \
490 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
492 #define dont_expect(X) __builtin_expect ((X), 0)
494 extern void _dl_reloc_overflow (struct link_map
*map
,
496 Elf64_Addr
*const reloc_addr
,
497 const Elf64_Sym
*refsym
)
500 auto inline void __attribute__ ((always_inline
))
501 elf_machine_rela_relative (Elf64_Addr l_addr
, const Elf64_Rela
*reloc
,
502 void *const reloc_addr_arg
)
504 Elf64_Addr
*const reloc_addr
= reloc_addr_arg
;
505 *reloc_addr
= l_addr
+ reloc
->r_addend
;
508 #if !defined RTLD_BOOTSTRAP || USE___THREAD
509 /* This computes the value used by TPREL* relocs. */
510 auto inline Elf64_Addr
__attribute__ ((always_inline
, const))
511 elf_machine_tprel (struct link_map
*map
,
512 struct link_map
*sym_map
,
513 const Elf64_Sym
*sym
,
514 const Elf64_Rela
*reloc
)
516 # ifndef RTLD_BOOTSTRAP
519 CHECK_STATIC_TLS (map
, sym_map
);
521 return TLS_TPREL_VALUE (sym_map
, sym
, reloc
);
522 # ifndef RTLD_BOOTSTRAP
529 /* Call function at address VALUE (an OPD entry) to resolve ifunc relocs. */
530 auto inline Elf64_Addr
__attribute__ ((always_inline
))
531 resolve_ifunc (Elf64_Addr value
,
532 const struct link_map
*map
, const struct link_map
*sym_map
)
534 #ifndef RESOLVE_CONFLICT_FIND_MAP
535 /* The function we are calling may not yet have its opd entry relocated. */
538 # if !defined RTLD_BOOTSTRAP && defined SHARED
539 /* Bootstrap map doesn't have l_relocated set for it. */
540 && sym_map
!= &GL(dl_rtld_map
)
542 && !sym_map
->l_relocated
)
544 Elf64_FuncDesc
*func
= (Elf64_FuncDesc
*) value
;
545 opd
.fd_func
= func
->fd_func
+ sym_map
->l_addr
;
546 opd
.fd_toc
= func
->fd_toc
+ sym_map
->l_addr
;
547 opd
.fd_aux
= func
->fd_aux
;
548 value
= (Elf64_Addr
) &opd
;
551 return ((Elf64_Addr (*) (void)) value
) ();
554 /* Perform the relocation specified by RELOC and SYM (which is fully
555 resolved). MAP is the object containing the reloc. */
556 auto inline void __attribute__ ((always_inline
))
557 elf_machine_rela (struct link_map
*map
,
558 const Elf64_Rela
*reloc
,
559 const Elf64_Sym
*sym
,
560 const struct r_found_version
*version
,
561 void *const reloc_addr_arg
)
563 Elf64_Addr
*const reloc_addr
= reloc_addr_arg
;
564 const int r_type
= ELF64_R_TYPE (reloc
->r_info
);
565 #ifndef RTLD_BOOTSTRAP
566 const Elf64_Sym
*const refsym
= sym
;
569 if (r_type
== R_PPC64_RELATIVE
)
571 *reloc_addr
= map
->l_addr
+ reloc
->r_addend
;
575 if (__builtin_expect (r_type
== R_PPC64_NONE
, 0))
578 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
579 and STT_GNU_IFUNC. */
580 struct link_map
*sym_map
= RESOLVE_MAP (&sym
, version
, r_type
);
581 Elf64_Addr value
= ((sym_map
== NULL
? 0 : sym_map
->l_addr
+ sym
->st_value
)
585 && __builtin_expect (ELFW(ST_TYPE
) (sym
->st_info
) == STT_GNU_IFUNC
, 0)
586 && __builtin_expect (sym
->st_shndx
!= SHN_UNDEF
, 1))
587 value
= resolve_ifunc (value
, map
, sym_map
);
589 /* For relocs that don't edit code, return.
590 For relocs that might edit instructions, break from the switch. */
594 case R_PPC64_GLOB_DAT
:
598 case R_PPC64_IRELATIVE
:
599 value
= resolve_ifunc (value
, map
, sym_map
);
603 case R_PPC64_JMP_IREL
:
604 value
= resolve_ifunc (value
, map
, sym_map
);
606 case R_PPC64_JMP_SLOT
:
607 #ifdef RESOLVE_CONFLICT_FIND_MAP
608 elf_machine_plt_conflict (reloc_addr
, value
);
610 elf_machine_fixup_plt (map
, sym_map
, reloc
, reloc_addr
, value
);
614 #if !defined RTLD_BOOTSTRAP || USE___THREAD
615 case R_PPC64_DTPMOD64
:
616 # ifdef RTLD_BOOTSTRAP
617 /* During startup the dynamic linker is always index 1. */
620 /* Get the information from the link map returned by the
623 *reloc_addr
= sym_map
->l_tls_modid
;
627 case R_PPC64_DTPREL64
:
628 /* During relocation all TLS symbols are defined and used.
629 Therefore the offset is already correct. */
630 # ifndef RTLD_BOOTSTRAP
632 *reloc_addr
= TLS_DTPREL_VALUE (sym
, reloc
);
636 case R_PPC64_TPREL64
:
637 *reloc_addr
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
640 case R_PPC64_TPREL16_LO_DS
:
641 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
642 if (dont_expect ((value
& 3) != 0))
643 _dl_reloc_overflow (map
, "R_PPC64_TPREL16_LO_DS", reloc_addr
, refsym
);
644 *(Elf64_Half
*) reloc_addr
= BIT_INSERT (*(Elf64_Half
*) reloc_addr
,
648 case R_PPC64_TPREL16_DS
:
649 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
650 if (dont_expect ((value
+ 0x8000) >= 0x10000 || (value
& 3) != 0))
651 _dl_reloc_overflow (map
, "R_PPC64_TPREL16_DS", reloc_addr
, refsym
);
652 *(Elf64_Half
*) reloc_addr
= BIT_INSERT (*(Elf64_Half
*) reloc_addr
,
656 case R_PPC64_TPREL16
:
657 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
658 if (dont_expect ((value
+ 0x8000) >= 0x10000))
659 _dl_reloc_overflow (map
, "R_PPC64_TPREL16", reloc_addr
, refsym
);
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
);
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", reloc_addr
, refsym
);
703 BIT_INSERT (*(Elf64_Half
*) reloc_addr
, value
, 0xfffc);
706 case R_PPC64_ADDR16_LO
:
707 *(Elf64_Half
*) reloc_addr
= PPC_LO (value
);
710 case R_PPC64_ADDR16_HI
:
711 *(Elf64_Half
*) reloc_addr
= PPC_HI (value
);
714 case R_PPC64_ADDR16_HA
:
715 *(Elf64_Half
*) reloc_addr
= PPC_HA (value
);
720 Elf64_Addr delta
= value
- (Elf64_Xword
) reloc_addr
;
721 if (dont_expect ((delta
+ 0x80000000) >= 0x10000000
722 || (delta
& 3) != 0))
723 _dl_reloc_overflow (map
, "R_PPC64_ADDR30", reloc_addr
, refsym
);
724 BIT_INSERT (*(Elf64_Word
*) reloc_addr
, delta
, 0xfffffffc);
729 if (dont_expect (sym
== NULL
))
730 /* This can happen in trace mode when an object could not be found. */
732 if (dont_expect (sym
->st_size
> refsym
->st_size
734 && 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_arg
, (char *) value
,
746 MIN (sym
->st_size
, refsym
->st_size
));
749 case R_PPC64_UADDR64
:
750 /* We are big-endian. */
751 ((char *) reloc_addr_arg
)[0] = (value
>> 56) & 0xff;
752 ((char *) reloc_addr_arg
)[1] = (value
>> 48) & 0xff;
753 ((char *) reloc_addr_arg
)[2] = (value
>> 40) & 0xff;
754 ((char *) reloc_addr_arg
)[3] = (value
>> 32) & 0xff;
755 ((char *) reloc_addr_arg
)[4] = (value
>> 24) & 0xff;
756 ((char *) reloc_addr_arg
)[5] = (value
>> 16) & 0xff;
757 ((char *) reloc_addr_arg
)[6] = (value
>> 8) & 0xff;
758 ((char *) reloc_addr_arg
)[7] = (value
>> 0) & 0xff;
761 case R_PPC64_UADDR32
:
762 /* We are big-endian. */
763 ((char *) reloc_addr_arg
)[0] = (value
>> 24) & 0xff;
764 ((char *) reloc_addr_arg
)[1] = (value
>> 16) & 0xff;
765 ((char *) reloc_addr_arg
)[2] = (value
>> 8) & 0xff;
766 ((char *) reloc_addr_arg
)[3] = (value
>> 0) & 0xff;
770 if (dont_expect ((value
+ 0x80000000) >= 0x10000000))
771 _dl_reloc_overflow (map
, "R_PPC64_ADDR32", reloc_addr
, refsym
);
772 *(Elf64_Word
*) reloc_addr
= value
;
776 if (dont_expect ((value
+ 0x2000000) >= 0x4000000 || (value
& 3) != 0))
777 _dl_reloc_overflow (map
, "R_PPC64_ADDR24", reloc_addr
, refsym
);
778 BIT_INSERT (*(Elf64_Word
*) reloc_addr
, value
, 0x3fffffc);
782 if (dont_expect ((value
+ 0x8000) >= 0x10000))
783 _dl_reloc_overflow (map
, "R_PPC64_ADDR16", reloc_addr
, refsym
);
784 *(Elf64_Half
*) reloc_addr
= value
;
787 case R_PPC64_UADDR16
:
788 if (dont_expect ((value
+ 0x8000) >= 0x10000))
789 _dl_reloc_overflow (map
, "R_PPC64_UADDR16", reloc_addr
, refsym
);
790 /* We are big-endian. */
791 ((char *) reloc_addr_arg
)[0] = (value
>> 8) & 0xff;
792 ((char *) reloc_addr_arg
)[1] = (value
>> 0) & 0xff;
795 case R_PPC64_ADDR16_DS
:
796 if (dont_expect ((value
+ 0x8000) >= 0x10000 || (value
& 3) != 0))
797 _dl_reloc_overflow (map
, "R_PPC64_ADDR16_DS", reloc_addr
, refsym
);
798 BIT_INSERT (*(Elf64_Half
*) reloc_addr
, value
, 0xfffc);
801 case R_PPC64_ADDR16_HIGHER
:
802 *(Elf64_Half
*) reloc_addr
= PPC_HIGHER (value
);
805 case R_PPC64_ADDR16_HIGHEST
:
806 *(Elf64_Half
*) reloc_addr
= PPC_HIGHEST (value
);
809 case R_PPC64_ADDR16_HIGHERA
:
810 *(Elf64_Half
*) reloc_addr
= PPC_HIGHERA (value
);
813 case R_PPC64_ADDR16_HIGHESTA
:
814 *(Elf64_Half
*) reloc_addr
= PPC_HIGHESTA (value
);
818 case R_PPC64_ADDR14_BRTAKEN
:
819 case R_PPC64_ADDR14_BRNTAKEN
:
821 if (dont_expect ((value
+ 0x8000) >= 0x10000 || (value
& 3) != 0))
822 _dl_reloc_overflow (map
, "R_PPC64_ADDR14", reloc_addr
, refsym
);
823 Elf64_Word insn
= *(Elf64_Word
*) reloc_addr
;
824 BIT_INSERT (insn
, value
, 0xfffc);
825 if (r_type
!= R_PPC64_ADDR14
)
828 if (r_type
== R_PPC64_ADDR14_BRTAKEN
)
830 if ((insn
& (0x14 << 21)) == (0x04 << 21))
832 else if ((insn
& (0x14 << 21)) == (0x10 << 21))
835 *(Elf64_Word
*) reloc_addr
= insn
;
840 *(Elf64_Word
*) reloc_addr
= value
- (Elf64_Addr
) reloc_addr
;
844 *reloc_addr
= value
- (Elf64_Addr
) reloc_addr
;
846 #endif /* !RTLD_BOOTSTRAP */
849 _dl_reloc_bad_type (map
, r_type
, 0);
852 MODIFIED_CODE_NOQUEUE (reloc_addr
);
855 auto inline void __attribute__ ((always_inline
))
856 elf_machine_lazy_rel (struct link_map
*map
,
857 Elf64_Addr l_addr
, const Elf64_Rela
*reloc
)
859 /* elf_machine_runtime_setup handles this. */