Updated to fedora-glibc-20060109T2152
[glibc/history.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
blobcec271bb3a3aed2f56e951be6a8ae9da93bc82e0
1 /* Machine-dependent ELF dynamic relocation inline functions.
2 PowerPC64 version.
3 Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
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. */
22 #ifndef dl_machine_h
23 #define dl_machine_h
25 #define ELF_MACHINE_NAME "powerpc64"
27 #include <assert.h>
28 #include <sys/param.h>
29 #include <dl-tls.h>
30 #include <sysdep.h>
32 /* Translate a processor specific dynamic tag to the index
33 in l_info array. */
34 #define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
36 /* A PowerPC64 function descriptor. The .plt (procedure linkage
37 table) and .opd (official procedure descriptor) sections are
38 arrays of these. */
39 typedef struct
41 Elf64_Addr fd_func;
42 Elf64_Addr fd_toc;
43 Elf64_Addr fd_aux;
44 } Elf64_FuncDesc;
46 #define ELF_MULT_MACHINES_SUPPORTED
48 /* Return nonzero iff ELF header is compatible with the running host. */
49 static inline int
50 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
52 return ehdr->e_machine == EM_PPC64;
55 /* Return nonzero iff ELF header is compatible with the running host,
56 but not this loader. */
57 static inline int
58 elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
60 return ehdr->e_machine == EM_PPC;
63 /* Return nonzero iff ELF header is compatible with the running host,
64 but not this loader. */
65 static inline int
66 elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
68 return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
72 /* Return the run-time load address of the shared object, assuming it
73 was originally linked at zero. */
74 static inline Elf64_Addr
75 elf_machine_load_address (void) __attribute__ ((const));
77 static inline Elf64_Addr
78 elf_machine_load_address (void)
80 Elf64_Addr ret;
82 /* The first entry in .got (and thus the first entry in .toc) is the
83 link-time TOC_base, ie. r2. So the difference between that and
84 the current r2 set by the kernel is how far the shared lib has
85 moved. */
86 asm ( " ld %0,-32768(2)\n"
87 " subf %0,%0,2\n"
88 : "=r" (ret));
89 return ret;
92 /* Return the link-time address of _DYNAMIC. */
93 static inline Elf64_Addr
94 elf_machine_dynamic (void)
96 Elf64_Addr runtime_dynamic;
97 /* It's easier to get the run-time address. */
98 asm ( " addis %0,2,_DYNAMIC@toc@ha\n"
99 " addi %0,%0,_DYNAMIC@toc@l\n"
100 : "=b" (runtime_dynamic));
101 /* Then subtract off the load address offset. */
102 return runtime_dynamic - elf_machine_load_address() ;
105 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
107 /* The PLT uses Elf64_Rela relocs. */
108 #define elf_machine_relplt elf_machine_rela
111 #ifdef HAVE_INLINED_SYSCALLS
112 /* We do not need _dl_starting_up. */
113 # define DL_STARTING_UP_DEF
114 #else
115 # define DL_STARTING_UP_DEF \
116 ".LC__dl_starting_up:\n" \
117 " .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n"
118 #endif
121 /* Initial entry point code for the dynamic linker. The C function
122 `_dl_start' is the real entry point; its return value is the user
123 program's entry point. */
124 #define RTLD_START \
125 asm (".pushsection \".text\"\n" \
126 " .align 2\n" \
127 " .type " BODY_PREFIX "_start,@function\n" \
128 " .pushsection \".opd\",\"aw\"\n" \
129 " .align 3\n" \
130 " .globl _start\n" \
131 " " ENTRY_2(_start) "\n" \
132 "_start:\n" \
133 " " OPD_ENT(_start) "\n" \
134 " .popsection\n" \
135 BODY_PREFIX "_start:\n" \
136 /* We start with the following on the stack, from top: \
137 argc (4 bytes); \
138 arguments for program (terminated by NULL); \
139 environment variables (terminated by NULL); \
140 arguments for the program loader. */ \
141 " mr 3,1\n" \
142 " li 4,0\n" \
143 " stdu 4,-128(1)\n" \
144 /* Call _dl_start with one parameter pointing at argc. */ \
145 " bl " DOT_PREFIX "_dl_start\n" \
146 " nop\n" \
147 /* Transfer control to _dl_start_user! */ \
148 " b " DOT_PREFIX "_dl_start_user\n" \
149 ".LT__start:\n" \
150 " .long 0\n" \
151 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
152 " .long .LT__start-" BODY_PREFIX "_start\n" \
153 " .short .LT__start_name_end-.LT__start_name_start\n" \
154 ".LT__start_name_start:\n" \
155 " .ascii \"_start\"\n" \
156 ".LT__start_name_end:\n" \
157 " .align 2\n" \
158 " " END_2(_start) "\n" \
159 " .globl _dl_start_user\n" \
160 " .pushsection \".opd\",\"aw\"\n" \
161 "_dl_start_user:\n" \
162 " " OPD_ENT(_dl_start_user) "\n" \
163 " .popsection\n" \
164 " .pushsection \".toc\",\"aw\"\n" \
165 DL_STARTING_UP_DEF \
166 ".LC__rtld_global:\n" \
167 " .tc _rtld_global[TC],_rtld_global\n" \
168 ".LC__dl_argc:\n" \
169 " .tc _dl_argc[TC],_dl_argc\n" \
170 ".LC__dl_argv:\n" \
171 " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
172 ".LC__dl_fini:\n" \
173 " .tc _dl_fini[TC],_dl_fini\n" \
174 " .popsection\n" \
175 " .type " BODY_PREFIX "_dl_start_user,@function\n" \
176 " " ENTRY_2(_dl_start_user) "\n" \
177 /* Now, we do our main work of calling initialisation procedures. \
178 The ELF ABI doesn't say anything about parameters for these, \
179 so we just pass argc, argv, and the environment. \
180 Changing these is strongly discouraged (not least because argc is \
181 passed by value!). */ \
182 BODY_PREFIX "_dl_start_user:\n" \
183 /* the address of _start in r30. */ \
184 " mr 30,3\n" \
185 /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
186 " ld 28,.LC__rtld_global@toc(2)\n" \
187 " ld 29,.LC__dl_argc@toc(2)\n" \
188 " ld 27,.LC__dl_argv@toc(2)\n" \
189 /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \
190 " ld 3,0(28)\n" \
191 " lwa 4,0(29)\n" \
192 " ld 5,0(27)\n" \
193 " sldi 6,4,3\n" \
194 " add 6,5,6\n" \
195 " addi 6,6,8\n" \
196 " bl " DOT_PREFIX "_dl_init\n" \
197 " nop\n" \
198 /* Now, to conform to the ELF ABI, we have to: \
199 Pass argc (actually _dl_argc) in r3; */ \
200 " lwa 3,0(29)\n" \
201 /* Pass argv (actually _dl_argv) in r4; */ \
202 " ld 4,0(27)\n" \
203 /* Pass argv+argc+1 in r5; */ \
204 " sldi 5,3,3\n" \
205 " add 6,4,5\n" \
206 " addi 5,6,8\n" \
207 /* Pass the auxilary vector in r6. This is passed to us just after \
208 _envp. */ \
209 "2: ldu 0,8(6)\n" \
210 " cmpdi 0,0\n" \
211 " bne 2b\n" \
212 " addi 6,6,8\n" \
213 /* Pass a termination function pointer (in this case _dl_fini) in \
214 r7. */ \
215 " ld 7,.LC__dl_fini@toc(2)\n" \
216 /* Pass the stack pointer in r1 (so far so good), pointing to a NULL \
217 value. This lets our startup code distinguish between a program \
218 linked statically, which linux will call with argc on top of the \
219 stack which will hopefully never be zero, and a dynamically linked \
220 program which will always have a NULL on the top of the stack. \
221 Take the opportunity to clear LR, so anyone who accidentally \
222 returns from _start gets SEGV. Also clear the next few words of \
223 the stack. */ \
224 " li 31,0\n" \
225 " std 31,0(1)\n" \
226 " mtlr 31\n" \
227 " std 31,8(1)\n" \
228 " std 31,16(1)\n" \
229 " std 31,24(1)\n" \
230 /* Now, call the start function descriptor at r30... */ \
231 " .globl ._dl_main_dispatch\n" \
232 "._dl_main_dispatch:\n" \
233 " ld 0,0(30)\n" \
234 " ld 2,8(30)\n" \
235 " mtctr 0\n" \
236 " ld 11,16(30)\n" \
237 " bctr\n" \
238 ".LT__dl_start_user:\n" \
239 " .long 0\n" \
240 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
241 " .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n" \
242 " .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
243 ".LT__dl_start_user_name_start:\n" \
244 " .ascii \"_dl_start_user\"\n" \
245 ".LT__dl_start_user_name_end:\n" \
246 " .align 2\n" \
247 " " END_2(_dl_start_user) "\n" \
248 " .popsection");
250 /* Nonzero iff TYPE should not be allowed to resolve to one of
251 the main executable's symbols, as for a COPY reloc. */
252 #define elf_machine_lookup_noexec_p(type) ((type) == R_PPC64_COPY)
254 /* Nonzero iff TYPE describes relocation of a PLT entry, so
255 PLT entries should not be allowed to define the value. */
256 #define elf_machine_lookup_noplt_p(type) ((type) == R_PPC64_JMP_SLOT)
258 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
259 PLT entries should not be allowed to define the value.
260 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
261 of the main executable's symbols, as for a COPY reloc. */
263 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
264 #define elf_machine_type_class(type) \
265 /* This covers all the TLS relocs, though most won't appear. */ \
266 (((((type) >= R_PPC64_DTPMOD64 && (type) <= R_PPC64_TPREL16_HIGHESTA) \
267 || (type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
268 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
269 #else
270 #define elf_machine_type_class(type) \
271 ((((type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
272 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
273 #endif
275 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
276 #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
278 /* The PowerPC never uses REL relocations. */
279 #define ELF_MACHINE_NO_REL 1
281 /* Stuff for the PLT. */
282 #define PLT_INITIAL_ENTRY_WORDS 3
283 #define GLINK_INITIAL_ENTRY_WORDS 8
285 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
286 #define PPC_SYNC asm volatile ("sync" : : : "memory")
287 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
288 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
289 #define PPC_DIE asm volatile ("tweq 0,0")
290 /* Use this when you've modified some code, but it won't be in the
291 instruction fetch queue (or when it doesn't matter if it is). */
292 #define MODIFIED_CODE_NOQUEUE(where) \
293 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
294 /* Use this when it might be in the instruction queue. */
295 #define MODIFIED_CODE(where) \
296 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
298 /* Set up the loaded object described by MAP so its unrelocated PLT
299 entries will jump to the on-demand fixup code in dl-runtime.c. */
300 static inline int __attribute__ ((always_inline))
301 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
303 if (map->l_info[DT_JMPREL])
305 Elf64_Word i;
306 Elf64_Word *glink = NULL;
307 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
308 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
309 / sizeof (Elf64_Rela));
310 Elf64_Addr l_addr = map->l_addr;
311 Elf64_Dyn **info = map->l_info;
312 char *p;
314 extern void _dl_runtime_resolve (void);
315 extern void _dl_profile_resolve (void);
317 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
318 elf_get_dynamic_info takes care of the standard entries but
319 doesn't know exactly what to do with processor specific
320 entires. */
321 if (info[DT_PPC64(GLINK)] != NULL)
322 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
324 if (lazy)
326 /* The function descriptor of the appropriate trampline
327 routine is used to set the 1st and 2nd doubleword of the
328 plt_reserve. */
329 Elf64_FuncDesc *resolve_fd;
330 Elf64_Word glink_offset;
331 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
332 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
333 Elf64_Word offset;
335 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
336 : _dl_runtime_resolve);
337 if (profile && GLRO(dl_profile) != NULL
338 && _dl_name_match_p (GLRO(dl_profile), map))
339 /* This is the object we are looking for. Say that we really
340 want profiling and the timers are started. */
341 GL(dl_profile_map) = map;
344 /* We need to stuff the address/TOC of _dl_runtime_resolve
345 into doublewords 0 and 1 of plt_reserve. Then we need to
346 stuff the map address into doubleword 2 of plt_reserve.
347 This allows the GLINK0 code to transfer control to the
348 correct trampoline which will transfer control to fixup
349 in dl-machine.c. */
350 plt_reserve->fd_func = resolve_fd->fd_func;
351 plt_reserve->fd_toc = resolve_fd->fd_toc;
352 plt_reserve->fd_aux = (Elf64_Addr) map;
353 #ifdef RTLD_BOOTSTRAP
354 /* When we're bootstrapping, the opd entry will not have
355 been relocated yet. */
356 plt_reserve->fd_func += l_addr;
357 plt_reserve->fd_toc += l_addr;
358 #endif
360 /* Set up the lazy PLT entries. */
361 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
362 offset = PLT_INITIAL_ENTRY_WORDS;
363 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
364 for (i = 0; i < num_plt_entries; i++)
367 plt[offset] = (Elf64_Xword) &glink[glink_offset];
368 offset += 3;
369 /* The first 32k entries of glink can set an index and
370 branch using two instructions; Past that point,
371 glink uses three instructions. */
372 if (i < 0x8000)
373 glink_offset += 2;
374 else
375 glink_offset += 3;
378 /* Now, we've modified data. We need to write the changes from
379 the data cache to a second-level unified cache, then make
380 sure that stale data in the instruction cache is removed.
381 (In a multiprocessor system, the effect is more complex.)
382 Most of the PLT shouldn't be in the instruction cache, but
383 there may be a little overlap at the start and the end.
385 Assumes that dcbst and icbi apply to lines of 16 bytes or
386 more. Current known line sizes are 16, 32, and 128 bytes. */
388 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
389 PPC_DCBST (p);
390 PPC_SYNC;
393 return lazy;
396 /* Change the PLT entry whose reloc is 'reloc' to call the actual
397 routine. */
398 static inline Elf64_Addr __attribute__ ((always_inline))
399 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
400 const Elf64_Rela *reloc,
401 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
403 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
404 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
405 Elf64_Addr offset = 0;
407 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
408 if (sym_map == NULL)
409 return 0;
411 /* If the opd entry is not yet relocated (because it's from a shared
412 object that hasn't been processed yet), then manually reloc it. */
413 if (map != sym_map && !sym_map->l_relocated
414 #if !defined RTLD_BOOTSTRAP && defined SHARED
415 /* Bootstrap map doesn't have l_relocated set for it. */
416 && sym_map != &GL(dl_rtld_map)
417 #endif
419 offset = sym_map->l_addr;
421 /* For PPC64, fixup_plt copies the function descriptor from opd
422 over the corresponding PLT entry.
423 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
424 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
425 so for thread safety we write them before changing fd_func. */
427 plt->fd_aux = rel->fd_aux + offset;
428 plt->fd_toc = rel->fd_toc + offset;
429 PPC_DCBST (&plt->fd_aux);
430 PPC_DCBST (&plt->fd_toc);
431 PPC_SYNC;
433 plt->fd_func = rel->fd_func + offset;
434 PPC_DCBST (&plt->fd_func);
435 PPC_SYNC;
437 return finaladdr;
440 static inline void __attribute__ ((always_inline))
441 elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
443 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
444 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
446 plt->fd_func = rel->fd_func;
447 plt->fd_aux = rel->fd_aux;
448 plt->fd_toc = rel->fd_toc;
449 PPC_DCBST (&plt->fd_func);
450 PPC_DCBST (&plt->fd_aux);
451 PPC_DCBST (&plt->fd_toc);
452 PPC_SYNC;
455 /* Return the final value of a plt relocation. */
456 static inline Elf64_Addr
457 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
458 Elf64_Addr value)
460 return value + reloc->r_addend;
464 /* Names of the architecture-specific auditing callback functions. */
465 #define ARCH_LA_PLTENTER ppc64_gnu_pltenter
466 #define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
468 #endif /* dl_machine_h */
470 #ifdef RESOLVE_MAP
472 #define PPC_LO(v) ((v) & 0xffff)
473 #define PPC_HI(v) (((v) >> 16) & 0xffff)
474 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
475 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
476 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
477 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
478 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
479 #define BIT_INSERT(var, val, mask) \
480 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
482 #define dont_expect(X) __builtin_expect ((X), 0)
484 extern void _dl_reloc_overflow (struct link_map *map,
485 const char *name,
486 Elf64_Addr *const reloc_addr,
487 const Elf64_Sym *refsym)
488 attribute_hidden;
490 auto inline void __attribute__ ((always_inline))
491 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
492 void *const reloc_addr_arg)
494 Elf64_Addr *const reloc_addr = reloc_addr_arg;
495 *reloc_addr = l_addr + reloc->r_addend;
498 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
499 /* This computes the value used by TPREL* relocs. */
500 auto inline Elf64_Addr __attribute__ ((always_inline, const))
501 elf_machine_tprel (struct link_map *map,
502 struct link_map *sym_map,
503 const Elf64_Sym *sym,
504 const Elf64_Rela *reloc)
506 # ifndef RTLD_BOOTSTRAP
507 if (sym_map)
509 CHECK_STATIC_TLS (map, sym_map);
510 # endif
511 return TLS_TPREL_VALUE (sym_map, sym, reloc);
512 # ifndef RTLD_BOOTSTRAP
514 # endif
515 return 0;
517 #endif
519 /* Perform the relocation specified by RELOC and SYM (which is fully
520 resolved). MAP is the object containing the reloc. */
521 auto inline void __attribute__ ((always_inline))
522 elf_machine_rela (struct link_map *map,
523 const Elf64_Rela *reloc,
524 const Elf64_Sym *sym,
525 const struct r_found_version *version,
526 void *const reloc_addr_arg)
528 Elf64_Addr *const reloc_addr = reloc_addr_arg;
529 const int r_type = ELF64_R_TYPE (reloc->r_info);
530 #ifndef RTLD_BOOTSTRAP
531 const Elf64_Sym *const refsym = sym;
532 #endif
534 if (r_type == R_PPC64_RELATIVE)
536 *reloc_addr = map->l_addr + reloc->r_addend;
537 return;
540 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
541 return;
543 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt. */
544 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
545 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
546 + reloc->r_addend);
548 /* For relocs that don't edit code, return.
549 For relocs that might edit instructions, break from the switch. */
550 switch (r_type)
552 case R_PPC64_ADDR64:
553 case R_PPC64_GLOB_DAT:
554 *reloc_addr = value;
555 return;
557 case R_PPC64_JMP_SLOT:
558 #ifdef RESOLVE_CONFLICT_FIND_MAP
559 elf_machine_plt_conflict (reloc_addr, value);
560 #else
561 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
562 #endif
563 return;
565 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
566 case R_PPC64_DTPMOD64:
567 # ifdef RTLD_BOOTSTRAP
568 /* During startup the dynamic linker is always index 1. */
569 *reloc_addr = 1;
570 # else
571 /* Get the information from the link map returned by the
572 resolve function. */
573 if (sym_map != NULL)
574 *reloc_addr = sym_map->l_tls_modid;
575 # endif
576 return;
578 case R_PPC64_DTPREL64:
579 /* During relocation all TLS symbols are defined and used.
580 Therefore the offset is already correct. */
581 # ifndef RTLD_BOOTSTRAP
582 if (sym_map != NULL)
583 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
584 # endif
585 return;
587 case R_PPC64_TPREL64:
588 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
589 return;
591 case R_PPC64_TPREL16_LO_DS:
592 value = elf_machine_tprel (map, sym_map, sym, reloc);
593 if (dont_expect ((value & 3) != 0))
594 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
595 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
596 value, 0xfffc);
597 break;
599 case R_PPC64_TPREL16_DS:
600 value = elf_machine_tprel (map, sym_map, sym, reloc);
601 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
602 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
603 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
604 value, 0xfffc);
605 break;
607 case R_PPC64_TPREL16:
608 value = elf_machine_tprel (map, sym_map, sym, reloc);
609 if (dont_expect ((value + 0x8000) >= 0x10000))
610 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
611 *(Elf64_Half *) reloc_addr = PPC_LO (value);
612 break;
614 case R_PPC64_TPREL16_LO:
615 value = elf_machine_tprel (map, sym_map, sym, reloc);
616 *(Elf64_Half *) reloc_addr = PPC_LO (value);
617 break;
619 case R_PPC64_TPREL16_HI:
620 value = elf_machine_tprel (map, sym_map, sym, reloc);
621 *(Elf64_Half *) reloc_addr = PPC_HI (value);
622 break;
624 case R_PPC64_TPREL16_HA:
625 value = elf_machine_tprel (map, sym_map, sym, reloc);
626 *(Elf64_Half *) reloc_addr = PPC_HA (value);
627 break;
629 case R_PPC64_TPREL16_HIGHER:
630 value = elf_machine_tprel (map, sym_map, sym, reloc);
631 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
632 break;
634 case R_PPC64_TPREL16_HIGHEST:
635 value = elf_machine_tprel (map, sym_map, sym, reloc);
636 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
637 break;
639 case R_PPC64_TPREL16_HIGHERA:
640 value = elf_machine_tprel (map, sym_map, sym, reloc);
641 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
642 break;
644 case R_PPC64_TPREL16_HIGHESTA:
645 value = elf_machine_tprel (map, sym_map, sym, reloc);
646 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
647 break;
648 #endif /* USE_TLS etc. */
650 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
651 case R_PPC64_ADDR16_LO_DS:
652 if (dont_expect ((value & 3) != 0))
653 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
654 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
655 break;
657 case R_PPC64_ADDR16_LO:
658 *(Elf64_Half *) reloc_addr = PPC_LO (value);
659 break;
661 case R_PPC64_ADDR16_HI:
662 *(Elf64_Half *) reloc_addr = PPC_HI (value);
663 break;
665 case R_PPC64_ADDR16_HA:
666 *(Elf64_Half *) reloc_addr = PPC_HA (value);
667 break;
669 case R_PPC64_ADDR30:
671 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
672 if (dont_expect ((delta + 0x80000000) >= 0x10000000
673 || (delta & 3) != 0))
674 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
675 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
677 break;
679 case R_PPC64_COPY:
680 if (dont_expect (sym == NULL))
681 /* This can happen in trace mode when an object could not be found. */
682 return;
683 if (dont_expect (sym->st_size > refsym->st_size
684 || (GLRO(dl_verbose)
685 && sym->st_size < refsym->st_size)))
687 const char *strtab;
689 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
690 _dl_error_printf ("%s: Symbol `%s' has different size" \
691 " in shared object," \
692 " consider re-linking\n",
693 _dl_argv[0] ?: "<program name unknown>",
694 strtab + refsym->st_name);
696 memcpy (reloc_addr_arg, (char *) value,
697 MIN (sym->st_size, refsym->st_size));
698 return;
700 case R_PPC64_UADDR64:
701 /* We are big-endian. */
702 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
703 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
704 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
705 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
706 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
707 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
708 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
709 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
710 return;
712 case R_PPC64_UADDR32:
713 /* We are big-endian. */
714 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
715 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
716 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
717 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
718 return;
720 case R_PPC64_ADDR32:
721 if (dont_expect ((value + 0x80000000) >= 0x10000000))
722 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
723 *(Elf64_Word *) reloc_addr = value;
724 return;
726 case R_PPC64_ADDR24:
727 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
728 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
729 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
730 break;
732 case R_PPC64_ADDR16:
733 if (dont_expect ((value + 0x8000) >= 0x10000))
734 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
735 *(Elf64_Half *) reloc_addr = value;
736 break;
738 case R_PPC64_UADDR16:
739 if (dont_expect ((value + 0x8000) >= 0x10000))
740 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
741 /* We are big-endian. */
742 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
743 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
744 break;
746 case R_PPC64_ADDR16_DS:
747 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
748 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
749 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
750 break;
752 case R_PPC64_ADDR16_HIGHER:
753 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
754 break;
756 case R_PPC64_ADDR16_HIGHEST:
757 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
758 break;
760 case R_PPC64_ADDR16_HIGHERA:
761 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
762 break;
764 case R_PPC64_ADDR16_HIGHESTA:
765 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
766 break;
768 case R_PPC64_ADDR14:
769 case R_PPC64_ADDR14_BRTAKEN:
770 case R_PPC64_ADDR14_BRNTAKEN:
772 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
773 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
774 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
775 BIT_INSERT (insn, value, 0xfffc);
776 if (r_type != R_PPC64_ADDR14)
778 insn &= ~(1 << 21);
779 if (r_type == R_PPC64_ADDR14_BRTAKEN)
780 insn |= 1 << 21;
781 if ((insn & (0x14 << 21)) == (0x04 << 21))
782 insn |= 0x02 << 21;
783 else if ((insn & (0x14 << 21)) == (0x10 << 21))
784 insn |= 0x08 << 21;
786 *(Elf64_Word *) reloc_addr = insn;
788 break;
790 case R_PPC64_REL32:
791 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
792 return;
794 case R_PPC64_REL64:
795 *reloc_addr = value - (Elf64_Addr) reloc_addr;
796 return;
797 #endif /* !RTLD_BOOTSTRAP */
799 default:
800 _dl_reloc_bad_type (map, r_type, 0);
801 return;
803 MODIFIED_CODE_NOQUEUE (reloc_addr);
806 auto inline void __attribute__ ((always_inline))
807 elf_machine_lazy_rel (struct link_map *map,
808 Elf64_Addr l_addr, const Elf64_Rela *reloc)
810 /* elf_machine_runtime_setup handles this. */
814 #endif /* RESOLVE */