]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/powerpc/powerpc64/dl-machine.h
Update copyright notices with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / powerpc / powerpc64 / dl-machine.h
CommitLineData
a6963e69 1/* Machine-dependent ELF dynamic relocation inline functions.
cfc91acd 2 PowerPC64 version.
568035b7 3 Copyright 1995-2013 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
59ba27a6
PE
17 License along with the GNU C Library; see the file COPYING.LIB. If
18 not, see <http://www.gnu.org/licenses/>. */
cfc91acd
RM
19
20#ifndef dl_machine_h
21#define dl_machine_h
22
23#define ELF_MACHINE_NAME "powerpc64"
24
25#include <assert.h>
26#include <sys/param.h>
790eed83 27#include <dl-tls.h>
590b40f7 28#include <sysdep.h>
cfc91acd
RM
29
30/* Translate a processor specific dynamic tag to the index
31 in l_info array. */
32#define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
33
34/* A PowerPC64 function descriptor. The .plt (procedure linkage
35 table) and .opd (official procedure descriptor) sections are
36 arrays of these. */
37typedef struct
38{
39 Elf64_Addr fd_func;
40 Elf64_Addr fd_toc;
41 Elf64_Addr fd_aux;
42} Elf64_FuncDesc;
43
44#define ELF_MULT_MACHINES_SUPPORTED
45
46/* Return nonzero iff ELF header is compatible with the running host. */
47static inline int
48elf_machine_matches_host (const Elf64_Ehdr *ehdr)
49{
50 return ehdr->e_machine == EM_PPC64;
51}
52
53/* Return nonzero iff ELF header is compatible with the running host,
54 but not this loader. */
55static inline int
56elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
57{
58 return ehdr->e_machine == EM_PPC;
59}
60
61/* Return nonzero iff ELF header is compatible with the running host,
62 but not this loader. */
63static inline int
64elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
65{
66 return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
67}
68
69
70/* Return the run-time load address of the shared object, assuming it
71 was originally linked at zero. */
72static inline Elf64_Addr
73elf_machine_load_address (void) __attribute__ ((const));
74
75static inline Elf64_Addr
76elf_machine_load_address (void)
77{
78 Elf64_Addr ret;
79
80 /* The first entry in .got (and thus the first entry in .toc) is the
81 link-time TOC_base, ie. r2. So the difference between that and
82 the current r2 set by the kernel is how far the shared lib has
83 moved. */
84 asm ( " ld %0,-32768(2)\n"
85 " subf %0,%0,2\n"
86 : "=r" (ret));
87 return ret;
88}
89
90/* Return the link-time address of _DYNAMIC. */
91static inline Elf64_Addr
92elf_machine_dynamic (void)
93{
94 Elf64_Addr runtime_dynamic;
95 /* It's easier to get the run-time address. */
96 asm ( " addis %0,2,_DYNAMIC@toc@ha\n"
97 " addi %0,%0,_DYNAMIC@toc@l\n"
98 : "=b" (runtime_dynamic));
99 /* Then subtract off the load address offset. */
100 return runtime_dynamic - elf_machine_load_address() ;
101}
102
103#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
104
105/* The PLT uses Elf64_Rela relocs. */
106#define elf_machine_relplt elf_machine_rela
107
cfc91acd 108
ce6e047f
UD
109#ifdef HAVE_INLINED_SYSCALLS
110/* We do not need _dl_starting_up. */
111# define DL_STARTING_UP_DEF
112#else
113# define DL_STARTING_UP_DEF \
114".LC__dl_starting_up:\n" \
115" .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n"
116#endif
117
cfc91acd
RM
118
119/* Initial entry point code for the dynamic linker. The C function
120 `_dl_start' is the real entry point; its return value is the user
121 program's entry point. */
122#define RTLD_START \
c3d36434 123 asm (".pushsection \".text\"\n" \
cfc91acd 124" .align 2\n" \
590b40f7 125" .type " BODY_PREFIX "_start,@function\n" \
c3d36434 126" .pushsection \".opd\",\"aw\"\n" \
cfc91acd
RM
127" .align 3\n" \
128" .globl _start\n" \
590b40f7 129" " ENTRY_2(_start) "\n" \
cfc91acd 130"_start:\n" \
590b40f7 131" " OPD_ENT(_start) "\n" \
c3d36434 132" .popsection\n" \
590b40f7 133BODY_PREFIX "_start:\n" \
cfc91acd
RM
134/* We start with the following on the stack, from top: \
135 argc (4 bytes); \
136 arguments for program (terminated by NULL); \
137 environment variables (terminated by NULL); \
138 arguments for the program loader. */ \
139" mr 3,1\n" \
140" li 4,0\n" \
141" stdu 4,-128(1)\n" \
142/* Call _dl_start with one parameter pointing at argc. */ \
590b40f7 143" bl " DOT_PREFIX "_dl_start\n" \
cfc91acd
RM
144" nop\n" \
145/* Transfer control to _dl_start_user! */ \
590b40f7
UD
146" b " DOT_PREFIX "_dl_start_user\n" \
147".LT__start:\n" \
148" .long 0\n" \
cfc91acd 149" .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
590b40f7 150" .long .LT__start-" BODY_PREFIX "_start\n" \
cfc91acd
RM
151" .short .LT__start_name_end-.LT__start_name_start\n" \
152".LT__start_name_start:\n" \
153" .ascii \"_start\"\n" \
154".LT__start_name_end:\n" \
155" .align 2\n" \
590b40f7 156" " END_2(_start) "\n" \
cfc91acd 157" .globl _dl_start_user\n" \
c3d36434 158" .pushsection \".opd\",\"aw\"\n" \
cfc91acd 159"_dl_start_user:\n" \
590b40f7 160" " OPD_ENT(_dl_start_user) "\n" \
c3d36434
RM
161" .popsection\n" \
162" .pushsection \".toc\",\"aw\"\n" \
ce6e047f 163DL_STARTING_UP_DEF \
37fb1dc0
AS
164".LC__rtld_local:\n" \
165" .tc _rtld_local[TC],_rtld_local\n" \
ce6e047f
UD
166".LC__dl_argc:\n" \
167" .tc _dl_argc[TC],_dl_argc\n" \
168".LC__dl_argv:\n" \
169" .tc _dl_argv_internal[TC],_dl_argv_internal\n" \
170".LC__dl_fini:\n" \
171" .tc _dl_fini[TC],_dl_fini\n" \
c3d36434 172" .popsection\n" \
590b40f7
UD
173" .type " BODY_PREFIX "_dl_start_user,@function\n" \
174" " ENTRY_2(_dl_start_user) "\n" \
175/* Now, we do our main work of calling initialisation procedures. \
176 The ELF ABI doesn't say anything about parameters for these, \
177 so we just pass argc, argv, and the environment. \
178 Changing these is strongly discouraged (not least because argc is \
179 passed by value!). */ \
180BODY_PREFIX "_dl_start_user:\n" \
cfc91acd
RM
181/* the address of _start in r30. */ \
182" mr 30,3\n" \
183/* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
37fb1dc0 184" ld 28,.LC__rtld_local@toc(2)\n" \
590b40f7
UD
185" ld 29,.LC__dl_argc@toc(2)\n" \
186" ld 27,.LC__dl_argv@toc(2)\n" \
cfc91acd
RM
187/* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \
188" ld 3,0(28)\n" \
189" lwa 4,0(29)\n" \
190" ld 5,0(27)\n" \
191" sldi 6,4,3\n" \
192" add 6,5,6\n" \
193" addi 6,6,8\n" \
590b40f7 194" bl " DOT_PREFIX "_dl_init\n" \
cfc91acd
RM
195" nop\n" \
196/* Now, to conform to the ELF ABI, we have to: \
197 Pass argc (actually _dl_argc) in r3; */ \
198" lwa 3,0(29)\n" \
199/* Pass argv (actually _dl_argv) in r4; */ \
200" ld 4,0(27)\n" \
201/* Pass argv+argc+1 in r5; */ \
202" sldi 5,3,3\n" \
203" add 6,4,5\n" \
204" addi 5,6,8\n" \
205/* Pass the auxilary vector in r6. This is passed to us just after \
206 _envp. */ \
207"2: ldu 0,8(6)\n" \
208" cmpdi 0,0\n" \
209" bne 2b\n" \
210" addi 6,6,8\n" \
211/* Pass a termination function pointer (in this case _dl_fini) in \
212 r7. */ \
ce6e047f 213" ld 7,.LC__dl_fini@toc(2)\n" \
cfc91acd
RM
214/* Pass the stack pointer in r1 (so far so good), pointing to a NULL \
215 value. This lets our startup code distinguish between a program \
216 linked statically, which linux will call with argc on top of the \
217 stack which will hopefully never be zero, and a dynamically linked \
218 program which will always have a NULL on the top of the stack. \
590b40f7 219 Take the opportunity to clear LR, so anyone who accidentally \
cfc91acd
RM
220 returns from _start gets SEGV. Also clear the next few words of \
221 the stack. */ \
222" li 31,0\n" \
223" std 31,0(1)\n" \
224" mtlr 31\n" \
225" std 31,8(1)\n" \
226" std 31,16(1)\n" \
227" std 31,24(1)\n" \
cfc91acd 228/* Now, call the start function descriptor at r30... */ \
590b40f7
UD
229" .globl ._dl_main_dispatch\n" \
230"._dl_main_dispatch:\n" \
cfc91acd
RM
231" ld 0,0(30)\n" \
232" ld 2,8(30)\n" \
233" mtctr 0\n" \
234" ld 11,16(30)\n" \
235" bctr\n" \
590b40f7 236".LT__dl_start_user:\n" \
cfc91acd
RM
237" .long 0\n" \
238" .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \
590b40f7 239" .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n" \
cfc91acd
RM
240" .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
241".LT__dl_start_user_name_start:\n" \
242" .ascii \"_dl_start_user\"\n" \
243".LT__dl_start_user_name_end:\n" \
244" .align 2\n" \
590b40f7 245" " END_2(_dl_start_user) "\n" \
c3d36434 246" .popsection");
cfc91acd 247
d2207f32
UD
248/* ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to
249 one of the main executable's symbols, as for a COPY reloc.
cfc91acd 250
d2207f32
UD
251 To make function pointer comparisons work on most targets, the
252 relevant ABI states that the address of a non-local function in a
253 dynamically linked executable is the address of the PLT entry for
254 that function. This is quite reasonable since using the real
255 function address in a non-PIC executable would typically require
256 dynamic relocations in .text, something to be avoided. For such
257 functions, the linker emits a SHN_UNDEF symbol in the executable
258 with value equal to the PLT entry address. Normally, SHN_UNDEF
259 symbols have a value of zero, so this is a clue to ld.so that it
260 should treat these symbols specially. For relocations not in
261 ELF_RTYPE_CLASS_PLT (eg. those on function pointers), ld.so should
262 use the value of the executable SHN_UNDEF symbol, ie. the PLT entry
263 address. For relocations in ELF_RTYPE_CLASS_PLT (eg. the relocs in
264 the PLT itself), ld.so should use the value of the corresponding
265 defined symbol in the object that defines the function, ie. the
266 real function address. This complicates ld.so in that there are
267 now two possible values for a given symbol, and it gets even worse
268 because protected symbols need yet another set of rules.
cfc91acd 269
d2207f32
UD
270 On PowerPC64 we don't need any of this. The linker won't emit
271 SHN_UNDEF symbols with non-zero values. ld.so can make all
272 relocations behave "normally", ie. always use the real address
273 like PLT relocations. So always set ELF_RTYPE_CLASS_PLT. */
afafddab 274
cfc91acd 275#define elf_machine_type_class(type) \
d2207f32 276 (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
cfc91acd
RM
277
278/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
279#define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
280
281/* The PowerPC never uses REL relocations. */
282#define ELF_MACHINE_NO_REL 1
283
284/* Stuff for the PLT. */
285#define PLT_INITIAL_ENTRY_WORDS 3
286#define GLINK_INITIAL_ENTRY_WORDS 8
287
288#define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
153cf972
UD
289#define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
290#define PPC_DCBF(where) asm volatile ("dcbf 0,%0" : : "r"(where) : "memory")
cfc91acd
RM
291#define PPC_SYNC asm volatile ("sync" : : : "memory")
292#define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
293#define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
294#define PPC_DIE asm volatile ("tweq 0,0")
295/* Use this when you've modified some code, but it won't be in the
296 instruction fetch queue (or when it doesn't matter if it is). */
297#define MODIFIED_CODE_NOQUEUE(where) \
298 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
299/* Use this when it might be in the instruction queue. */
300#define MODIFIED_CODE(where) \
301 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
302
303/* Set up the loaded object described by MAP so its unrelocated PLT
304 entries will jump to the on-demand fixup code in dl-runtime.c. */
9e365fe7 305static inline int __attribute__ ((always_inline))
cfc91acd
RM
306elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
307{
308 if (map->l_info[DT_JMPREL])
309 {
310 Elf64_Word i;
311 Elf64_Word *glink = NULL;
312 Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
313 Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
314 / sizeof (Elf64_Rela));
315 Elf64_Addr l_addr = map->l_addr;
316 Elf64_Dyn **info = map->l_info;
317 char *p;
318
319 extern void _dl_runtime_resolve (void);
320 extern void _dl_profile_resolve (void);
321
322 /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
323 elf_get_dynamic_info takes care of the standard entries but
a6963e69 324 doesn't know exactly what to do with processor specific
cfc91acd
RM
325 entires. */
326 if (info[DT_PPC64(GLINK)] != NULL)
327 info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
328
329 if (lazy)
330 {
331 /* The function descriptor of the appropriate trampline
332 routine is used to set the 1st and 2nd doubleword of the
333 plt_reserve. */
334 Elf64_FuncDesc *resolve_fd;
335 Elf64_Word glink_offset;
336 /* the plt_reserve area is the 1st 3 doublewords of the PLT */
337 Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
338 Elf64_Word offset;
339
340 resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
341 : _dl_runtime_resolve);
4e2d5491
UD
342 if (profile && GLRO(dl_profile) != NULL
343 && _dl_name_match_p (GLRO(dl_profile), map))
cfc91acd
RM
344 /* This is the object we are looking for. Say that we really
345 want profiling and the timers are started. */
346 GL(dl_profile_map) = map;
347
348
349 /* We need to stuff the address/TOC of _dl_runtime_resolve
350 into doublewords 0 and 1 of plt_reserve. Then we need to
351 stuff the map address into doubleword 2 of plt_reserve.
352 This allows the GLINK0 code to transfer control to the
353 correct trampoline which will transfer control to fixup
354 in dl-machine.c. */
355 plt_reserve->fd_func = resolve_fd->fd_func;
356 plt_reserve->fd_toc = resolve_fd->fd_toc;
357 plt_reserve->fd_aux = (Elf64_Addr) map;
358#ifdef RTLD_BOOTSTRAP
359 /* When we're bootstrapping, the opd entry will not have
360 been relocated yet. */
361 plt_reserve->fd_func += l_addr;
362 plt_reserve->fd_toc += l_addr;
363#endif
a6963e69 364
cfc91acd
RM
365 /* Set up the lazy PLT entries. */
366 glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
367 offset = PLT_INITIAL_ENTRY_WORDS;
368 glink_offset = GLINK_INITIAL_ENTRY_WORDS;
369 for (i = 0; i < num_plt_entries; i++)
370 {
371
372 plt[offset] = (Elf64_Xword) &glink[glink_offset];
373 offset += 3;
374 /* The first 32k entries of glink can set an index and
375 branch using two instructions; Past that point,
376 glink uses three instructions. */
377 if (i < 0x8000)
d063d164 378 glink_offset += 2;
cfc91acd 379 else
d063d164 380 glink_offset += 3;
cfc91acd
RM
381 }
382
383 /* Now, we've modified data. We need to write the changes from
384 the data cache to a second-level unified cache, then make
385 sure that stale data in the instruction cache is removed.
386 (In a multiprocessor system, the effect is more complex.)
387 Most of the PLT shouldn't be in the instruction cache, but
388 there may be a little overlap at the start and the end.
389
390 Assumes that dcbst and icbi apply to lines of 16 bytes or
391 more. Current known line sizes are 16, 32, and 128 bytes. */
392
393 for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
394 PPC_DCBST (p);
395 PPC_SYNC;
396 }
397 }
398 return lazy;
399}
400
cfc91acd
RM
401/* Change the PLT entry whose reloc is 'reloc' to call the actual
402 routine. */
9e365fe7 403static inline Elf64_Addr __attribute__ ((always_inline))
cfc91acd
RM
404elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
405 const Elf64_Rela *reloc,
406 Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
407{
408 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
409 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
410 Elf64_Addr offset = 0;
cfc91acd 411
153cf972
UD
412 PPC_DCBT (&plt->fd_aux);
413 PPC_DCBT (&plt->fd_func);
414 PPC_DCBT (&rel->fd_aux);
415 PPC_DCBT (&rel->fd_func);
416
cfc91acd
RM
417 /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */
418 if (sym_map == NULL)
419 return 0;
420
421 /* If the opd entry is not yet relocated (because it's from a shared
422 object that hasn't been processed yet), then manually reloc it. */
423 if (map != sym_map && !sym_map->l_relocated
bb0ddc2f 424#if !defined RTLD_BOOTSTRAP && defined SHARED
cfc91acd
RM
425 /* Bootstrap map doesn't have l_relocated set for it. */
426 && sym_map != &GL(dl_rtld_map)
427#endif
428 )
429 offset = sym_map->l_addr;
430
431 /* For PPC64, fixup_plt copies the function descriptor from opd
432 over the corresponding PLT entry.
433 Initially, PLT Entry[i] is set up for lazy linking, or is zero.
434 For lazy linking, the fd_toc and fd_aux entries are irrelevant,
435 so for thread safety we write them before changing fd_func. */
436
437 plt->fd_aux = rel->fd_aux + offset;
438 plt->fd_toc = rel->fd_toc + offset;
153cf972
UD
439 PPC_DCBF (&plt->fd_toc);
440 PPC_ISYNC;
cfc91acd
RM
441
442 plt->fd_func = rel->fd_func + offset;
443 PPC_DCBST (&plt->fd_func);
153cf972 444 PPC_ISYNC;
cfc91acd
RM
445
446 return finaladdr;
447}
448
9e365fe7 449static inline void __attribute__ ((always_inline))
06e2e0a7
UD
450elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
451{
452 Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
453 Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
454
455 plt->fd_func = rel->fd_func;
456 plt->fd_aux = rel->fd_aux;
457 plt->fd_toc = rel->fd_toc;
458 PPC_DCBST (&plt->fd_func);
459 PPC_DCBST (&plt->fd_aux);
460 PPC_DCBST (&plt->fd_toc);
461 PPC_SYNC;
462}
463
cfc91acd
RM
464/* Return the final value of a plt relocation. */
465static inline Elf64_Addr
466elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
467 Elf64_Addr value)
468{
469 return value + reloc->r_addend;
470}
a6963e69 471
82221992
UD
472
473/* Names of the architecture-specific auditing callback functions. */
474#define ARCH_LA_PLTENTER ppc64_gnu_pltenter
475#define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
476
cfc91acd
RM
477#endif /* dl_machine_h */
478
479#ifdef RESOLVE_MAP
480
481#define PPC_LO(v) ((v) & 0xffff)
482#define PPC_HI(v) (((v) >> 16) & 0xffff)
483#define PPC_HA(v) PPC_HI ((v) + 0x8000)
484#define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
485#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
486#define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
487#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
bb0ddc2f 488#define BIT_INSERT(var, val, mask) \
790eed83 489 ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
cfc91acd
RM
490
491#define dont_expect(X) __builtin_expect ((X), 0)
492
493extern void _dl_reloc_overflow (struct link_map *map,
d063d164
UD
494 const char *name,
495 Elf64_Addr *const reloc_addr,
496 const Elf64_Sym *refsym)
497 attribute_hidden;
cfc91acd 498
7de00121 499auto inline void __attribute__ ((always_inline))
cfc91acd 500elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
87d254a7 501 void *const reloc_addr_arg)
cfc91acd 502{
87d254a7 503 Elf64_Addr *const reloc_addr = reloc_addr_arg;
cfc91acd 504 *reloc_addr = l_addr + reloc->r_addend;
afafddab 505}
cfc91acd 506
b3838ebd 507/* This computes the value used by TPREL* relocs. */
7de00121 508auto inline Elf64_Addr __attribute__ ((always_inline, const))
b3838ebd
RM
509elf_machine_tprel (struct link_map *map,
510 struct link_map *sym_map,
511 const Elf64_Sym *sym,
512 const Elf64_Rela *reloc)
513{
d063d164 514#ifndef RTLD_BOOTSTRAP
b3838ebd
RM
515 if (sym_map)
516 {
517 CHECK_STATIC_TLS (map, sym_map);
d063d164 518#endif
b3838ebd 519 return TLS_TPREL_VALUE (sym_map, sym, reloc);
d063d164 520#ifndef RTLD_BOOTSTRAP
b3838ebd 521 }
d063d164 522#endif
b3838ebd
RM
523 return 0;
524}
b3838ebd 525
77799d9d
AM
526/* Call function at address VALUE (an OPD entry) to resolve ifunc relocs. */
527auto inline Elf64_Addr __attribute__ ((always_inline))
528resolve_ifunc (Elf64_Addr value,
529 const struct link_map *map, const struct link_map *sym_map)
530{
872873d4 531#ifndef RESOLVE_CONFLICT_FIND_MAP
77799d9d
AM
532 /* The function we are calling may not yet have its opd entry relocated. */
533 Elf64_FuncDesc opd;
534 if (map != sym_map
872873d4 535# if !defined RTLD_BOOTSTRAP && defined SHARED
77799d9d
AM
536 /* Bootstrap map doesn't have l_relocated set for it. */
537 && sym_map != &GL(dl_rtld_map)
872873d4 538# endif
77799d9d
AM
539 && !sym_map->l_relocated)
540 {
541 Elf64_FuncDesc *func = (Elf64_FuncDesc *) value;
542 opd.fd_func = func->fd_func + sym_map->l_addr;
543 opd.fd_toc = func->fd_toc + sym_map->l_addr;
544 opd.fd_aux = func->fd_aux;
545 value = (Elf64_Addr) &opd;
546 }
872873d4 547#endif
a386f1cc 548 return ((Elf64_Addr (*) (unsigned long int)) value) (GLRO(dl_hwcap));
77799d9d
AM
549}
550
cfc91acd
RM
551/* Perform the relocation specified by RELOC and SYM (which is fully
552 resolved). MAP is the object containing the reloc. */
7de00121 553auto inline void __attribute__ ((always_inline))
cfc91acd
RM
554elf_machine_rela (struct link_map *map,
555 const Elf64_Rela *reloc,
556 const Elf64_Sym *sym,
557 const struct r_found_version *version,
3a62d00d
AS
558 void *const reloc_addr_arg,
559 int skip_ifunc)
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 563 const Elf64_Sym *const refsym = sym;
cfc91acd
RM
564
565 if (r_type == R_PPC64_RELATIVE)
566 {
afafddab 567 *reloc_addr = map->l_addr + reloc->r_addend;
cfc91acd
RM
568 return;
569 }
570
bb0ddc2f 571 if (__builtin_expect (r_type == R_PPC64_NONE, 0))
cfc91acd
RM
572 return;
573
77799d9d
AM
574 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
575 and STT_GNU_IFUNC. */
bb0ddc2f 576 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
b3838ebd 577 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
790eed83 578 + reloc->r_addend);
cfc91acd 579
77799d9d
AM
580 if (sym != NULL
581 && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
3a62d00d
AS
582 && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
583 && __builtin_expect (!skip_ifunc, 1))
77799d9d
AM
584 value = resolve_ifunc (value, map, sym_map);
585
bb0ddc2f
RM
586 /* For relocs that don't edit code, return.
587 For relocs that might edit instructions, break from the switch. */
cfc91acd
RM
588 switch (r_type)
589 {
590 case R_PPC64_ADDR64:
591 case R_PPC64_GLOB_DAT:
a6963e69 592 *reloc_addr = value;
cfc91acd 593 return;
a6963e69 594
77799d9d 595 case R_PPC64_IRELATIVE:
3a62d00d
AS
596 if (__builtin_expect (!skip_ifunc, 1))
597 value = resolve_ifunc (value, map, sym_map);
77799d9d
AM
598 *reloc_addr = value;
599 return;
600
601 case R_PPC64_JMP_IREL:
3a62d00d
AS
602 if (__builtin_expect (!skip_ifunc, 1))
603 value = resolve_ifunc (value, map, sym_map);
77799d9d 604 /* Fall thru */
bb0ddc2f
RM
605 case R_PPC64_JMP_SLOT:
606#ifdef RESOLVE_CONFLICT_FIND_MAP
06e2e0a7
UD
607 elf_machine_plt_conflict (reloc_addr, value);
608#else
bb0ddc2f 609 elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
06e2e0a7 610#endif
bb0ddc2f 611 return;
afafddab
RM
612
613 case R_PPC64_DTPMOD64:
d063d164 614#ifdef RTLD_BOOTSTRAP
b3838ebd 615 /* During startup the dynamic linker is always index 1. */
afafddab 616 *reloc_addr = 1;
d063d164 617#else
b3838ebd
RM
618 /* Get the information from the link map returned by the
619 resolve function. */
afafddab 620 if (sym_map != NULL)
d063d164
UD
621 *reloc_addr = sym_map->l_tls_modid;
622#endif
afafddab 623 return;
a6963e69 624
3a601d31 625 case R_PPC64_DTPREL64:
bb0ddc2f 626 /* During relocation all TLS symbols are defined and used.
d063d164
UD
627 Therefore the offset is already correct. */
628#ifndef RTLD_BOOTSTRAP
22163624
UD
629 if (sym_map != NULL)
630 *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
d063d164 631#endif
b3838ebd
RM
632 return;
633
3a601d31 634 case R_PPC64_TPREL64:
b3838ebd
RM
635 *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
636 return;
637
638 case R_PPC64_TPREL16_LO_DS:
639 value = elf_machine_tprel (map, sym_map, sym, reloc);
640 if (dont_expect ((value & 3) != 0))
d063d164 641 _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
817328ee 642 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
b3838ebd
RM
643 break;
644
645 case R_PPC64_TPREL16_DS:
646 value = elf_machine_tprel (map, sym_map, sym, reloc);
647 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
d063d164 648 _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
817328ee 649 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
b3838ebd
RM
650 break;
651
652 case R_PPC64_TPREL16:
653 value = elf_machine_tprel (map, sym_map, sym, reloc);
654 if (dont_expect ((value + 0x8000) >= 0x10000))
d063d164 655 _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
b3838ebd
RM
656 *(Elf64_Half *) reloc_addr = PPC_LO (value);
657 break;
658
659 case R_PPC64_TPREL16_LO:
660 value = elf_machine_tprel (map, sym_map, sym, reloc);
661 *(Elf64_Half *) reloc_addr = PPC_LO (value);
662 break;
663
664 case R_PPC64_TPREL16_HI:
665 value = elf_machine_tprel (map, sym_map, sym, reloc);
666 *(Elf64_Half *) reloc_addr = PPC_HI (value);
667 break;
668
669 case R_PPC64_TPREL16_HA:
670 value = elf_machine_tprel (map, sym_map, sym, reloc);
671 *(Elf64_Half *) reloc_addr = PPC_HA (value);
672 break;
673
674 case R_PPC64_TPREL16_HIGHER:
675 value = elf_machine_tprel (map, sym_map, sym, reloc);
676 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
677 break;
678
679 case R_PPC64_TPREL16_HIGHEST:
680 value = elf_machine_tprel (map, sym_map, sym, reloc);
681 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
682 break;
683
684 case R_PPC64_TPREL16_HIGHERA:
685 value = elf_machine_tprel (map, sym_map, sym, reloc);
686 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
687 break;
688
689 case R_PPC64_TPREL16_HIGHESTA:
690 value = elf_machine_tprel (map, sym_map, sym, reloc);
691 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
bb0ddc2f 692 break;
cfc91acd
RM
693
694#ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
695 case R_PPC64_ADDR16_LO_DS:
696 if (dont_expect ((value & 3) != 0))
d063d164 697 _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
bb0ddc2f 698 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
afafddab
RM
699 break;
700
cfc91acd
RM
701 case R_PPC64_ADDR16_LO:
702 *(Elf64_Half *) reloc_addr = PPC_LO (value);
703 break;
704
705 case R_PPC64_ADDR16_HI:
706 *(Elf64_Half *) reloc_addr = PPC_HI (value);
707 break;
708
709 case R_PPC64_ADDR16_HA:
710 *(Elf64_Half *) reloc_addr = PPC_HA (value);
711 break;
712
b3838ebd 713 case R_PPC64_ADDR30:
cfc91acd 714 {
d063d164
UD
715 Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
716 if (dont_expect ((delta + 0x80000000) >= 0x10000000
b3838ebd 717 || (delta & 3) != 0))
d063d164
UD
718 _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
719 BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
cfc91acd
RM
720 }
721 break;
722
723 case R_PPC64_COPY:
724 if (dont_expect (sym == NULL))
b3838ebd 725 /* This can happen in trace mode when an object could not be found. */
d063d164 726 return;
cfc91acd 727 if (dont_expect (sym->st_size > refsym->st_size
afdca0f2
UD
728 || (GLRO(dl_verbose)
729 && sym->st_size < refsym->st_size)))
b3838ebd 730 {
d063d164 731 const char *strtab;
cfc91acd 732
d063d164
UD
733 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
734 _dl_error_printf ("%s: Symbol `%s' has different size" \
735 " in shared object," \
736 " consider re-linking\n",
37fb1dc0 737 rtld_progname ?: "<program name unknown>",
b3838ebd
RM
738 strtab + refsym->st_name);
739 }
87d254a7
AO
740 memcpy (reloc_addr_arg, (char *) value,
741 MIN (sym->st_size, refsym->st_size));
cfc91acd
RM
742 return;
743
744 case R_PPC64_UADDR64:
745 /* We are big-endian. */
87d254a7
AO
746 ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
747 ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
748 ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
749 ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
750 ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
751 ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
752 ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
753 ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
cfc91acd
RM
754 return;
755
756 case R_PPC64_UADDR32:
757 /* We are big-endian. */
87d254a7
AO
758 ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
759 ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
760 ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
761 ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
cfc91acd
RM
762 return;
763
b3838ebd
RM
764 case R_PPC64_ADDR32:
765 if (dont_expect ((value + 0x80000000) >= 0x10000000))
d063d164 766 _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
b3838ebd
RM
767 *(Elf64_Word *) reloc_addr = value;
768 return;
769
cfc91acd
RM
770 case R_PPC64_ADDR24:
771 if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
d063d164 772 _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
bb0ddc2f 773 BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
cfc91acd
RM
774 break;
775
776 case R_PPC64_ADDR16:
777 if (dont_expect ((value + 0x8000) >= 0x10000))
d063d164 778 _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
cfc91acd
RM
779 *(Elf64_Half *) reloc_addr = value;
780 break;
781
782 case R_PPC64_UADDR16:
783 if (dont_expect ((value + 0x8000) >= 0x10000))
d063d164 784 _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
cfc91acd 785 /* We are big-endian. */
87d254a7
AO
786 ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
787 ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
cfc91acd
RM
788 break;
789
790 case R_PPC64_ADDR16_DS:
791 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
d063d164 792 _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
bb0ddc2f 793 BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
afafddab
RM
794 break;
795
cfc91acd
RM
796 case R_PPC64_ADDR16_HIGHER:
797 *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
798 break;
799
800 case R_PPC64_ADDR16_HIGHEST:
801 *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
802 break;
803
804 case R_PPC64_ADDR16_HIGHERA:
805 *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
806 break;
807
808 case R_PPC64_ADDR16_HIGHESTA:
809 *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
810 break;
811
812 case R_PPC64_ADDR14:
813 case R_PPC64_ADDR14_BRTAKEN:
814 case R_PPC64_ADDR14_BRNTAKEN:
815 {
d063d164 816 if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
63c7a7e8 817 _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
d063d164
UD
818 Elf64_Word insn = *(Elf64_Word *) reloc_addr;
819 BIT_INSERT (insn, value, 0xfffc);
820 if (r_type != R_PPC64_ADDR14)
bb0ddc2f
RM
821 {
822 insn &= ~(1 << 21);
823 if (r_type == R_PPC64_ADDR14_BRTAKEN)
824 insn |= 1 << 21;
825 if ((insn & (0x14 << 21)) == (0x04 << 21))
826 insn |= 0x02 << 21;
827 else if ((insn & (0x14 << 21)) == (0x10 << 21))
828 insn |= 0x08 << 21;
829 }
d063d164 830 *(Elf64_Word *) reloc_addr = insn;
cfc91acd
RM
831 }
832 break;
833
834 case R_PPC64_REL32:
b3838ebd
RM
835 *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
836 return;
837
838 case R_PPC64_REL64:
839 *reloc_addr = value - (Elf64_Addr) reloc_addr;
cfc91acd
RM
840 return;
841#endif /* !RTLD_BOOTSTRAP */
842
843 default:
844 _dl_reloc_bad_type (map, r_type, 0);
845 return;
846 }
847 MODIFIED_CODE_NOQUEUE (reloc_addr);
848}
849
7de00121 850auto inline void __attribute__ ((always_inline))
7ba7c829 851elf_machine_lazy_rel (struct link_map *map,
3a62d00d
AS
852 Elf64_Addr l_addr, const Elf64_Rela *reloc,
853 int skip_ifunc)
7ba7c829
UD
854{
855 /* elf_machine_runtime_setup handles this. */
856}
857
7de00121 858
cfc91acd 859#endif /* RESOLVE */