[BZ #2510, BZ #2830, BZ #3137, BZ #3313, BZ #3426, BZ #3465, BZ #3480, BZ #3483,...
[glibc.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
blob89a69e1a2377d046703be694859b36fe93acdb46
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 /* Nonzero iff TYPE should not be allowed to resolve to one of
250 the main executable's symbols, as for a COPY reloc. */
251 #define elf_machine_lookup_noexec_p(type) ((type) == R_PPC64_COPY)
253 /* Nonzero iff TYPE describes relocation of a PLT entry, so
254 PLT entries should not be allowed to define the value. */
255 #define elf_machine_lookup_noplt_p(type) ((type) == R_PPC64_JMP_SLOT)
257 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
258 PLT entries should not be allowed to define the value.
259 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
260 of the main executable's symbols, as for a COPY reloc. */
262 #if !defined RTLD_BOOTSTRAP || USE___THREAD
263 #define elf_machine_type_class(type) \
264 /* This covers all the TLS relocs, though most won't appear. */ \
265 (((((type) >= R_PPC64_DTPMOD64 && (type) <= R_PPC64_TPREL16_HIGHESTA) \
266 || (type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
267 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
268 #else
269 #define elf_machine_type_class(type) \
270 ((((type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
271 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
272 #endif
274 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
275 #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
277 /* The PowerPC never uses REL relocations. */
278 #define ELF_MACHINE_NO_REL 1
280 /* Stuff for the PLT. */
281 #define PLT_INITIAL_ENTRY_WORDS 3
282 #define GLINK_INITIAL_ENTRY_WORDS 8
284 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
285 #define PPC_SYNC asm volatile ("sync" : : : "memory")
286 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
287 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
288 #define PPC_DIE asm volatile ("tweq 0,0")
289 /* Use this when you've modified some code, but it won't be in the
290 instruction fetch queue (or when it doesn't matter if it is). */
291 #define MODIFIED_CODE_NOQUEUE(where) \
292 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
293 /* Use this when it might be in the instruction queue. */
294 #define MODIFIED_CODE(where) \
295 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
297 /* Set up the loaded object described by MAP so its unrelocated PLT
298 entries will jump to the on-demand fixup code in dl-runtime.c. */
299 static inline int __attribute__ ((always_inline))
300 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
302 if (map->l_info[DT_JMPREL])
304 Elf64_Word i;
305 Elf64_Word *glink = NULL;
306 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
307 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
308 / sizeof (Elf64_Rela));
309 Elf64_Addr l_addr = map->l_addr;
310 Elf64_Dyn **info = map->l_info;
311 char *p;
313 extern void _dl_runtime_resolve (void);
314 extern void _dl_profile_resolve (void);
316 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
317 elf_get_dynamic_info takes care of the standard entries but
318 doesn't know exactly what to do with processor specific
319 entires. */
320 if (info[DT_PPC64(GLINK)] != NULL)
321 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
323 if (lazy)
325 /* The function descriptor of the appropriate trampline
326 routine is used to set the 1st and 2nd doubleword of the
327 plt_reserve. */
328 Elf64_FuncDesc *resolve_fd;
329 Elf64_Word glink_offset;
330 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
331 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
332 Elf64_Word offset;
334 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
335 : _dl_runtime_resolve);
336 if (profile && GLRO(dl_profile) != NULL
337 && _dl_name_match_p (GLRO(dl_profile), map))
338 /* This is the object we are looking for. Say that we really
339 want profiling and the timers are started. */
340 GL(dl_profile_map) = map;
343 /* We need to stuff the address/TOC of _dl_runtime_resolve
344 into doublewords 0 and 1 of plt_reserve. Then we need to
345 stuff the map address into doubleword 2 of plt_reserve.
346 This allows the GLINK0 code to transfer control to the
347 correct trampoline which will transfer control to fixup
348 in dl-machine.c. */
349 plt_reserve->fd_func = resolve_fd->fd_func;
350 plt_reserve->fd_toc = resolve_fd->fd_toc;
351 plt_reserve->fd_aux = (Elf64_Addr) map;
352 #ifdef RTLD_BOOTSTRAP
353 /* When we're bootstrapping, the opd entry will not have
354 been relocated yet. */
355 plt_reserve->fd_func += l_addr;
356 plt_reserve->fd_toc += l_addr;
357 #endif
359 /* Set up the lazy PLT entries. */
360 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
361 offset = PLT_INITIAL_ENTRY_WORDS;
362 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
363 for (i = 0; i < num_plt_entries; i++)
366 plt[offset] = (Elf64_Xword) &glink[glink_offset];
367 offset += 3;
368 /* The first 32k entries of glink can set an index and
369 branch using two instructions; Past that point,
370 glink uses three instructions. */
371 if (i < 0x8000)
372 glink_offset += 2;
373 else
374 glink_offset += 3;
377 /* Now, we've modified data. We need to write the changes from
378 the data cache to a second-level unified cache, then make
379 sure that stale data in the instruction cache is removed.
380 (In a multiprocessor system, the effect is more complex.)
381 Most of the PLT shouldn't be in the instruction cache, but
382 there may be a little overlap at the start and the end.
384 Assumes that dcbst and icbi apply to lines of 16 bytes or
385 more. Current known line sizes are 16, 32, and 128 bytes. */
387 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
388 PPC_DCBST (p);
389 PPC_SYNC;
392 return lazy;
395 /* Change the PLT entry whose reloc is 'reloc' to call the actual
396 routine. */
397 static inline Elf64_Addr __attribute__ ((always_inline))
398 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
399 const Elf64_Rela *reloc,
400 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
402 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
403 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
404 Elf64_Addr offset = 0;
406 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
407 if (sym_map == NULL)
408 return 0;
410 /* If the opd entry is not yet relocated (because it's from a shared
411 object that hasn't been processed yet), then manually reloc it. */
412 if (map != sym_map && !sym_map->l_relocated
413 #if !defined RTLD_BOOTSTRAP && defined SHARED
414 /* Bootstrap map doesn't have l_relocated set for it. */
415 && sym_map != &GL(dl_rtld_map)
416 #endif
418 offset = sym_map->l_addr;
420 /* For PPC64, fixup_plt copies the function descriptor from opd
421 over the corresponding PLT entry.
422 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
423 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
424 so for thread safety we write them before changing fd_func. */
426 plt->fd_aux = rel->fd_aux + offset;
427 plt->fd_toc = rel->fd_toc + offset;
428 PPC_DCBST (&plt->fd_aux);
429 PPC_DCBST (&plt->fd_toc);
430 PPC_SYNC;
432 plt->fd_func = rel->fd_func + offset;
433 PPC_DCBST (&plt->fd_func);
434 PPC_SYNC;
436 return finaladdr;
439 static inline void __attribute__ ((always_inline))
440 elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
442 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
443 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
445 plt->fd_func = rel->fd_func;
446 plt->fd_aux = rel->fd_aux;
447 plt->fd_toc = rel->fd_toc;
448 PPC_DCBST (&plt->fd_func);
449 PPC_DCBST (&plt->fd_aux);
450 PPC_DCBST (&plt->fd_toc);
451 PPC_SYNC;
454 /* Return the final value of a plt relocation. */
455 static inline Elf64_Addr
456 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
457 Elf64_Addr value)
459 return value + reloc->r_addend;
463 /* Names of the architecture-specific auditing callback functions. */
464 #define ARCH_LA_PLTENTER ppc64_gnu_pltenter
465 #define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
467 #endif /* dl_machine_h */
469 #ifdef RESOLVE_MAP
471 #define PPC_LO(v) ((v) & 0xffff)
472 #define PPC_HI(v) (((v) >> 16) & 0xffff)
473 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
474 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
475 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
476 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
477 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
478 #define BIT_INSERT(var, val, mask) \
479 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
481 #define dont_expect(X) __builtin_expect ((X), 0)
483 extern void _dl_reloc_overflow (struct link_map *map,
484 const char *name,
485 Elf64_Addr *const reloc_addr,
486 const Elf64_Sym *refsym)
487 attribute_hidden;
489 auto inline void __attribute__ ((always_inline))
490 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
491 void *const reloc_addr_arg)
493 Elf64_Addr *const reloc_addr = reloc_addr_arg;
494 *reloc_addr = l_addr + reloc->r_addend;
497 #if !defined RTLD_BOOTSTRAP || USE___THREAD
498 /* This computes the value used by TPREL* relocs. */
499 auto inline Elf64_Addr __attribute__ ((always_inline, const))
500 elf_machine_tprel (struct link_map *map,
501 struct link_map *sym_map,
502 const Elf64_Sym *sym,
503 const Elf64_Rela *reloc)
505 # ifndef RTLD_BOOTSTRAP
506 if (sym_map)
508 CHECK_STATIC_TLS (map, sym_map);
509 # endif
510 return TLS_TPREL_VALUE (sym_map, sym, reloc);
511 # ifndef RTLD_BOOTSTRAP
513 # endif
514 return 0;
516 #endif
518 /* Perform the relocation specified by RELOC and SYM (which is fully
519 resolved). MAP is the object containing the reloc. */
520 auto inline void __attribute__ ((always_inline))
521 elf_machine_rela (struct link_map *map,
522 const Elf64_Rela *reloc,
523 const Elf64_Sym *sym,
524 const struct r_found_version *version,
525 void *const reloc_addr_arg)
527 Elf64_Addr *const reloc_addr = reloc_addr_arg;
528 const int r_type = ELF64_R_TYPE (reloc->r_info);
529 #ifndef RTLD_BOOTSTRAP
530 const Elf64_Sym *const refsym = sym;
531 #endif
533 if (r_type == R_PPC64_RELATIVE)
535 *reloc_addr = map->l_addr + reloc->r_addend;
536 return;
539 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
540 return;
542 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt. */
543 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
544 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
545 + reloc->r_addend);
547 /* For relocs that don't edit code, return.
548 For relocs that might edit instructions, break from the switch. */
549 switch (r_type)
551 case R_PPC64_ADDR64:
552 case R_PPC64_GLOB_DAT:
553 *reloc_addr = value;
554 return;
556 case R_PPC64_JMP_SLOT:
557 #ifdef RESOLVE_CONFLICT_FIND_MAP
558 elf_machine_plt_conflict (reloc_addr, value);
559 #else
560 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
561 #endif
562 return;
564 #if !defined RTLD_BOOTSTRAP || USE___THREAD
565 case R_PPC64_DTPMOD64:
566 # ifdef RTLD_BOOTSTRAP
567 /* During startup the dynamic linker is always index 1. */
568 *reloc_addr = 1;
569 # else
570 /* Get the information from the link map returned by the
571 resolve function. */
572 if (sym_map != NULL)
573 *reloc_addr = sym_map->l_tls_modid;
574 # endif
575 return;
577 case R_PPC64_DTPREL64:
578 /* During relocation all TLS symbols are defined and used.
579 Therefore the offset is already correct. */
580 # ifndef RTLD_BOOTSTRAP
581 if (sym_map != NULL)
582 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
583 # endif
584 return;
586 case R_PPC64_TPREL64:
587 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
588 return;
590 case R_PPC64_TPREL16_LO_DS:
591 value = elf_machine_tprel (map, sym_map, sym, reloc);
592 if (dont_expect ((value & 3) != 0))
593 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
594 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
595 value, 0xfffc);
596 break;
598 case R_PPC64_TPREL16_DS:
599 value = elf_machine_tprel (map, sym_map, sym, reloc);
600 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
601 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
602 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
603 value, 0xfffc);
604 break;
606 case R_PPC64_TPREL16:
607 value = elf_machine_tprel (map, sym_map, sym, reloc);
608 if (dont_expect ((value + 0x8000) >= 0x10000))
609 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
610 *(Elf64_Half *) reloc_addr = PPC_LO (value);
611 break;
613 case R_PPC64_TPREL16_LO:
614 value = elf_machine_tprel (map, sym_map, sym, reloc);
615 *(Elf64_Half *) reloc_addr = PPC_LO (value);
616 break;
618 case R_PPC64_TPREL16_HI:
619 value = elf_machine_tprel (map, sym_map, sym, reloc);
620 *(Elf64_Half *) reloc_addr = PPC_HI (value);
621 break;
623 case R_PPC64_TPREL16_HA:
624 value = elf_machine_tprel (map, sym_map, sym, reloc);
625 *(Elf64_Half *) reloc_addr = PPC_HA (value);
626 break;
628 case R_PPC64_TPREL16_HIGHER:
629 value = elf_machine_tprel (map, sym_map, sym, reloc);
630 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
631 break;
633 case R_PPC64_TPREL16_HIGHEST:
634 value = elf_machine_tprel (map, sym_map, sym, reloc);
635 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
636 break;
638 case R_PPC64_TPREL16_HIGHERA:
639 value = elf_machine_tprel (map, sym_map, sym, reloc);
640 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
641 break;
643 case R_PPC64_TPREL16_HIGHESTA:
644 value = elf_machine_tprel (map, sym_map, sym, reloc);
645 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
646 break;
647 #endif
649 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
650 case R_PPC64_ADDR16_LO_DS:
651 if (dont_expect ((value & 3) != 0))
652 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
653 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
654 break;
656 case R_PPC64_ADDR16_LO:
657 *(Elf64_Half *) reloc_addr = PPC_LO (value);
658 break;
660 case R_PPC64_ADDR16_HI:
661 *(Elf64_Half *) reloc_addr = PPC_HI (value);
662 break;
664 case R_PPC64_ADDR16_HA:
665 *(Elf64_Half *) reloc_addr = PPC_HA (value);
666 break;
668 case R_PPC64_ADDR30:
670 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
671 if (dont_expect ((delta + 0x80000000) >= 0x10000000
672 || (delta & 3) != 0))
673 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
674 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
676 break;
678 case R_PPC64_COPY:
679 if (dont_expect (sym == NULL))
680 /* This can happen in trace mode when an object could not be found. */
681 return;
682 if (dont_expect (sym->st_size > refsym->st_size
683 || (GLRO(dl_verbose)
684 && sym->st_size < refsym->st_size)))
686 const char *strtab;
688 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
689 _dl_error_printf ("%s: Symbol `%s' has different size" \
690 " in shared object," \
691 " consider re-linking\n",
692 _dl_argv[0] ?: "<program name unknown>",
693 strtab + refsym->st_name);
695 memcpy (reloc_addr_arg, (char *) value,
696 MIN (sym->st_size, refsym->st_size));
697 return;
699 case R_PPC64_UADDR64:
700 /* We are big-endian. */
701 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
702 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
703 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
704 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
705 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
706 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
707 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
708 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
709 return;
711 case R_PPC64_UADDR32:
712 /* We are big-endian. */
713 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
714 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
715 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
716 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
717 return;
719 case R_PPC64_ADDR32:
720 if (dont_expect ((value + 0x80000000) >= 0x10000000))
721 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
722 *(Elf64_Word *) reloc_addr = value;
723 return;
725 case R_PPC64_ADDR24:
726 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
727 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
728 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
729 break;
731 case R_PPC64_ADDR16:
732 if (dont_expect ((value + 0x8000) >= 0x10000))
733 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
734 *(Elf64_Half *) reloc_addr = value;
735 break;
737 case R_PPC64_UADDR16:
738 if (dont_expect ((value + 0x8000) >= 0x10000))
739 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
740 /* We are big-endian. */
741 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
742 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
743 break;
745 case R_PPC64_ADDR16_DS:
746 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
747 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
748 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
749 break;
751 case R_PPC64_ADDR16_HIGHER:
752 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
753 break;
755 case R_PPC64_ADDR16_HIGHEST:
756 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
757 break;
759 case R_PPC64_ADDR16_HIGHERA:
760 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
761 break;
763 case R_PPC64_ADDR16_HIGHESTA:
764 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
765 break;
767 case R_PPC64_ADDR14:
768 case R_PPC64_ADDR14_BRTAKEN:
769 case R_PPC64_ADDR14_BRNTAKEN:
771 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
772 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
773 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
774 BIT_INSERT (insn, value, 0xfffc);
775 if (r_type != R_PPC64_ADDR14)
777 insn &= ~(1 << 21);
778 if (r_type == R_PPC64_ADDR14_BRTAKEN)
779 insn |= 1 << 21;
780 if ((insn & (0x14 << 21)) == (0x04 << 21))
781 insn |= 0x02 << 21;
782 else if ((insn & (0x14 << 21)) == (0x10 << 21))
783 insn |= 0x08 << 21;
785 *(Elf64_Word *) reloc_addr = insn;
787 break;
789 case R_PPC64_REL32:
790 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
791 return;
793 case R_PPC64_REL64:
794 *reloc_addr = value - (Elf64_Addr) reloc_addr;
795 return;
796 #endif /* !RTLD_BOOTSTRAP */
798 default:
799 _dl_reloc_bad_type (map, r_type, 0);
800 return;
802 MODIFIED_CODE_NOQUEUE (reloc_addr);
805 auto inline void __attribute__ ((always_inline))
806 elf_machine_lazy_rel (struct link_map *map,
807 Elf64_Addr l_addr, const Elf64_Rela *reloc)
809 /* elf_machine_runtime_setup handles this. */
813 #endif /* RESOLVE */