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 " .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" \
248 " .tc _dl_argc[TC],_dl_argc\n" \
250 " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
252 " .tc _dl_fini[TC],_dl_fini\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. */ \
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). */ \
277 /* Now, to conform to the ELF ABI, we have to: \
278 Pass argc (actually _dl_argc) in r3; */ \
280 /* Pass argv (actually _dl_argv) in r4; */ \
282 /* Pass argv+argc+1 in r5; */ \
286 /* Pass the auxilary vector in r6. This is passed to us just after \
292 /* Pass a termination function pointer (in this case _dl_fini) in \
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 \
310 /* Clear _dl_starting_up. */ \
312 /* Now, call the start function descriptor at r30... */ \
313 " .globl ._dl_main_dispatch\n" \
314 "._dl_main_dispatch:\n" \
320 ".LT__dl_start_user:\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" \
329 " .size ._dl_start_user,.-._dl_start_user\n" \
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))
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))
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. */
383 elf_machine_runtime_setup (struct link_map
*map
, int lazy
, int profile
)
385 if (map
->l_info
[DT_JMPREL
])
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
;
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
403 if (info
[DT_PPC64(GLINK
)] != NULL
)
404 info
[DT_PPC64(GLINK
)]->d_un
.d_ptr
+= l_addr
;
408 /* The function descriptor of the appropriate trampline
409 routine is used to set the 1st and 2nd doubleword of the
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
;
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
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
;
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
];
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. */
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)
477 /* Change the PLT entry whose reloc is 'reloc' to call the actual
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. */
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
)
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
);
514 plt
->fd_func
= rel
->fd_func
+ offset
;
515 PPC_DCBST (&plt
->fd_func
);
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
);
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
,
541 return value
+ reloc
->r_addend
;
544 #endif /* dl_machine_h */
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
,
562 Elf64_Addr
*const reloc_addr
,
563 const Elf64_Sym
*refsym
)
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
585 CHECK_STATIC_TLS (map
, sym_map
);
587 return TLS_TPREL_VALUE (sym_map
, sym
, reloc
);
588 # ifndef RTLD_BOOTSTRAP
595 /* Perform the relocation specified by RELOC and SYM (which is fully
596 resolved). MAP is the object containing the reloc. */
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
;
610 if (r_type
== R_PPC64_RELATIVE
)
612 *reloc_addr
= map
->l_addr
+ reloc
->r_addend
;
616 if (__builtin_expect (r_type
== R_PPC64_NONE
, 0))
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
)
624 /* For relocs that don't edit code, return.
625 For relocs that might edit instructions, break from the switch. */
629 case R_PPC64_GLOB_DAT
:
633 case R_PPC64_JMP_SLOT
:
634 #ifdef RESOLVE_CONFLICT_FIND_MAP
635 elf_machine_plt_conflict (reloc_addr
, value
);
637 elf_machine_fixup_plt (map
, sym_map
, reloc
, reloc_addr
, value
);
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. */
647 /* Get the information from the link map returned by the
650 *reloc_addr
= sym_map
->l_tls_modid
;
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
659 *reloc_addr
= TLS_DTPREL_VALUE (sym
, reloc
);
663 case R_PPC64_TPREL64
:
664 *reloc_addr
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
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
,
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
,
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
);
690 case R_PPC64_TPREL16_LO
:
691 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
692 *(Elf64_Half
*) reloc_addr
= PPC_LO (value
);
695 case R_PPC64_TPREL16_HI
:
696 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
697 *(Elf64_Half
*) reloc_addr
= PPC_HI (value
);
700 case R_PPC64_TPREL16_HA
:
701 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
702 *(Elf64_Half
*) reloc_addr
= PPC_HA (value
);
705 case R_PPC64_TPREL16_HIGHER
:
706 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
707 *(Elf64_Half
*) reloc_addr
= PPC_HIGHER (value
);
710 case R_PPC64_TPREL16_HIGHEST
:
711 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
712 *(Elf64_Half
*) reloc_addr
= PPC_HIGHEST (value
);
715 case R_PPC64_TPREL16_HIGHERA
:
716 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
717 *(Elf64_Half
*) reloc_addr
= PPC_HIGHERA (value
);
720 case R_PPC64_TPREL16_HIGHESTA
:
721 value
= elf_machine_tprel (map
, sym_map
, sym
, reloc
);
722 *(Elf64_Half
*) reloc_addr
= PPC_HIGHESTA (value
);
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);
733 case R_PPC64_ADDR16_LO
:
734 *(Elf64_Half
*) reloc_addr
= PPC_LO (value
);
737 case R_PPC64_ADDR16_HI
:
738 *(Elf64_Half
*) reloc_addr
= PPC_HI (value
);
741 case R_PPC64_ADDR16_HA
:
742 *(Elf64_Half
*) reloc_addr
= PPC_HA (value
);
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);
756 if (dont_expect (sym
== NULL
))
757 /* This can happen in trace mode when an object could not be found. */
759 if (dont_expect (sym
->st_size
> refsym
->st_size
760 || (GL(dl_verbose
) && sym
->st_size
< refsym
->st_size
)))
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
));
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;
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;
796 if (dont_expect ((value
+ 0x80000000) >= 0x10000000))
797 _dl_reloc_overflow (map
, "R_PPC64_ADDR32", reloc_addr
, refsym
);
798 *(Elf64_Word
*) reloc_addr
= value
;
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);
808 if (dont_expect ((value
+ 0x8000) >= 0x10000))
809 _dl_reloc_overflow (map
, "R_PPC64_ADDR16", reloc_addr
, refsym
);
810 *(Elf64_Half
*) reloc_addr
= value
;
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;
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);
827 case R_PPC64_ADDR16_HIGHER
:
828 *(Elf64_Half
*) reloc_addr
= PPC_HIGHER (value
);
831 case R_PPC64_ADDR16_HIGHEST
:
832 *(Elf64_Half
*) reloc_addr
= PPC_HIGHEST (value
);
835 case R_PPC64_ADDR16_HIGHERA
:
836 *(Elf64_Half
*) reloc_addr
= PPC_HIGHERA (value
);
839 case R_PPC64_ADDR16_HIGHESTA
:
840 *(Elf64_Half
*) reloc_addr
= PPC_HIGHESTA (value
);
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
)
854 if (r_type
== R_PPC64_ADDR14_BRTAKEN
)
856 if ((insn
& (0x14 << 21)) == (0x04 << 21))
858 else if ((insn
& (0x14 << 21)) == (0x10 << 21))
861 *(Elf64_Word
*) reloc_addr
= insn
;
866 *(Elf64_Word
*) reloc_addr
= value
- (Elf64_Addr
) reloc_addr
;
870 *reloc_addr
= value
- (Elf64_Addr
) reloc_addr
;
872 #endif /* !RTLD_BOOTSTRAP */
875 _dl_reloc_bad_type (map
, r_type
, 0);
878 MODIFIED_CODE_NOQUEUE (reloc_addr
);
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. */