Updated to fedora-glibc-20080410T1907
[glibc/history.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
blobc837393d796524d66f9e67e414e8cfcc61d8b061
1 /* Machine-dependent ELF dynamic relocation inline functions.
2 PowerPC64 version.
3 Copyright 1995-2005, 2006 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. */
21 #ifndef dl_machine_h
22 #define dl_machine_h
24 #define ELF_MACHINE_NAME "powerpc64"
26 #include <assert.h>
27 #include <sys/param.h>
28 #include <dl-tls.h>
29 #include <sysdep.h>
31 /* Translate a processor specific dynamic tag to the index
32 in l_info array. */
33 #define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
35 /* A PowerPC64 function descriptor. The .plt (procedure linkage
36 table) and .opd (official procedure descriptor) sections are
37 arrays of these. */
38 typedef struct
40 Elf64_Addr fd_func;
41 Elf64_Addr fd_toc;
42 Elf64_Addr fd_aux;
43 } Elf64_FuncDesc;
45 #define ELF_MULT_MACHINES_SUPPORTED
47 /* Return nonzero iff ELF header is compatible with the running host. */
48 static inline int
49 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
51 return ehdr->e_machine == EM_PPC64;
54 /* Return nonzero iff ELF header is compatible with the running host,
55 but not this loader. */
56 static inline int
57 elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
59 return ehdr->e_machine == EM_PPC;
62 /* Return nonzero iff ELF header is compatible with the running host,
63 but not this loader. */
64 static inline int
65 elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
67 return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
71 /* Return the run-time load address of the shared object, assuming it
72 was originally linked at zero. */
73 static inline Elf64_Addr
74 elf_machine_load_address (void) __attribute__ ((const));
76 static inline Elf64_Addr
77 elf_machine_load_address (void)
79 Elf64_Addr ret;
81 /* The first entry in .got (and thus the first entry in .toc) is the
82 link-time TOC_base, ie. r2. So the difference between that and
83 the current r2 set by the kernel is how far the shared lib has
84 moved. */
85 asm ( " ld %0,-32768(2)\n"
86 " subf %0,%0,2\n"
87 : "=r" (ret));
88 return ret;
91 /* Return the link-time address of _DYNAMIC. */
92 static inline Elf64_Addr
93 elf_machine_dynamic (void)
95 Elf64_Addr runtime_dynamic;
96 /* It's easier to get the run-time address. */
97 asm ( " addis %0,2,_DYNAMIC@toc@ha\n"
98 " addi %0,%0,_DYNAMIC@toc@l\n"
99 : "=b" (runtime_dynamic));
100 /* Then subtract off the load address offset. */
101 return runtime_dynamic - elf_machine_load_address() ;
104 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
106 /* The PLT uses Elf64_Rela relocs. */
107 #define elf_machine_relplt elf_machine_rela
110 #ifdef HAVE_INLINED_SYSCALLS
111 /* We do not need _dl_starting_up. */
112 # define DL_STARTING_UP_DEF
113 #else
114 # define DL_STARTING_UP_DEF \
115 ".LC__dl_starting_up:\n" \
116 " .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n"
117 #endif
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. */
123 #define RTLD_START \
124 asm (".pushsection \".text\"\n" \
125 " .align 2\n" \
126 " .type " BODY_PREFIX "_start,@function\n" \
127 " .pushsection \".opd\",\"aw\"\n" \
128 " .align 3\n" \
129 " .globl _start\n" \
130 " " ENTRY_2(_start) "\n" \
131 "_start:\n" \
132 " " OPD_ENT(_start) "\n" \
133 " .popsection\n" \
134 BODY_PREFIX "_start:\n" \
135 /* We start with the following on the stack, from top: \
136 argc (4 bytes); \
137 arguments for program (terminated by NULL); \
138 environment variables (terminated by NULL); \
139 arguments for the program loader. */ \
140 " mr 3,1\n" \
141 " li 4,0\n" \
142 " stdu 4,-128(1)\n" \
143 /* Call _dl_start with one parameter pointing at argc. */ \
144 " bl " DOT_PREFIX "_dl_start\n" \
145 " nop\n" \
146 /* Transfer control to _dl_start_user! */ \
147 " b " DOT_PREFIX "_dl_start_user\n" \
148 ".LT__start:\n" \
149 " .long 0\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" \
156 " .align 2\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" \
162 " .popsection\n" \
163 " .pushsection \".toc\",\"aw\"\n" \
164 DL_STARTING_UP_DEF \
165 ".LC__rtld_global:\n" \
166 " .tc _rtld_global[TC],_rtld_global\n" \
167 ".LC__dl_argc:\n" \
168 " .tc _dl_argc[TC],_dl_argc\n" \
169 ".LC__dl_argv:\n" \
170 " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
171 ".LC__dl_fini:\n" \
172 " .tc _dl_fini[TC],_dl_fini\n" \
173 " .popsection\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. */ \
183 " mr 30,3\n" \
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). */ \
189 " ld 3,0(28)\n" \
190 " lwa 4,0(29)\n" \
191 " ld 5,0(27)\n" \
192 " sldi 6,4,3\n" \
193 " add 6,5,6\n" \
194 " addi 6,6,8\n" \
195 " bl " DOT_PREFIX "_dl_init\n" \
196 " nop\n" \
197 /* Now, to conform to the ELF ABI, we have to: \
198 Pass argc (actually _dl_argc) in r3; */ \
199 " lwa 3,0(29)\n" \
200 /* Pass argv (actually _dl_argv) in r4; */ \
201 " ld 4,0(27)\n" \
202 /* Pass argv+argc+1 in r5; */ \
203 " sldi 5,3,3\n" \
204 " add 6,4,5\n" \
205 " addi 5,6,8\n" \
206 /* Pass the auxilary vector in r6. This is passed to us just after \
207 _envp. */ \
208 "2: ldu 0,8(6)\n" \
209 " cmpdi 0,0\n" \
210 " bne 2b\n" \
211 " addi 6,6,8\n" \
212 /* Pass a termination function pointer (in this case _dl_fini) in \
213 r7. */ \
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 \
222 the stack. */ \
223 " li 31,0\n" \
224 " std 31,0(1)\n" \
225 " mtlr 31\n" \
226 " std 31,8(1)\n" \
227 " std 31,16(1)\n" \
228 " std 31,24(1)\n" \
229 /* Now, call the start function descriptor at r30... */ \
230 " .globl ._dl_main_dispatch\n" \
231 "._dl_main_dispatch:\n" \
232 " ld 0,0(30)\n" \
233 " ld 2,8(30)\n" \
234 " mtctr 0\n" \
235 " ld 11,16(30)\n" \
236 " bctr\n" \
237 ".LT__dl_start_user:\n" \
238 " .long 0\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" \
245 " .align 2\n" \
246 " " END_2(_dl_start_user) "\n" \
247 " .popsection");
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_SYNC asm volatile ("sync" : : : "memory")
291 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
292 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
293 #define PPC_DIE asm volatile ("tweq 0,0")
294 /* Use this when you've modified some code, but it won't be in the
295 instruction fetch queue (or when it doesn't matter if it is). */
296 #define MODIFIED_CODE_NOQUEUE(where) \
297 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
298 /* Use this when it might be in the instruction queue. */
299 #define MODIFIED_CODE(where) \
300 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
302 /* Set up the loaded object described by MAP so its unrelocated PLT
303 entries will jump to the on-demand fixup code in dl-runtime.c. */
304 static inline int __attribute__ ((always_inline))
305 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
307 if (map->l_info[DT_JMPREL])
309 Elf64_Word i;
310 Elf64_Word *glink = NULL;
311 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
312 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
313 / sizeof (Elf64_Rela));
314 Elf64_Addr l_addr = map->l_addr;
315 Elf64_Dyn **info = map->l_info;
316 char *p;
318 extern void _dl_runtime_resolve (void);
319 extern void _dl_profile_resolve (void);
321 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
322 elf_get_dynamic_info takes care of the standard entries but
323 doesn't know exactly what to do with processor specific
324 entires. */
325 if (info[DT_PPC64(GLINK)] != NULL)
326 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
328 if (lazy)
330 /* The function descriptor of the appropriate trampline
331 routine is used to set the 1st and 2nd doubleword of the
332 plt_reserve. */
333 Elf64_FuncDesc *resolve_fd;
334 Elf64_Word glink_offset;
335 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
336 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
337 Elf64_Word offset;
339 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
340 : _dl_runtime_resolve);
341 if (profile && GLRO(dl_profile) != NULL
342 && _dl_name_match_p (GLRO(dl_profile), map))
343 /* This is the object we are looking for. Say that we really
344 want profiling and the timers are started. */
345 GL(dl_profile_map) = map;
348 /* We need to stuff the address/TOC of _dl_runtime_resolve
349 into doublewords 0 and 1 of plt_reserve. Then we need to
350 stuff the map address into doubleword 2 of plt_reserve.
351 This allows the GLINK0 code to transfer control to the
352 correct trampoline which will transfer control to fixup
353 in dl-machine.c. */
354 plt_reserve->fd_func = resolve_fd->fd_func;
355 plt_reserve->fd_toc = resolve_fd->fd_toc;
356 plt_reserve->fd_aux = (Elf64_Addr) map;
357 #ifdef RTLD_BOOTSTRAP
358 /* When we're bootstrapping, the opd entry will not have
359 been relocated yet. */
360 plt_reserve->fd_func += l_addr;
361 plt_reserve->fd_toc += l_addr;
362 #endif
364 /* Set up the lazy PLT entries. */
365 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
366 offset = PLT_INITIAL_ENTRY_WORDS;
367 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
368 for (i = 0; i < num_plt_entries; i++)
371 plt[offset] = (Elf64_Xword) &glink[glink_offset];
372 offset += 3;
373 /* The first 32k entries of glink can set an index and
374 branch using two instructions; Past that point,
375 glink uses three instructions. */
376 if (i < 0x8000)
377 glink_offset += 2;
378 else
379 glink_offset += 3;
382 /* Now, we've modified data. We need to write the changes from
383 the data cache to a second-level unified cache, then make
384 sure that stale data in the instruction cache is removed.
385 (In a multiprocessor system, the effect is more complex.)
386 Most of the PLT shouldn't be in the instruction cache, but
387 there may be a little overlap at the start and the end.
389 Assumes that dcbst and icbi apply to lines of 16 bytes or
390 more. Current known line sizes are 16, 32, and 128 bytes. */
392 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
393 PPC_DCBST (p);
394 PPC_SYNC;
397 return lazy;
400 /* Change the PLT entry whose reloc is 'reloc' to call the actual
401 routine. */
402 static inline Elf64_Addr __attribute__ ((always_inline))
403 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
404 const Elf64_Rela *reloc,
405 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
407 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
408 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
409 Elf64_Addr offset = 0;
411 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
412 if (sym_map == NULL)
413 return 0;
415 /* If the opd entry is not yet relocated (because it's from a shared
416 object that hasn't been processed yet), then manually reloc it. */
417 if (map != sym_map && !sym_map->l_relocated
418 #if !defined RTLD_BOOTSTRAP && defined SHARED
419 /* Bootstrap map doesn't have l_relocated set for it. */
420 && sym_map != &GL(dl_rtld_map)
421 #endif
423 offset = sym_map->l_addr;
425 /* For PPC64, fixup_plt copies the function descriptor from opd
426 over the corresponding PLT entry.
427 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
428 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
429 so for thread safety we write them before changing fd_func. */
431 plt->fd_aux = rel->fd_aux + offset;
432 plt->fd_toc = rel->fd_toc + offset;
433 PPC_DCBST (&plt->fd_aux);
434 PPC_DCBST (&plt->fd_toc);
435 PPC_SYNC;
437 plt->fd_func = rel->fd_func + offset;
438 PPC_DCBST (&plt->fd_func);
439 PPC_SYNC;
441 return finaladdr;
444 static inline void __attribute__ ((always_inline))
445 elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
447 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
448 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
450 plt->fd_func = rel->fd_func;
451 plt->fd_aux = rel->fd_aux;
452 plt->fd_toc = rel->fd_toc;
453 PPC_DCBST (&plt->fd_func);
454 PPC_DCBST (&plt->fd_aux);
455 PPC_DCBST (&plt->fd_toc);
456 PPC_SYNC;
459 /* Return the final value of a plt relocation. */
460 static inline Elf64_Addr
461 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
462 Elf64_Addr value)
464 return value + reloc->r_addend;
468 /* Names of the architecture-specific auditing callback functions. */
469 #define ARCH_LA_PLTENTER ppc64_gnu_pltenter
470 #define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
472 #endif /* dl_machine_h */
474 #ifdef RESOLVE_MAP
476 #define PPC_LO(v) ((v) & 0xffff)
477 #define PPC_HI(v) (((v) >> 16) & 0xffff)
478 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
479 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
480 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
481 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
482 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
483 #define BIT_INSERT(var, val, mask) \
484 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
486 #define dont_expect(X) __builtin_expect ((X), 0)
488 extern void _dl_reloc_overflow (struct link_map *map,
489 const char *name,
490 Elf64_Addr *const reloc_addr,
491 const Elf64_Sym *refsym)
492 attribute_hidden;
494 auto inline void __attribute__ ((always_inline))
495 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
496 void *const reloc_addr_arg)
498 Elf64_Addr *const reloc_addr = reloc_addr_arg;
499 *reloc_addr = l_addr + reloc->r_addend;
502 #if !defined RTLD_BOOTSTRAP || USE___THREAD
503 /* This computes the value used by TPREL* relocs. */
504 auto inline Elf64_Addr __attribute__ ((always_inline, const))
505 elf_machine_tprel (struct link_map *map,
506 struct link_map *sym_map,
507 const Elf64_Sym *sym,
508 const Elf64_Rela *reloc)
510 # ifndef RTLD_BOOTSTRAP
511 if (sym_map)
513 CHECK_STATIC_TLS (map, sym_map);
514 # endif
515 return TLS_TPREL_VALUE (sym_map, sym, reloc);
516 # ifndef RTLD_BOOTSTRAP
518 # endif
519 return 0;
521 #endif
523 /* Perform the relocation specified by RELOC and SYM (which is fully
524 resolved). MAP is the object containing the reloc. */
525 auto inline void __attribute__ ((always_inline))
526 elf_machine_rela (struct link_map *map,
527 const Elf64_Rela *reloc,
528 const Elf64_Sym *sym,
529 const struct r_found_version *version,
530 void *const reloc_addr_arg)
532 Elf64_Addr *const reloc_addr = reloc_addr_arg;
533 const int r_type = ELF64_R_TYPE (reloc->r_info);
534 #ifndef RTLD_BOOTSTRAP
535 const Elf64_Sym *const refsym = sym;
536 #endif
538 if (r_type == R_PPC64_RELATIVE)
540 *reloc_addr = map->l_addr + reloc->r_addend;
541 return;
544 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
545 return;
547 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt. */
548 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
549 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
550 + reloc->r_addend);
552 /* For relocs that don't edit code, return.
553 For relocs that might edit instructions, break from the switch. */
554 switch (r_type)
556 case R_PPC64_ADDR64:
557 case R_PPC64_GLOB_DAT:
558 *reloc_addr = value;
559 return;
561 case R_PPC64_JMP_SLOT:
562 #ifdef RESOLVE_CONFLICT_FIND_MAP
563 elf_machine_plt_conflict (reloc_addr, value);
564 #else
565 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
566 #endif
567 return;
569 #if !defined RTLD_BOOTSTRAP || USE___THREAD
570 case R_PPC64_DTPMOD64:
571 # ifdef RTLD_BOOTSTRAP
572 /* During startup the dynamic linker is always index 1. */
573 *reloc_addr = 1;
574 # else
575 /* Get the information from the link map returned by the
576 resolve function. */
577 if (sym_map != NULL)
578 *reloc_addr = sym_map->l_tls_modid;
579 # endif
580 return;
582 case R_PPC64_DTPREL64:
583 /* During relocation all TLS symbols are defined and used.
584 Therefore the offset is already correct. */
585 # ifndef RTLD_BOOTSTRAP
586 if (sym_map != NULL)
587 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
588 # endif
589 return;
591 case R_PPC64_TPREL64:
592 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
593 return;
595 case R_PPC64_TPREL16_LO_DS:
596 value = elf_machine_tprel (map, sym_map, sym, reloc);
597 if (dont_expect ((value & 3) != 0))
598 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
599 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
600 value, 0xfffc);
601 break;
603 case R_PPC64_TPREL16_DS:
604 value = elf_machine_tprel (map, sym_map, sym, reloc);
605 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
606 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
607 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
608 value, 0xfffc);
609 break;
611 case R_PPC64_TPREL16:
612 value = elf_machine_tprel (map, sym_map, sym, reloc);
613 if (dont_expect ((value + 0x8000) >= 0x10000))
614 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
615 *(Elf64_Half *) reloc_addr = PPC_LO (value);
616 break;
618 case R_PPC64_TPREL16_LO:
619 value = elf_machine_tprel (map, sym_map, sym, reloc);
620 *(Elf64_Half *) reloc_addr = PPC_LO (value);
621 break;
623 case R_PPC64_TPREL16_HI:
624 value = elf_machine_tprel (map, sym_map, sym, reloc);
625 *(Elf64_Half *) reloc_addr = PPC_HI (value);
626 break;
628 case R_PPC64_TPREL16_HA:
629 value = elf_machine_tprel (map, sym_map, sym, reloc);
630 *(Elf64_Half *) reloc_addr = PPC_HA (value);
631 break;
633 case R_PPC64_TPREL16_HIGHER:
634 value = elf_machine_tprel (map, sym_map, sym, reloc);
635 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
636 break;
638 case R_PPC64_TPREL16_HIGHEST:
639 value = elf_machine_tprel (map, sym_map, sym, reloc);
640 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
641 break;
643 case R_PPC64_TPREL16_HIGHERA:
644 value = elf_machine_tprel (map, sym_map, sym, reloc);
645 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
646 break;
648 case R_PPC64_TPREL16_HIGHESTA:
649 value = elf_machine_tprel (map, sym_map, sym, reloc);
650 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
651 break;
652 #endif
654 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
655 case R_PPC64_ADDR16_LO_DS:
656 if (dont_expect ((value & 3) != 0))
657 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
658 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
659 break;
661 case R_PPC64_ADDR16_LO:
662 *(Elf64_Half *) reloc_addr = PPC_LO (value);
663 break;
665 case R_PPC64_ADDR16_HI:
666 *(Elf64_Half *) reloc_addr = PPC_HI (value);
667 break;
669 case R_PPC64_ADDR16_HA:
670 *(Elf64_Half *) reloc_addr = PPC_HA (value);
671 break;
673 case R_PPC64_ADDR30:
675 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
676 if (dont_expect ((delta + 0x80000000) >= 0x10000000
677 || (delta & 3) != 0))
678 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
679 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
681 break;
683 case R_PPC64_COPY:
684 if (dont_expect (sym == NULL))
685 /* This can happen in trace mode when an object could not be found. */
686 return;
687 if (dont_expect (sym->st_size > refsym->st_size
688 || (GLRO(dl_verbose)
689 && sym->st_size < refsym->st_size)))
691 const char *strtab;
693 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
694 _dl_error_printf ("%s: Symbol `%s' has different size" \
695 " in shared object," \
696 " consider re-linking\n",
697 _dl_argv[0] ?: "<program name unknown>",
698 strtab + refsym->st_name);
700 memcpy (reloc_addr_arg, (char *) value,
701 MIN (sym->st_size, refsym->st_size));
702 return;
704 case R_PPC64_UADDR64:
705 /* We are big-endian. */
706 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
707 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
708 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
709 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
710 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
711 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
712 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
713 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
714 return;
716 case R_PPC64_UADDR32:
717 /* We are big-endian. */
718 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
719 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
720 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
721 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
722 return;
724 case R_PPC64_ADDR32:
725 if (dont_expect ((value + 0x80000000) >= 0x10000000))
726 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
727 *(Elf64_Word *) reloc_addr = value;
728 return;
730 case R_PPC64_ADDR24:
731 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
732 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
733 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
734 break;
736 case R_PPC64_ADDR16:
737 if (dont_expect ((value + 0x8000) >= 0x10000))
738 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
739 *(Elf64_Half *) reloc_addr = value;
740 break;
742 case R_PPC64_UADDR16:
743 if (dont_expect ((value + 0x8000) >= 0x10000))
744 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
745 /* We are big-endian. */
746 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
747 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
748 break;
750 case R_PPC64_ADDR16_DS:
751 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
752 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
753 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
754 break;
756 case R_PPC64_ADDR16_HIGHER:
757 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
758 break;
760 case R_PPC64_ADDR16_HIGHEST:
761 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
762 break;
764 case R_PPC64_ADDR16_HIGHERA:
765 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
766 break;
768 case R_PPC64_ADDR16_HIGHESTA:
769 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
770 break;
772 case R_PPC64_ADDR14:
773 case R_PPC64_ADDR14_BRTAKEN:
774 case R_PPC64_ADDR14_BRNTAKEN:
776 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
777 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
778 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
779 BIT_INSERT (insn, value, 0xfffc);
780 if (r_type != R_PPC64_ADDR14)
782 insn &= ~(1 << 21);
783 if (r_type == R_PPC64_ADDR14_BRTAKEN)
784 insn |= 1 << 21;
785 if ((insn & (0x14 << 21)) == (0x04 << 21))
786 insn |= 0x02 << 21;
787 else if ((insn & (0x14 << 21)) == (0x10 << 21))
788 insn |= 0x08 << 21;
790 *(Elf64_Word *) reloc_addr = insn;
792 break;
794 case R_PPC64_REL32:
795 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
796 return;
798 case R_PPC64_REL64:
799 *reloc_addr = value - (Elf64_Addr) reloc_addr;
800 return;
801 #endif /* !RTLD_BOOTSTRAP */
803 default:
804 _dl_reloc_bad_type (map, r_type, 0);
805 return;
807 MODIFIED_CODE_NOQUEUE (reloc_addr);
810 auto inline void __attribute__ ((always_inline))
811 elf_machine_lazy_rel (struct link_map *map,
812 Elf64_Addr l_addr, const Elf64_Rela *reloc)
814 /* elf_machine_runtime_setup handles this. */
818 #endif /* RESOLVE */