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