]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/powerpc/powerpc64/dl-machine.h
Remove support for !USE___THREAD
[thirdparty/glibc.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
CommitLineData
a6963e69 1/* Machine-dependent ELF dynamic relocation inline functions.
cfc91acd 2 PowerPC64 version.
d063d164 3 Copyright 1995-2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
cfc91acd
RM
4 This file is part of the GNU C Library.
5
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.
10
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.
15
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. */
20
21#ifndef dl_machine_h
22#define dl_machine_h
23
24#define ELF_MACHINE_NAME "powerpc64"
25
26#include <assert.h>
27#include <sys/param.h>
790eed83 28#include <dl-tls.h>
590b40f7 29#include <sysdep.h>
cfc91acd
RM
30
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)
34
35/* A PowerPC64 function descriptor. The .plt (procedure linkage
36 table) and .opd (official procedure descriptor) sections are
37 arrays of these. */
38typedef struct
39{
40 Elf64_Addr fd_func;
41 Elf64_Addr fd_toc;
42 Elf64_Addr fd_aux;
43} Elf64_FuncDesc;
44
45#define ELF_MULT_MACHINES_SUPPORTED
46
47/* Return nonzero iff ELF header is compatible with the running host. */
48static inline int
49elf_machine_matches_host (const Elf64_Ehdr *ehdr)
50{
51 return ehdr->e_machine == EM_PPC64;
52}
53
54/* Return nonzero iff ELF header is compatible with the running host,
55 but not this loader. */
56static inline int
57elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
58{
59 return ehdr->e_machine == EM_PPC;
60}
61
62/* Return nonzero iff ELF header is compatible with the running host,
63 but not this loader. */
64static inline int
65elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
66{
67 return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
68}
69
70
71/* Return the run-time load address of the shared object, assuming it
72 was originally linked at zero. */
73static inline Elf64_Addr
74elf_machine_load_address (void) __attribute__ ((const));
75
76static inline Elf64_Addr
77elf_machine_load_address (void)
78{
79 Elf64_Addr ret;
80
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;
89}
90
91/* Return the link-time address of _DYNAMIC. */
92static inline Elf64_Addr
93elf_machine_dynamic (void)
94{
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() ;
102}
103
104#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
105
106/* The PLT uses Elf64_Rela relocs. */
107#define elf_machine_relplt elf_machine_rela
108
cfc91acd 109
ce6e047f
UD
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
118
cfc91acd
RM
119
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 \
c3d36434 124 asm (".pushsection \".text\"\n" \
cfc91acd 125" .align 2\n" \
590b40f7 126" .type " BODY_PREFIX "_start,@function\n" \
c3d36434 127" .pushsection \".opd\",\"aw\"\n" \
cfc91acd
RM
128" .align 3\n" \
129" .globl _start\n" \
590b40f7 130" " ENTRY_2(_start) "\n" \
cfc91acd 131"_start:\n" \
590b40f7 132" " OPD_ENT(_start) "\n" \
c3d36434 133" .popsection\n" \
590b40f7 134BODY_PREFIX "_start:\n" \
cfc91acd
RM
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. */ \
590b40f7 144" bl " DOT_PREFIX "_dl_start\n" \
cfc91acd
RM
145" nop\n" \
146/* Transfer control to _dl_start_user! */ \
590b40f7
UD
147" b " DOT_PREFIX "_dl_start_user\n" \
148".LT__start:\n" \
149" .long 0\n" \
cfc91acd 150" .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
590b40f7 151" .long .LT__start-" BODY_PREFIX "_start\n" \
cfc91acd
RM
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" \
590b40f7 157" " END_2(_start) "\n" \
cfc91acd 158" .globl _dl_start_user\n" \
c3d36434 159" .pushsection \".opd\",\"aw\"\n" \
cfc91acd 160"_dl_start_user:\n" \
590b40f7 161" " OPD_ENT(_dl_start_user) "\n" \
c3d36434
RM
162" .popsection\n" \
163" .pushsection \".toc\",\"aw\"\n" \
ce6e047f
UD
164DL_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" \
c3d36434 173" .popsection\n" \
590b40f7
UD
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!). */ \
181BODY_PREFIX "_dl_start_user:\n" \
cfc91acd
RM
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. */ \
590b40f7
UD
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" \
cfc91acd
RM
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" \
590b40f7 195" bl " DOT_PREFIX "_dl_init\n" \
cfc91acd
RM
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. */ \
ce6e047f 214" ld 7,.LC__dl_fini@toc(2)\n" \
cfc91acd
RM
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. \
590b40f7 220 Take the opportunity to clear LR, so anyone who accidentally \
cfc91acd
RM
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" \
cfc91acd 229/* Now, call the start function descriptor at r30... */ \
590b40f7
UD
230" .globl ._dl_main_dispatch\n" \
231"._dl_main_dispatch:\n" \
cfc91acd
RM
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" \
590b40f7 237".LT__dl_start_user:\n" \
cfc91acd
RM
238" .long 0\n" \
239" .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
590b40f7 240" .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n" \
cfc91acd
RM
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" \
590b40f7 246" " END_2(_dl_start_user) "\n" \
c3d36434 247" .popsection");
cfc91acd 248
d2207f32
UD
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.
cfc91acd 251
d2207f32
UD
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.
cfc91acd 270
d2207f32
UD
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. */
afafddab 275
cfc91acd 276#define elf_machine_type_class(type) \
d2207f32 277 (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
cfc91acd
RM
278
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
281
282/* The PowerPC never uses REL relocations. */
283#define ELF_MACHINE_NO_REL 1
284
285/* Stuff for the PLT. */
286#define PLT_INITIAL_ENTRY_WORDS 3
287#define GLINK_INITIAL_ENTRY_WORDS 8
288
289#define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
153cf972
UD
290#define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
291#define PPC_DCBF(where) asm volatile ("dcbf 0,%0" : : "r"(where) : "memory")
cfc91acd
RM
292#define PPC_SYNC asm volatile ("sync" : : : "memory")
293#define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
294#define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
295#define PPC_DIE asm volatile ("tweq 0,0")
296/* Use this when you've modified some code, but it won't be in the
297 instruction fetch queue (or when it doesn't matter if it is). */
298#define MODIFIED_CODE_NOQUEUE(where) \
299 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
300/* Use this when it might be in the instruction queue. */
301#define MODIFIED_CODE(where) \
302 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
303
304/* Set up the loaded object described by MAP so its unrelocated PLT
305 entries will jump to the on-demand fixup code in dl-runtime.c. */
9e365fe7 306static inline int __attribute__ ((always_inline))
cfc91acd
RM
307elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
308{
309 if (map->l_info[DT_JMPREL])
310 {
311 Elf64_Word i;
312 Elf64_Word *glink = NULL;
313 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
314 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
315 / sizeof (Elf64_Rela));
316 Elf64_Addr l_addr = map->l_addr;
317 Elf64_Dyn **info = map->l_info;
318 char *p;
319
320 extern void _dl_runtime_resolve (void);
321 extern void _dl_profile_resolve (void);
322
323 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
324 elf_get_dynamic_info takes care of the standard entries but
a6963e69 325 doesn't know exactly what to do with processor specific
cfc91acd
RM
326 entires. */
327 if (info[DT_PPC64(GLINK)] != NULL)
328 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
329
330 if (lazy)
331 {
332 /* The function descriptor of the appropriate trampline
333 routine is used to set the 1st and 2nd doubleword of the
334 plt_reserve. */
335 Elf64_FuncDesc *resolve_fd;
336 Elf64_Word glink_offset;
337 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
338 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
339 Elf64_Word offset;
340
341 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
342 : _dl_runtime_resolve);
4e2d5491
UD
343 if (profile && GLRO(dl_profile) != NULL
344 && _dl_name_match_p (GLRO(dl_profile), map))
cfc91acd
RM
345 /* This is the object we are looking for. Say that we really
346 want profiling and the timers are started. */
347 GL(dl_profile_map) = map;
348
349
350 /* We need to stuff the address/TOC of _dl_runtime_resolve
351 into doublewords 0 and 1 of plt_reserve. Then we need to
352 stuff the map address into doubleword 2 of plt_reserve.
353 This allows the GLINK0 code to transfer control to the
354 correct trampoline which will transfer control to fixup
355 in dl-machine.c. */
356 plt_reserve->fd_func = resolve_fd->fd_func;
357 plt_reserve->fd_toc = resolve_fd->fd_toc;
358 plt_reserve->fd_aux = (Elf64_Addr) map;
359#ifdef RTLD_BOOTSTRAP
360 /* When we're bootstrapping, the opd entry will not have
361 been relocated yet. */
362 plt_reserve->fd_func += l_addr;
363 plt_reserve->fd_toc += l_addr;
364#endif
a6963e69 365
cfc91acd
RM
366 /* Set up the lazy PLT entries. */
367 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
368 offset = PLT_INITIAL_ENTRY_WORDS;
369 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
370 for (i = 0; i < num_plt_entries; i++)
371 {
372
373 plt[offset] = (Elf64_Xword) &glink[glink_offset];
374 offset += 3;
375 /* The first 32k entries of glink can set an index and
376 branch using two instructions; Past that point,
377 glink uses three instructions. */
378 if (i < 0x8000)
d063d164 379 glink_offset += 2;
cfc91acd 380 else
d063d164 381 glink_offset += 3;
cfc91acd
RM
382 }
383
384 /* Now, we've modified data. We need to write the changes from
385 the data cache to a second-level unified cache, then make
386 sure that stale data in the instruction cache is removed.
387 (In a multiprocessor system, the effect is more complex.)
388 Most of the PLT shouldn't be in the instruction cache, but
389 there may be a little overlap at the start and the end.
390
391 Assumes that dcbst and icbi apply to lines of 16 bytes or
392 more. Current known line sizes are 16, 32, and 128 bytes. */
393
394 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
395 PPC_DCBST (p);
396 PPC_SYNC;
397 }
398 }
399 return lazy;
400}
401
cfc91acd
RM
402/* Change the PLT entry whose reloc is 'reloc' to call the actual
403 routine. */
9e365fe7 404static inline Elf64_Addr __attribute__ ((always_inline))
cfc91acd
RM
405elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
406 const Elf64_Rela *reloc,
407 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
408{
409 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
410 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
411 Elf64_Addr offset = 0;
cfc91acd 412
153cf972
UD
413 PPC_DCBT (&plt->fd_aux);
414 PPC_DCBT (&plt->fd_func);
415 PPC_DCBT (&rel->fd_aux);
416 PPC_DCBT (&rel->fd_func);
417
cfc91acd
RM
418 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
419 if (sym_map == NULL)
420 return 0;
421
422 /* If the opd entry is not yet relocated (because it's from a shared
423 object that hasn't been processed yet), then manually reloc it. */
424 if (map != sym_map && !sym_map->l_relocated
bb0ddc2f 425#if !defined RTLD_BOOTSTRAP && defined SHARED
cfc91acd
RM
426 /* Bootstrap map doesn't have l_relocated set for it. */
427 && sym_map != &GL(dl_rtld_map)
428#endif
429 )
430 offset = sym_map->l_addr;
431
432 /* For PPC64, fixup_plt copies the function descriptor from opd
433 over the corresponding PLT entry.
434 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
435 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
436 so for thread safety we write them before changing fd_func. */
437
438 plt->fd_aux = rel->fd_aux + offset;
439 plt->fd_toc = rel->fd_toc + offset;
153cf972
UD
440 PPC_DCBF (&plt->fd_toc);
441 PPC_ISYNC;
cfc91acd
RM
442
443 plt->fd_func = rel->fd_func + offset;
444 PPC_DCBST (&plt->fd_func);
153cf972 445 PPC_ISYNC;
cfc91acd
RM
446
447 return finaladdr;
448}
449
9e365fe7 450static inline void __attribute__ ((always_inline))
06e2e0a7
UD
451elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
452{
453 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
454 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
455
456 plt->fd_func = rel->fd_func;
457 plt->fd_aux = rel->fd_aux;
458 plt->fd_toc = rel->fd_toc;
459 PPC_DCBST (&plt->fd_func);
460 PPC_DCBST (&plt->fd_aux);
461 PPC_DCBST (&plt->fd_toc);
462 PPC_SYNC;
463}
464
cfc91acd
RM
465/* Return the final value of a plt relocation. */
466static inline Elf64_Addr
467elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
468 Elf64_Addr value)
469{
470 return value + reloc->r_addend;
471}
a6963e69 472
82221992
UD
473
474/* Names of the architecture-specific auditing callback functions. */
475#define ARCH_LA_PLTENTER ppc64_gnu_pltenter
476#define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
477
cfc91acd
RM
478#endif /* dl_machine_h */
479
480#ifdef RESOLVE_MAP
481
482#define PPC_LO(v) ((v) & 0xffff)
483#define PPC_HI(v) (((v) >> 16) & 0xffff)
484#define PPC_HA(v) PPC_HI ((v) + 0x8000)
485#define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
486#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
487#define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
488#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
bb0ddc2f 489#define BIT_INSERT(var, val, mask) \
790eed83 490 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
cfc91acd
RM
491
492#define dont_expect(X) __builtin_expect ((X), 0)
493
494extern void _dl_reloc_overflow (struct link_map *map,
d063d164
UD
495 const char *name,
496 Elf64_Addr *const reloc_addr,
497 const Elf64_Sym *refsym)
498 attribute_hidden;
cfc91acd 499
7de00121 500auto inline void __attribute__ ((always_inline))
cfc91acd 501elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
87d254a7 502 void *const reloc_addr_arg)
cfc91acd 503{
87d254a7 504 Elf64_Addr *const reloc_addr = reloc_addr_arg;
cfc91acd 505 *reloc_addr = l_addr + reloc->r_addend;
afafddab 506}
cfc91acd 507
b3838ebd 508/* This computes the value used by TPREL* relocs. */
7de00121 509auto inline Elf64_Addr __attribute__ ((always_inline, const))
b3838ebd
RM
510elf_machine_tprel (struct link_map *map,
511 struct link_map *sym_map,
512 const Elf64_Sym *sym,
513 const Elf64_Rela *reloc)
514{
d063d164 515#ifndef RTLD_BOOTSTRAP
b3838ebd
RM
516 if (sym_map)
517 {
518 CHECK_STATIC_TLS (map, sym_map);
d063d164 519#endif
b3838ebd 520 return TLS_TPREL_VALUE (sym_map, sym, reloc);
d063d164 521#ifndef RTLD_BOOTSTRAP
b3838ebd 522 }
d063d164 523#endif
b3838ebd
RM
524 return 0;
525}
b3838ebd 526
77799d9d
AM
527/* Call function at address VALUE (an OPD entry) to resolve ifunc relocs. */
528auto inline Elf64_Addr __attribute__ ((always_inline))
529resolve_ifunc (Elf64_Addr value,
530 const struct link_map *map, const struct link_map *sym_map)
531{
872873d4 532#ifndef RESOLVE_CONFLICT_FIND_MAP
77799d9d
AM
533 /* The function we are calling may not yet have its opd entry relocated. */
534 Elf64_FuncDesc opd;
535 if (map != sym_map
872873d4 536# if !defined RTLD_BOOTSTRAP && defined SHARED
77799d9d
AM
537 /* Bootstrap map doesn't have l_relocated set for it. */
538 && sym_map != &GL(dl_rtld_map)
872873d4 539# endif
77799d9d
AM
540 && !sym_map->l_relocated)
541 {
542 Elf64_FuncDesc *func = (Elf64_FuncDesc *) value;
543 opd.fd_func = func->fd_func + sym_map->l_addr;
544 opd.fd_toc = func->fd_toc + sym_map->l_addr;
545 opd.fd_aux = func->fd_aux;
546 value = (Elf64_Addr) &opd;
547 }
872873d4 548#endif
77799d9d
AM
549 return ((Elf64_Addr (*) (void)) value) ();
550}
551
cfc91acd
RM
552/* Perform the relocation specified by RELOC and SYM (which is fully
553 resolved). MAP is the object containing the reloc. */
7de00121 554auto inline void __attribute__ ((always_inline))
cfc91acd
RM
555elf_machine_rela (struct link_map *map,
556 const Elf64_Rela *reloc,
557 const Elf64_Sym *sym,
558 const struct r_found_version *version,
87d254a7 559 void *const reloc_addr_arg)
cfc91acd 560{
87d254a7 561 Elf64_Addr *const reloc_addr = reloc_addr_arg;
bb0ddc2f 562 const int r_type = ELF64_R_TYPE (reloc->r_info);
cfc91acd
RM
563#ifndef RTLD_BOOTSTRAP
564 const Elf64_Sym *const refsym = sym;
cfc91acd
RM
565#endif
566
567 if (r_type == R_PPC64_RELATIVE)
568 {
afafddab 569 *reloc_addr = map->l_addr + reloc->r_addend;
cfc91acd
RM
570 return;
571 }
572
bb0ddc2f 573 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
cfc91acd
RM
574 return;
575
77799d9d
AM
576 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
577 and STT_GNU_IFUNC. */
bb0ddc2f 578 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
b3838ebd 579 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
790eed83 580 + reloc->r_addend);
cfc91acd 581
77799d9d
AM
582 if (sym != NULL
583 && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
584 && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
585 value = resolve_ifunc (value, map, sym_map);
586
bb0ddc2f
RM
587 /* For relocs that don't edit code, return.
588 For relocs that might edit instructions, break from the switch. */
cfc91acd
RM
589 switch (r_type)
590 {
591 case R_PPC64_ADDR64:
592 case R_PPC64_GLOB_DAT:
a6963e69 593 *reloc_addr = value;
cfc91acd 594 return;
a6963e69 595
77799d9d
AM
596 case R_PPC64_IRELATIVE:
597 value = resolve_ifunc (value, map, sym_map);
598 *reloc_addr = value;
599 return;
600
601 case R_PPC64_JMP_IREL:
602 value = resolve_ifunc (value, map, sym_map);
603 /* Fall thru */
bb0ddc2f
RM
604 case R_PPC64_JMP_SLOT:
605#ifdef RESOLVE_CONFLICT_FIND_MAP
06e2e0a7
UD
606 elf_machine_plt_conflict (reloc_addr, value);
607#else
bb0ddc2f 608 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
06e2e0a7 609#endif
bb0ddc2f 610 return;
afafddab
RM
611
612 case R_PPC64_DTPMOD64:
d063d164 613#ifdef RTLD_BOOTSTRAP
b3838ebd 614 /* During startup the dynamic linker is always index 1. */
afafddab 615 *reloc_addr = 1;
d063d164 616#else
b3838ebd
RM
617 /* Get the information from the link map returned by the
618 resolve function. */
afafddab 619 if (sym_map != NULL)
d063d164
UD
620 *reloc_addr = sym_map->l_tls_modid;
621#endif
afafddab 622 return;
a6963e69 623
3a601d31 624 case R_PPC64_DTPREL64:
bb0ddc2f 625 /* During relocation all TLS symbols are defined and used.
d063d164
UD
626 Therefore the offset is already correct. */
627#ifndef RTLD_BOOTSTRAP
22163624
UD
628 if (sym_map != NULL)
629 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
d063d164 630#endif
b3838ebd
RM
631 return;
632
3a601d31 633 case R_PPC64_TPREL64:
b3838ebd
RM
634 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
635 return;
636
637 case R_PPC64_TPREL16_LO_DS:
638 value = elf_machine_tprel (map, sym_map, sym, reloc);
639 if (dont_expect ((value & 3) != 0))
d063d164 640 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
817328ee 641 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
b3838ebd
RM
642 break;
643
644 case R_PPC64_TPREL16_DS:
645 value = elf_machine_tprel (map, sym_map, sym, reloc);
646 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
d063d164 647 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
817328ee 648 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
b3838ebd
RM
649 break;
650
651 case R_PPC64_TPREL16:
652 value = elf_machine_tprel (map, sym_map, sym, reloc);
653 if (dont_expect ((value + 0x8000) >= 0x10000))
d063d164 654 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
b3838ebd
RM
655 *(Elf64_Half *) reloc_addr = PPC_LO (value);
656 break;
657
658 case R_PPC64_TPREL16_LO:
659 value = elf_machine_tprel (map, sym_map, sym, reloc);
660 *(Elf64_Half *) reloc_addr = PPC_LO (value);
661 break;
662
663 case R_PPC64_TPREL16_HI:
664 value = elf_machine_tprel (map, sym_map, sym, reloc);
665 *(Elf64_Half *) reloc_addr = PPC_HI (value);
666 break;
667
668 case R_PPC64_TPREL16_HA:
669 value = elf_machine_tprel (map, sym_map, sym, reloc);
670 *(Elf64_Half *) reloc_addr = PPC_HA (value);
671 break;
672
673 case R_PPC64_TPREL16_HIGHER:
674 value = elf_machine_tprel (map, sym_map, sym, reloc);
675 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
676 break;
677
678 case R_PPC64_TPREL16_HIGHEST:
679 value = elf_machine_tprel (map, sym_map, sym, reloc);
680 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
681 break;
682
683 case R_PPC64_TPREL16_HIGHERA:
684 value = elf_machine_tprel (map, sym_map, sym, reloc);
685 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
686 break;
687
688 case R_PPC64_TPREL16_HIGHESTA:
689 value = elf_machine_tprel (map, sym_map, sym, reloc);
690 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
bb0ddc2f 691 break;
cfc91acd
RM
692
693#ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
694 case R_PPC64_ADDR16_LO_DS:
695 if (dont_expect ((value & 3) != 0))
d063d164 696 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
bb0ddc2f 697 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
afafddab
RM
698 break;
699
cfc91acd
RM
700 case R_PPC64_ADDR16_LO:
701 *(Elf64_Half *) reloc_addr = PPC_LO (value);
702 break;
703
704 case R_PPC64_ADDR16_HI:
705 *(Elf64_Half *) reloc_addr = PPC_HI (value);
706 break;
707
708 case R_PPC64_ADDR16_HA:
709 *(Elf64_Half *) reloc_addr = PPC_HA (value);
710 break;
711
b3838ebd 712 case R_PPC64_ADDR30:
cfc91acd 713 {
d063d164
UD
714 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
715 if (dont_expect ((delta + 0x80000000) >= 0x10000000
b3838ebd 716 || (delta & 3) != 0))
d063d164
UD
717 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
718 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
cfc91acd
RM
719 }
720 break;
721
722 case R_PPC64_COPY:
723 if (dont_expect (sym == NULL))
b3838ebd 724 /* This can happen in trace mode when an object could not be found. */
d063d164 725 return;
cfc91acd 726 if (dont_expect (sym->st_size > refsym->st_size
afdca0f2
UD
727 || (GLRO(dl_verbose)
728 && sym->st_size < refsym->st_size)))
b3838ebd 729 {
d063d164 730 const char *strtab;
cfc91acd 731
d063d164
UD
732 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
733 _dl_error_printf ("%s: Symbol `%s' has different size" \
734 " in shared object," \
735 " consider re-linking\n",
736 _dl_argv[0] ?: "<program name unknown>",
b3838ebd
RM
737 strtab + refsym->st_name);
738 }
87d254a7
AO
739 memcpy (reloc_addr_arg, (char *) value,
740 MIN (sym->st_size, refsym->st_size));
cfc91acd
RM
741 return;
742
743 case R_PPC64_UADDR64:
744 /* We are big-endian. */
87d254a7
AO
745 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
746 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
747 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
748 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
749 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
750 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
751 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
752 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
cfc91acd
RM
753 return;
754
755 case R_PPC64_UADDR32:
756 /* We are big-endian. */
87d254a7
AO
757 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
758 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
759 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
760 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
cfc91acd
RM
761 return;
762
b3838ebd
RM
763 case R_PPC64_ADDR32:
764 if (dont_expect ((value + 0x80000000) >= 0x10000000))
d063d164 765 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
b3838ebd
RM
766 *(Elf64_Word *) reloc_addr = value;
767 return;
768
cfc91acd
RM
769 case R_PPC64_ADDR24:
770 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
d063d164 771 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
bb0ddc2f 772 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
cfc91acd
RM
773 break;
774
775 case R_PPC64_ADDR16:
776 if (dont_expect ((value + 0x8000) >= 0x10000))
d063d164 777 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
cfc91acd
RM
778 *(Elf64_Half *) reloc_addr = value;
779 break;
780
781 case R_PPC64_UADDR16:
782 if (dont_expect ((value + 0x8000) >= 0x10000))
d063d164 783 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
cfc91acd 784 /* We are big-endian. */
87d254a7
AO
785 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
786 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
cfc91acd
RM
787 break;
788
789 case R_PPC64_ADDR16_DS:
790 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
d063d164 791 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
bb0ddc2f 792 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
afafddab
RM
793 break;
794
cfc91acd
RM
795 case R_PPC64_ADDR16_HIGHER:
796 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
797 break;
798
799 case R_PPC64_ADDR16_HIGHEST:
800 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
801 break;
802
803 case R_PPC64_ADDR16_HIGHERA:
804 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
805 break;
806
807 case R_PPC64_ADDR16_HIGHESTA:
808 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
809 break;
810
811 case R_PPC64_ADDR14:
812 case R_PPC64_ADDR14_BRTAKEN:
813 case R_PPC64_ADDR14_BRNTAKEN:
814 {
d063d164 815 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
63c7a7e8 816 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
d063d164
UD
817 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
818 BIT_INSERT (insn, value, 0xfffc);
819 if (r_type != R_PPC64_ADDR14)
bb0ddc2f
RM
820 {
821 insn &= ~(1 << 21);
822 if (r_type == R_PPC64_ADDR14_BRTAKEN)
823 insn |= 1 << 21;
824 if ((insn & (0x14 << 21)) == (0x04 << 21))
825 insn |= 0x02 << 21;
826 else if ((insn & (0x14 << 21)) == (0x10 << 21))
827 insn |= 0x08 << 21;
828 }
d063d164 829 *(Elf64_Word *) reloc_addr = insn;
cfc91acd
RM
830 }
831 break;
832
833 case R_PPC64_REL32:
b3838ebd
RM
834 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
835 return;
836
837 case R_PPC64_REL64:
838 *reloc_addr = value - (Elf64_Addr) reloc_addr;
cfc91acd
RM
839 return;
840#endif /* !RTLD_BOOTSTRAP */
841
842 default:
843 _dl_reloc_bad_type (map, r_type, 0);
844 return;
845 }
846 MODIFIED_CODE_NOQUEUE (reloc_addr);
847}
848
7de00121 849auto inline void __attribute__ ((always_inline))
7ba7c829
UD
850elf_machine_lazy_rel (struct link_map *map,
851 Elf64_Addr l_addr, const Elf64_Rela *reloc)
852{
853 /* elf_machine_runtime_setup handles this. */
854}
855
7de00121 856
cfc91acd 857#endif /* RESOLVE */