(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[glibc.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
blob3fcf77df71bce47a640407940f89df4920bc6f85
1 /* Machine-dependent ELF dynamic relocation inline functions.
2 PowerPC64 version.
3 Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
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
110 /* This code gets called via a .glink stub which loads PLT0. It is
111 used in dl-runtime.c to call the `fixup' function and then redirect
112 to the address `fixup' returns.
114 Enter with r0 = plt reloc index,
115 r2 = ld.so tocbase,
116 r11 = ld.so link map. */
118 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
119 asm (".section \".text\"\n" \
120 " .align 2\n" \
121 " .type " BODY_PREFIX #tramp_name ",@function\n" \
122 " .section \".opd\",\"aw\"\n" \
123 " .align 3\n" \
124 " .globl " #tramp_name "\n" \
125 " " ENTRY_2(tramp_name) "\n" \
126 #tramp_name ":\n" \
127 " " OPD_ENT(tramp_name) "\n" \
128 " .previous\n" \
129 BODY_PREFIX #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" \
133 " std 3,48(1)\n" \
134 " mr 3,11\n" \
135 " std 4,56(1)\n" \
136 " sldi 4,0,1\n" \
137 " std 5,64(1)\n" \
138 " add 4,4,0\n" \
139 " std 6,72(1)\n" \
140 " sldi 4,4,3\n" \
141 " std 7,80(1)\n" \
142 " mflr 0\n" \
143 " std 8,88(1)\n" \
144 /* Store the LR in the LR Save area of the previous frame. */ \
145 " std 0,128+16(1)\n" \
146 " mfcr 0\n" \
147 " std 9,96(1)\n" \
148 " std 10,104(1)\n" \
149 /* I'm almost certain we don't have to save cr... be safe. */ \
150 " std 0,8(1)\n" \
151 " bl " DOT_PREFIX #fixup_name "\n" \
152 /* Put the registers back. */ \
153 " ld 0,128+16(1)\n" \
154 " ld 10,104(1)\n" \
155 " ld 9,96(1)\n" \
156 " ld 8,88(1)\n" \
157 " ld 7,80(1)\n" \
158 " mtlr 0\n" \
159 " ld 0,8(1)\n" \
160 " ld 6,72(1)\n" \
161 " ld 5,64(1)\n" \
162 " ld 4,56(1)\n" \
163 " mtcrf 0xFF,0\n" \
164 /* Load the target address, toc and static chain reg from the function \
165 descriptor returned by fixup. */ \
166 " ld 0,0(3)\n" \
167 " ld 2,8(3)\n" \
168 " mtctr 0\n" \
169 " ld 11,16(3)\n" \
170 " ld 3,48(1)\n" \
171 /* Unwind the stack frame, and jump. */ \
172 " addi 1,1,128\n" \
173 " bctr\n" \
174 ".LT_" #tramp_name ":\n" \
175 " .long 0\n" \
176 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
177 " .long .LT_" #tramp_name "-" BODY_PREFIX #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" \
182 " .align 2\n" \
183 " " END_2(tramp_name) "\n" \
184 " .previous");
186 #ifndef PROF
187 #define ELF_MACHINE_RUNTIME_TRAMPOLINE \
188 TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
189 TRAMPOLINE_TEMPLATE (_dl_profile_resolve, profile_fixup);
190 #else
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);
195 #endif
197 #ifdef HAVE_INLINED_SYSCALLS
198 /* We do not need _dl_starting_up. */
199 # define DL_STARTING_UP_DEF
200 #else
201 # define DL_STARTING_UP_DEF \
202 ".LC__dl_starting_up:\n" \
203 " .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n"
204 #endif
207 /* Initial entry point code for the dynamic linker. The C function
208 `_dl_start' is the real entry point; its return value is the user
209 program's entry point. */
210 #define RTLD_START \
211 asm (".section \".text\"\n" \
212 " .align 2\n" \
213 " .type " BODY_PREFIX "_start,@function\n" \
214 " .section \".opd\",\"aw\"\n" \
215 " .align 3\n" \
216 " .globl _start\n" \
217 " " ENTRY_2(_start) "\n" \
218 "_start:\n" \
219 " " OPD_ENT(_start) "\n" \
220 " .previous\n" \
221 BODY_PREFIX "_start:\n" \
222 /* We start with the following on the stack, from top: \
223 argc (4 bytes); \
224 arguments for program (terminated by NULL); \
225 environment variables (terminated by NULL); \
226 arguments for the program loader. */ \
227 " mr 3,1\n" \
228 " li 4,0\n" \
229 " stdu 4,-128(1)\n" \
230 /* Call _dl_start with one parameter pointing at argc. */ \
231 " bl " DOT_PREFIX "_dl_start\n" \
232 " nop\n" \
233 /* Transfer control to _dl_start_user! */ \
234 " b " DOT_PREFIX "_dl_start_user\n" \
235 ".LT__start:\n" \
236 " .long 0\n" \
237 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
238 " .long .LT__start-" BODY_PREFIX "_start\n" \
239 " .short .LT__start_name_end-.LT__start_name_start\n" \
240 ".LT__start_name_start:\n" \
241 " .ascii \"_start\"\n" \
242 ".LT__start_name_end:\n" \
243 " .align 2\n" \
244 " " END_2(_start) "\n" \
245 " .globl _dl_start_user\n" \
246 " .section \".opd\",\"aw\"\n" \
247 "_dl_start_user:\n" \
248 " " OPD_ENT(_dl_start_user) "\n" \
249 " .previous\n" \
250 " .section \".toc\",\"aw\"\n" \
251 DL_STARTING_UP_DEF \
252 ".LC__rtld_global:\n" \
253 " .tc _rtld_global[TC],_rtld_global\n" \
254 ".LC__dl_argc:\n" \
255 " .tc _dl_argc[TC],_dl_argc\n" \
256 ".LC__dl_argv:\n" \
257 " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
258 ".LC__dl_fini:\n" \
259 " .tc _dl_fini[TC],_dl_fini\n" \
260 " .previous\n" \
261 " .type " BODY_PREFIX "_dl_start_user,@function\n" \
262 " " ENTRY_2(_dl_start_user) "\n" \
263 /* Now, we do our main work of calling initialisation procedures. \
264 The ELF ABI doesn't say anything about parameters for these, \
265 so we just pass argc, argv, and the environment. \
266 Changing these is strongly discouraged (not least because argc is \
267 passed by value!). */ \
268 BODY_PREFIX "_dl_start_user:\n" \
269 /* the address of _start in r30. */ \
270 " mr 30,3\n" \
271 /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
272 " ld 28,.LC__rtld_global@toc(2)\n" \
273 " ld 29,.LC__dl_argc@toc(2)\n" \
274 " ld 27,.LC__dl_argv@toc(2)\n" \
275 /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \
276 " ld 3,0(28)\n" \
277 " lwa 4,0(29)\n" \
278 " ld 5,0(27)\n" \
279 " sldi 6,4,3\n" \
280 " add 6,5,6\n" \
281 " addi 6,6,8\n" \
282 " bl " DOT_PREFIX "_dl_init\n" \
283 " nop\n" \
284 /* Now, to conform to the ELF ABI, we have to: \
285 Pass argc (actually _dl_argc) in r3; */ \
286 " lwa 3,0(29)\n" \
287 /* Pass argv (actually _dl_argv) in r4; */ \
288 " ld 4,0(27)\n" \
289 /* Pass argv+argc+1 in r5; */ \
290 " sldi 5,3,3\n" \
291 " add 6,4,5\n" \
292 " addi 5,6,8\n" \
293 /* Pass the auxilary vector in r6. This is passed to us just after \
294 _envp. */ \
295 "2: ldu 0,8(6)\n" \
296 " cmpdi 0,0\n" \
297 " bne 2b\n" \
298 " addi 6,6,8\n" \
299 /* Pass a termination function pointer (in this case _dl_fini) in \
300 r7. */ \
301 " ld 7,.LC__dl_fini@toc(2)\n" \
302 /* Pass the stack pointer in r1 (so far so good), pointing to a NULL \
303 value. This lets our startup code distinguish between a program \
304 linked statically, which linux will call with argc on top of the \
305 stack which will hopefully never be zero, and a dynamically linked \
306 program which will always have a NULL on the top of the stack. \
307 Take the opportunity to clear LR, so anyone who accidentally \
308 returns from _start gets SEGV. Also clear the next few words of \
309 the stack. */ \
310 " li 31,0\n" \
311 " std 31,0(1)\n" \
312 " mtlr 31\n" \
313 " std 31,8(1)\n" \
314 " std 31,16(1)\n" \
315 " std 31,24(1)\n" \
316 /* Now, call the start function descriptor at r30... */ \
317 " .globl ._dl_main_dispatch\n" \
318 "._dl_main_dispatch:\n" \
319 " ld 0,0(30)\n" \
320 " ld 2,8(30)\n" \
321 " mtctr 0\n" \
322 " ld 11,16(30)\n" \
323 " bctr\n" \
324 ".LT__dl_start_user:\n" \
325 " .long 0\n" \
326 " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
327 " .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n" \
328 " .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
329 ".LT__dl_start_user_name_start:\n" \
330 " .ascii \"_dl_start_user\"\n" \
331 ".LT__dl_start_user_name_end:\n" \
332 " .align 2\n" \
333 " " END_2(_dl_start_user) "\n" \
334 " .previous");
336 /* Nonzero iff TYPE should not be allowed to resolve to one of
337 the main executable's symbols, as for a COPY reloc. */
338 #define elf_machine_lookup_noexec_p(type) ((type) == R_PPC64_COPY)
340 /* Nonzero iff TYPE describes relocation of a PLT entry, so
341 PLT entries should not be allowed to define the value. */
342 #define elf_machine_lookup_noplt_p(type) ((type) == R_PPC64_JMP_SLOT)
344 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
345 PLT entries should not be allowed to define the value.
346 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
347 of the main executable's symbols, as for a COPY reloc. */
349 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
350 #define elf_machine_type_class(type) \
351 /* This covers all the TLS relocs, though most won't appear. */ \
352 (((((type) >= R_PPC64_DTPMOD64 && (type) <= R_PPC64_TPREL16_HIGHESTA) \
353 || (type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
354 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
355 #else
356 #define elf_machine_type_class(type) \
357 ((((type) == R_PPC64_ADDR24) * ELF_RTYPE_CLASS_PLT) \
358 | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
359 #endif
361 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
362 #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
364 /* The PowerPC never uses REL relocations. */
365 #define ELF_MACHINE_NO_REL 1
367 /* Stuff for the PLT. */
368 #define PLT_INITIAL_ENTRY_WORDS 3
369 #define GLINK_INITIAL_ENTRY_WORDS 8
371 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
372 #define PPC_SYNC asm volatile ("sync" : : : "memory")
373 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
374 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
375 #define PPC_DIE asm volatile ("tweq 0,0")
376 /* Use this when you've modified some code, but it won't be in the
377 instruction fetch queue (or when it doesn't matter if it is). */
378 #define MODIFIED_CODE_NOQUEUE(where) \
379 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
380 /* Use this when it might be in the instruction queue. */
381 #define MODIFIED_CODE(where) \
382 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
384 /* Set up the loaded object described by MAP so its unrelocated PLT
385 entries will jump to the on-demand fixup code in dl-runtime.c. */
386 static inline int __attribute__ ((always_inline))
387 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
389 if (map->l_info[DT_JMPREL])
391 Elf64_Word i;
392 Elf64_Word *glink = NULL;
393 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
394 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
395 / sizeof (Elf64_Rela));
396 Elf64_Addr l_addr = map->l_addr;
397 Elf64_Dyn **info = map->l_info;
398 char *p;
400 extern void _dl_runtime_resolve (void);
401 extern void _dl_profile_resolve (void);
403 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
404 elf_get_dynamic_info takes care of the standard entries but
405 doesn't know exactly what to do with processor specific
406 entires. */
407 if (info[DT_PPC64(GLINK)] != NULL)
408 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
410 if (lazy)
412 /* The function descriptor of the appropriate trampline
413 routine is used to set the 1st and 2nd doubleword of the
414 plt_reserve. */
415 Elf64_FuncDesc *resolve_fd;
416 Elf64_Word glink_offset;
417 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
418 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
419 Elf64_Word offset;
421 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
422 : _dl_runtime_resolve);
423 if (profile && _dl_name_match_p (GLRO(dl_profile), map))
424 /* This is the object we are looking for. Say that we really
425 want profiling and the timers are started. */
426 GL(dl_profile_map) = map;
429 /* We need to stuff the address/TOC of _dl_runtime_resolve
430 into doublewords 0 and 1 of plt_reserve. Then we need to
431 stuff the map address into doubleword 2 of plt_reserve.
432 This allows the GLINK0 code to transfer control to the
433 correct trampoline which will transfer control to fixup
434 in dl-machine.c. */
435 plt_reserve->fd_func = resolve_fd->fd_func;
436 plt_reserve->fd_toc = resolve_fd->fd_toc;
437 plt_reserve->fd_aux = (Elf64_Addr) map;
438 #ifdef RTLD_BOOTSTRAP
439 /* When we're bootstrapping, the opd entry will not have
440 been relocated yet. */
441 plt_reserve->fd_func += l_addr;
442 plt_reserve->fd_toc += l_addr;
443 #endif
445 /* Set up the lazy PLT entries. */
446 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
447 offset = PLT_INITIAL_ENTRY_WORDS;
448 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
449 for (i = 0; i < num_plt_entries; i++)
452 plt[offset] = (Elf64_Xword) &glink[glink_offset];
453 offset += 3;
454 /* The first 32k entries of glink can set an index and
455 branch using two instructions; Past that point,
456 glink uses three instructions. */
457 if (i < 0x8000)
458 glink_offset += 2;
459 else
460 glink_offset += 3;
463 /* Now, we've modified data. We need to write the changes from
464 the data cache to a second-level unified cache, then make
465 sure that stale data in the instruction cache is removed.
466 (In a multiprocessor system, the effect is more complex.)
467 Most of the PLT shouldn't be in the instruction cache, but
468 there may be a little overlap at the start and the end.
470 Assumes that dcbst and icbi apply to lines of 16 bytes or
471 more. Current known line sizes are 16, 32, and 128 bytes. */
473 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
474 PPC_DCBST (p);
475 PPC_SYNC;
478 return lazy;
481 /* Change the PLT entry whose reloc is 'reloc' to call the actual
482 routine. */
483 static inline Elf64_Addr __attribute__ ((always_inline))
484 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
485 const Elf64_Rela *reloc,
486 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
488 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
489 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
490 Elf64_Addr offset = 0;
492 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
493 if (sym_map == NULL)
494 return 0;
496 /* If the opd entry is not yet relocated (because it's from a shared
497 object that hasn't been processed yet), then manually reloc it. */
498 if (map != sym_map && !sym_map->l_relocated
499 #if !defined RTLD_BOOTSTRAP && defined SHARED
500 /* Bootstrap map doesn't have l_relocated set for it. */
501 && sym_map != &GL(dl_rtld_map)
502 #endif
504 offset = sym_map->l_addr;
506 /* For PPC64, fixup_plt copies the function descriptor from opd
507 over the corresponding PLT entry.
508 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
509 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
510 so for thread safety we write them before changing fd_func. */
512 plt->fd_aux = rel->fd_aux + offset;
513 plt->fd_toc = rel->fd_toc + offset;
514 PPC_DCBST (&plt->fd_aux);
515 PPC_DCBST (&plt->fd_toc);
516 PPC_SYNC;
518 plt->fd_func = rel->fd_func + offset;
519 PPC_DCBST (&plt->fd_func);
520 PPC_SYNC;
522 return finaladdr;
525 static inline void __attribute__ ((always_inline))
526 elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
528 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
529 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
531 plt->fd_func = rel->fd_func;
532 plt->fd_aux = rel->fd_aux;
533 plt->fd_toc = rel->fd_toc;
534 PPC_DCBST (&plt->fd_func);
535 PPC_DCBST (&plt->fd_aux);
536 PPC_DCBST (&plt->fd_toc);
537 PPC_SYNC;
540 /* Return the final value of a plt relocation. */
541 static inline Elf64_Addr
542 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
543 Elf64_Addr value)
545 return value + reloc->r_addend;
548 #endif /* dl_machine_h */
550 #ifdef RESOLVE_MAP
552 #define PPC_LO(v) ((v) & 0xffff)
553 #define PPC_HI(v) (((v) >> 16) & 0xffff)
554 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
555 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
556 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
557 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
558 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
559 #define BIT_INSERT(var, val, mask) \
560 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
562 #define dont_expect(X) __builtin_expect ((X), 0)
564 extern void _dl_reloc_overflow (struct link_map *map,
565 const char *name,
566 Elf64_Addr *const reloc_addr,
567 const Elf64_Sym *refsym)
568 attribute_hidden;
570 static inline void
571 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
572 void *const reloc_addr_arg)
574 Elf64_Addr *const reloc_addr = reloc_addr_arg;
575 *reloc_addr = l_addr + reloc->r_addend;
578 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
579 /* This computes the value used by TPREL* relocs. */
580 static Elf64_Addr __attribute__ ((const))
581 elf_machine_tprel (struct link_map *map,
582 struct link_map *sym_map,
583 const Elf64_Sym *sym,
584 const Elf64_Rela *reloc)
586 # ifndef RTLD_BOOTSTRAP
587 if (sym_map)
589 CHECK_STATIC_TLS (map, sym_map);
590 # endif
591 return TLS_TPREL_VALUE (sym_map, sym, reloc);
592 # ifndef RTLD_BOOTSTRAP
594 # endif
595 return 0;
597 #endif
599 /* Perform the relocation specified by RELOC and SYM (which is fully
600 resolved). MAP is the object containing the reloc. */
601 static inline void
602 elf_machine_rela (struct link_map *map,
603 const Elf64_Rela *reloc,
604 const Elf64_Sym *sym,
605 const struct r_found_version *version,
606 void *const reloc_addr_arg)
608 Elf64_Addr *const reloc_addr = reloc_addr_arg;
609 const int r_type = ELF64_R_TYPE (reloc->r_info);
610 #ifndef RTLD_BOOTSTRAP
611 const Elf64_Sym *const refsym = sym;
612 #endif
614 if (r_type == R_PPC64_RELATIVE)
616 *reloc_addr = map->l_addr + reloc->r_addend;
617 return;
620 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
621 return;
623 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt. */
624 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
625 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
626 + reloc->r_addend);
628 /* For relocs that don't edit code, return.
629 For relocs that might edit instructions, break from the switch. */
630 switch (r_type)
632 case R_PPC64_ADDR64:
633 case R_PPC64_GLOB_DAT:
634 *reloc_addr = value;
635 return;
637 case R_PPC64_JMP_SLOT:
638 #ifdef RESOLVE_CONFLICT_FIND_MAP
639 elf_machine_plt_conflict (reloc_addr, value);
640 #else
641 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
642 #endif
643 return;
645 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
646 case R_PPC64_DTPMOD64:
647 # ifdef RTLD_BOOTSTRAP
648 /* During startup the dynamic linker is always index 1. */
649 *reloc_addr = 1;
650 # else
651 /* Get the information from the link map returned by the
652 resolve function. */
653 if (sym_map != NULL)
654 *reloc_addr = sym_map->l_tls_modid;
655 # endif
656 return;
658 case R_PPC64_DTPREL64:
659 /* During relocation all TLS symbols are defined and used.
660 Therefore the offset is already correct. */
661 # ifndef RTLD_BOOTSTRAP
662 if (sym_map != NULL)
663 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
664 # endif
665 return;
667 case R_PPC64_TPREL64:
668 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
669 return;
671 case R_PPC64_TPREL16_LO_DS:
672 value = elf_machine_tprel (map, sym_map, sym, reloc);
673 if (dont_expect ((value & 3) != 0))
674 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
675 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
676 value, 0xfffc);
677 break;
679 case R_PPC64_TPREL16_DS:
680 value = elf_machine_tprel (map, sym_map, sym, reloc);
681 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
682 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
683 *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
684 value, 0xfffc);
685 break;
687 case R_PPC64_TPREL16:
688 value = elf_machine_tprel (map, sym_map, sym, reloc);
689 if (dont_expect ((value + 0x8000) >= 0x10000))
690 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
691 *(Elf64_Half *) reloc_addr = PPC_LO (value);
692 break;
694 case R_PPC64_TPREL16_LO:
695 value = elf_machine_tprel (map, sym_map, sym, reloc);
696 *(Elf64_Half *) reloc_addr = PPC_LO (value);
697 break;
699 case R_PPC64_TPREL16_HI:
700 value = elf_machine_tprel (map, sym_map, sym, reloc);
701 *(Elf64_Half *) reloc_addr = PPC_HI (value);
702 break;
704 case R_PPC64_TPREL16_HA:
705 value = elf_machine_tprel (map, sym_map, sym, reloc);
706 *(Elf64_Half *) reloc_addr = PPC_HA (value);
707 break;
709 case R_PPC64_TPREL16_HIGHER:
710 value = elf_machine_tprel (map, sym_map, sym, reloc);
711 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
712 break;
714 case R_PPC64_TPREL16_HIGHEST:
715 value = elf_machine_tprel (map, sym_map, sym, reloc);
716 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
717 break;
719 case R_PPC64_TPREL16_HIGHERA:
720 value = elf_machine_tprel (map, sym_map, sym, reloc);
721 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
722 break;
724 case R_PPC64_TPREL16_HIGHESTA:
725 value = elf_machine_tprel (map, sym_map, sym, reloc);
726 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
727 break;
728 #endif /* USE_TLS etc. */
730 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
731 case R_PPC64_ADDR16_LO_DS:
732 if (dont_expect ((value & 3) != 0))
733 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
734 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
735 break;
737 case R_PPC64_ADDR16_LO:
738 *(Elf64_Half *) reloc_addr = PPC_LO (value);
739 break;
741 case R_PPC64_ADDR16_HI:
742 *(Elf64_Half *) reloc_addr = PPC_HI (value);
743 break;
745 case R_PPC64_ADDR16_HA:
746 *(Elf64_Half *) reloc_addr = PPC_HA (value);
747 break;
749 case R_PPC64_ADDR30:
751 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
752 if (dont_expect ((delta + 0x80000000) >= 0x10000000
753 || (delta & 3) != 0))
754 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
755 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
757 break;
759 case R_PPC64_COPY:
760 if (dont_expect (sym == NULL))
761 /* This can happen in trace mode when an object could not be found. */
762 return;
763 if (dont_expect (sym->st_size > refsym->st_size
764 || (GLRO(dl_verbose)
765 && sym->st_size < refsym->st_size)))
767 const char *strtab;
769 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
770 _dl_error_printf ("%s: Symbol `%s' has different size" \
771 " in shared object," \
772 " consider re-linking\n",
773 _dl_argv[0] ?: "<program name unknown>",
774 strtab + refsym->st_name);
776 memcpy (reloc_addr_arg, (char *) value,
777 MIN (sym->st_size, refsym->st_size));
778 return;
780 case R_PPC64_UADDR64:
781 /* We are big-endian. */
782 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
783 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
784 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
785 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
786 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
787 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
788 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
789 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
790 return;
792 case R_PPC64_UADDR32:
793 /* We are big-endian. */
794 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
795 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
796 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
797 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
798 return;
800 case R_PPC64_ADDR32:
801 if (dont_expect ((value + 0x80000000) >= 0x10000000))
802 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
803 *(Elf64_Word *) reloc_addr = value;
804 return;
806 case R_PPC64_ADDR24:
807 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
808 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
809 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
810 break;
812 case R_PPC64_ADDR16:
813 if (dont_expect ((value + 0x8000) >= 0x10000))
814 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
815 *(Elf64_Half *) reloc_addr = value;
816 break;
818 case R_PPC64_UADDR16:
819 if (dont_expect ((value + 0x8000) >= 0x10000))
820 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
821 /* We are big-endian. */
822 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
823 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
824 break;
826 case R_PPC64_ADDR16_DS:
827 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
828 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
829 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
830 break;
832 case R_PPC64_ADDR16_HIGHER:
833 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
834 break;
836 case R_PPC64_ADDR16_HIGHEST:
837 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
838 break;
840 case R_PPC64_ADDR16_HIGHERA:
841 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
842 break;
844 case R_PPC64_ADDR16_HIGHESTA:
845 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
846 break;
848 case R_PPC64_ADDR14:
849 case R_PPC64_ADDR14_BRTAKEN:
850 case R_PPC64_ADDR14_BRNTAKEN:
852 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
853 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
854 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
855 BIT_INSERT (insn, value, 0xfffc);
856 if (r_type != R_PPC64_ADDR14)
858 insn &= ~(1 << 21);
859 if (r_type == R_PPC64_ADDR14_BRTAKEN)
860 insn |= 1 << 21;
861 if ((insn & (0x14 << 21)) == (0x04 << 21))
862 insn |= 0x02 << 21;
863 else if ((insn & (0x14 << 21)) == (0x10 << 21))
864 insn |= 0x08 << 21;
866 *(Elf64_Word *) reloc_addr = insn;
868 break;
870 case R_PPC64_REL32:
871 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
872 return;
874 case R_PPC64_REL64:
875 *reloc_addr = value - (Elf64_Addr) reloc_addr;
876 return;
877 #endif /* !RTLD_BOOTSTRAP */
879 default:
880 _dl_reloc_bad_type (map, r_type, 0);
881 return;
883 MODIFIED_CODE_NOQUEUE (reloc_addr);
886 static inline void
887 elf_machine_lazy_rel (struct link_map *map,
888 Elf64_Addr l_addr, const Elf64_Rela *reloc)
890 /* elf_machine_runtime_setup handles this. */
893 #endif /* RESOLVE */