Rename __LONG_DOUBLE_USES_FLOAT128 to __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI
[glibc.git] / sysdeps / hppa / dl-machine.h
blob8ecff97706f12165778e33357372166fe32702cd
1 /* Machine-dependent ELF dynamic relocation inline functions. PA-RISC version.
2 Copyright (C) 1995-2020 Free Software Foundation, Inc.
3 Contributed by David Huggins-Daines <dhd@debian.org>
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library. If not, see
18 <https://www.gnu.org/licenses/>. */
20 #ifndef dl_machine_h
21 #define dl_machine_h 1
23 #define ELF_MACHINE_NAME "hppa"
25 #include <sys/param.h>
26 #include <assert.h>
27 #include <string.h>
28 #include <link.h>
29 #include <errno.h>
30 #include <dl-fptr.h>
31 #include <abort-instr.h>
32 #include <tls.h>
34 /* These two definitions must match the definition of the stub in
35 bfd/elf32-hppa.c (see plt_stub[]).
37 a. Define the size of the *entire* stub we place at the end of the PLT
38 table (right up against the GOT).
40 b. Define the number of bytes back from the GOT to the entry point of
41 the PLT stub. You see the PLT stub must be entered in the middle
42 so it can depwi to find it's own address (long jump stub)
44 c. Define the size of a single PLT entry so we can jump over the
45 last entry to get the stub address */
47 #define SIZEOF_PLT_STUB (7*4)
48 #define GOT_FROM_PLT_STUB (4*4)
49 #define PLT_ENTRY_SIZE (2*4)
51 /* The gp slot in the function descriptor contains the relocation offset
52 before resolution. To distinguish between a resolved gp value and an
53 unresolved relocation offset we set an unused bit in the relocation
54 offset. This would allow us to do a synchronzied two word update
55 using this bit (interlocked update), but instead of waiting for the
56 update we simply recompute the gp value given that we know the ip. */
57 #define PA_GP_RELOC 1
59 /* Initialize the function descriptor table before relocations */
60 static inline void
61 __hppa_init_bootstrap_fdesc_table (struct link_map *map)
63 ElfW(Addr) *boot_table;
65 /* Careful: this will be called before got has been relocated... */
66 ELF_MACHINE_LOAD_ADDRESS(boot_table,_dl_boot_fptr_table);
68 map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
69 map->l_mach.fptr_table = boot_table;
72 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) \
73 __hppa_init_bootstrap_fdesc_table (BOOTSTRAP_MAP); \
74 _dl_fptr_init();
76 /* Return nonzero iff ELF header is compatible with the running host. */
77 static inline int
78 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
80 return ehdr->e_machine == EM_PARISC;
83 /* Return the link-time address of _DYNAMIC. */
84 static inline Elf32_Addr
85 elf_machine_dynamic (void) __attribute__ ((const));
87 static inline Elf32_Addr
88 elf_machine_dynamic (void)
90 Elf32_Addr dynamic;
92 asm ("bl 1f,%0\n"
93 " addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 1),%0\n"
94 "1: ldw R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
95 : "=r" (dynamic) : : "r1");
97 return dynamic;
100 /* Return the run-time load address of the shared object. */
101 static inline Elf32_Addr
102 elf_machine_load_address (void) __attribute__ ((const));
104 static inline Elf32_Addr
105 elf_machine_load_address (void)
107 Elf32_Addr dynamic;
109 asm (
110 " bl 1f,%0\n"
111 " addil L'_DYNAMIC - ($PIC_pcrel$0 - 1),%0\n"
112 "1: ldo R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
113 : "=r" (dynamic) : : "r1");
115 return dynamic - elf_machine_dynamic ();
118 /* Fixup a PLT entry to bounce directly to the function at VALUE. */
119 static inline struct fdesc __attribute__ ((always_inline))
120 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
121 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
122 const Elf32_Rela *reloc,
123 Elf32_Addr *reloc_addr, struct fdesc value)
125 volatile Elf32_Addr *rfdesc = reloc_addr;
126 /* map is the link_map for the caller, t is the link_map for the object
127 being called */
129 /* We would like the function descriptor to be double word aligned. This
130 helps performance (ip and gp then reside on the same cache line) and
131 we can update the pair atomically with a single store. The linker
132 now ensures this alignment but we still have to handle old code. */
133 if ((unsigned int)reloc_addr & 7)
135 /* Need to ensure that the gp is visible before the code
136 entry point is updated */
137 rfdesc[1] = value.gp;
138 atomic_full_barrier();
139 rfdesc[0] = value.ip;
141 else
143 /* Update pair atomically with floating point store. */
144 union { ElfW(Word) v[2]; double d; } u;
146 u.v[0] = value.ip;
147 u.v[1] = value.gp;
148 *(volatile double *)rfdesc = u.d;
150 return value;
153 /* Return the final value of a plt relocation. */
154 static inline struct fdesc
155 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
156 struct fdesc value)
158 /* We are rela only, return a function descriptor as a plt entry. */
159 return (struct fdesc) { value.ip + reloc->r_addend, value.gp };
162 /* Set up the loaded object described by L so its unrelocated PLT
163 entries will jump to the on-demand fixup code in dl-runtime.c. */
165 static inline int
166 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
168 Elf32_Addr *got = NULL;
169 Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type, r_sym;
170 const Elf32_Rela *reloc;
171 struct fdesc *fptr;
172 static union {
173 unsigned char c[8];
174 Elf32_Addr i[2];
175 } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
177 /* If we don't have a PLT we can just skip all this... */
178 if (__builtin_expect (l->l_info[DT_JMPREL] == NULL,0))
179 return lazy;
181 /* All paths use these values */
182 l_addr = l->l_addr;
183 jmprel = D_PTR(l, l_info[DT_JMPREL]);
184 end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
186 extern void _dl_runtime_resolve (void);
187 extern void _dl_runtime_profile (void);
189 /* Linking lazily */
190 if (lazy)
192 /* FIXME: Search for the got, but backwards through the relocs, technically we should
193 find it on the first try. However, assuming the relocs got out of order the
194 routine is made a bit more robust by searching them all in case of failure. */
195 for (iplt = (end_jmprel - sizeof (Elf32_Rela)); iplt >= jmprel; iplt -= sizeof (Elf32_Rela))
198 reloc = (const Elf32_Rela *) iplt;
199 r_type = ELF32_R_TYPE (reloc->r_info);
200 r_sym = ELF32_R_SYM (reloc->r_info);
202 got = (Elf32_Addr *) (reloc->r_offset + l_addr + PLT_ENTRY_SIZE + SIZEOF_PLT_STUB);
204 /* If we aren't an IPLT, and we aren't NONE then it's a bad reloc */
205 if (__builtin_expect (r_type != R_PARISC_IPLT, 0))
207 if (__builtin_expect (r_type != R_PARISC_NONE, 0))
208 _dl_reloc_bad_type (l, r_type, 1);
209 continue;
212 /* Check for the plt_stub that binutils placed here for us
213 to use with _dl_runtime_resolve */
214 if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
216 got = NULL; /* Not the stub... keep looking */
218 else
220 /* Found the GOT! */
221 register Elf32_Addr ltp __asm__ ("%r19");
223 /* Identify this shared object. Second entry in the got. */
224 got[1] = (Elf32_Addr) l;
226 /* This function will be called to perform the relocation. */
227 if (__builtin_expect (!profile, 1))
229 /* If a static application called us, then _dl_runtime_resolve is not
230 a function descriptor, but the *real* address of the function... */
231 if((unsigned long) &_dl_runtime_resolve & 3)
233 got[-2] = (Elf32_Addr) ((struct fdesc *)
234 ((unsigned long) &_dl_runtime_resolve & ~3))->ip;
236 else
238 /* Static executable! */
239 got[-2] = (Elf32_Addr) &_dl_runtime_resolve;
242 else
244 if (GLRO(dl_profile) != NULL
245 && _dl_name_match_p (GLRO(dl_profile), l))
247 /* This is the object we are looking for. Say that
248 we really want profiling and the timers are
249 started. */
250 GL(dl_profile_map) = l;
253 if((unsigned long) &_dl_runtime_profile & 3)
255 got[-2] = (Elf32_Addr) ((struct fdesc *)
256 ((unsigned long) &_dl_runtime_profile & ~3))->ip;
258 else
260 /* Static executable */
261 got[-2] = (Elf32_Addr) &_dl_runtime_profile;
264 /* Plunk in the gp of this function descriptor so we
265 can make the call to _dl_runtime_xxxxxx */
266 got[-1] = ltp;
267 break;
268 /* Done looking for the GOT, and stub is setup */
269 } /* else we found the GOT */
270 } /* for, walk the relocs backwards */
272 if(!got)
273 return 0; /* No lazy linking for you! */
275 /* Process all the relocs, now that we know the GOT... */
276 for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
278 reloc = (const Elf32_Rela *) iplt;
279 r_type = ELF32_R_TYPE (reloc->r_info);
280 r_sym = ELF32_R_SYM (reloc->r_info);
282 if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
284 fptr = (struct fdesc *) (reloc->r_offset + l_addr);
285 if (r_sym != 0)
287 /* Relocate the pointer to the stub. */
288 fptr->ip = (Elf32_Addr) got - GOT_FROM_PLT_STUB;
290 /* Instead of the LTP value, we put the reloc offset
291 here. The trampoline code will load the proper
292 LTP and pass the reloc offset to the fixup
293 function. */
294 fptr->gp = (iplt - jmprel) | PA_GP_RELOC;
295 } /* r_sym != 0 */
296 else
298 /* Relocate this *ABS* entry. */
299 fptr->ip = reloc->r_addend + l_addr;
300 fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
302 } /* r_type == R_PARISC_IPLT */
303 } /* for all the relocations */
304 } /* if lazy */
305 else
307 for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
309 reloc = (const Elf32_Rela *) iplt;
310 r_type = ELF32_R_TYPE (reloc->r_info);
311 r_sym = ELF32_R_SYM (reloc->r_info);
313 if (__builtin_expect ((r_type == R_PARISC_IPLT) && (r_sym == 0), 1))
315 fptr = (struct fdesc *) (reloc->r_offset + l_addr);
316 /* Relocate this *ABS* entry, set only the gp, the rest is set later
317 when elf_machine_rela_relative is called (WITHOUT the linkmap) */
318 fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
319 } /* r_type == R_PARISC_IPLT */
320 } /* for all the relocations */
322 return lazy;
326 /* Names of the architecture-specific auditing callback functions. */
327 #define ARCH_LA_PLTENTER hppa_gnu_pltenter
328 #define ARCH_LA_PLTEXIT hppa_gnu_pltexit
330 /* Adjust DL_STACK_END to get value we want in __libc_stack_end. */
331 #define DL_STACK_END(cookie) \
332 ((void *) (((long) (cookie)) + 0x160))
334 /* Initial entry point code for the dynamic linker.
335 The C function `_dl_start' is the real entry point;
336 its return value is the user program's entry point. */
338 #define RTLD_START \
339 /* Set up dp for any non-PIC lib constructors that may be called. */ \
340 static struct link_map * __attribute__((used)) \
341 set_dp (struct link_map *map) \
343 register Elf32_Addr dp asm ("%r27"); \
344 dp = D_PTR (map, l_info[DT_PLTGOT]); \
345 asm volatile ("" : : "r" (dp)); \
346 return map; \
349 asm ( \
350 " .text\n" \
351 " .globl _start\n" \
352 " .type _start,@function\n" \
353 "_start:\n" \
354 /* The kernel does not give us an initial stack frame. */ \
355 " ldo 64(%sp),%sp\n" \
356 /* Save the relevant arguments (yes, those are the correct \
357 registers, the kernel is weird) in their stack slots. */ \
358 " stw %r25,-40(%sp)\n" /* argc */ \
359 " stw %r24,-44(%sp)\n" /* argv */ \
361 /* We need the LTP, and we need it now. \
362 $PIC_pcrel$0 points 8 bytes past the current instruction, \
363 just like a branch reloc. This sequence gets us the \
364 runtime address of _DYNAMIC. */ \
365 " bl 0f,%r19\n" \
366 " addil L'_DYNAMIC - ($PIC_pcrel$0 - 1),%r19\n" \
367 "0: ldo R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%r1),%r26\n" \
369 /* The link time address is stored in the first entry of the \
370 GOT. */ \
371 " addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 9),%r19\n" \
372 " ldw R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 13)(%r1),%r20\n" \
374 " sub %r26,%r20,%r20\n" /* Calculate load offset */ \
376 /* Rummage through the dynamic entries, looking for \
377 DT_PLTGOT. */ \
378 " ldw,ma 8(%r26),%r19\n" \
379 "1: cmpib,=,n 3,%r19,2f\n" /* tag == DT_PLTGOT? */ \
380 " cmpib,<>,n 0,%r19,1b\n" \
381 " ldw,ma 8(%r26),%r19\n" \
383 /* Uh oh! We didn't find one. Abort. */ \
384 " iitlbp %r0,(%sr0,%r0)\n" \
386 "2: ldw -4(%r26),%r19\n" /* Found it, load value. */ \
387 " add %r19,%r20,%r19\n" /* And add the load offset. */ \
389 /* Our initial stack layout is rather different from everyone \
390 else's due to the unique PA-RISC ABI. As far as I know it \
391 looks like this: \
393 ----------------------------------- (this frame created above) \
394 | 32 bytes of magic | \
395 |---------------------------------| \
396 | 32 bytes argument/sp save area | \
397 |---------------------------------| ((current->mm->env_end) \
398 | N bytes of slack | + 63 & ~63) \
399 |---------------------------------| \
400 | envvar and arg strings | \
401 |---------------------------------| \
402 | ELF auxiliary info | \
403 | (up to 28 words) | \
404 |---------------------------------| \
405 | Environment variable pointers | \
406 | upwards to NULL | \
407 |---------------------------------| \
408 | Argument pointers | \
409 | upwards to NULL | \
410 |---------------------------------| \
411 | argc (1 word) | \
412 ----------------------------------- \
414 So, obviously, we can't just pass %sp to _dl_start. That's \
415 okay, argv-4 will do just fine. \
417 The pleasant part of this is that if we need to skip \
418 arguments we can just decrement argc and move argv, because \
419 the stack pointer is utterly unrelated to the location of \
420 the environment and argument vectors. */ \
422 /* This is always within range so we'll be okay. */ \
423 " bl _dl_start,%rp\n" \
424 " ldo -4(%r24),%r26\n" \
426 " .globl _dl_start_user\n" \
427 " .type _dl_start_user,@function\n" \
428 "_dl_start_user:\n" \
429 /* Save the entry point in %r3. */ \
430 " copy %ret0,%r3\n" \
432 /* See if we were called as a command with the executable file \
433 name as an extra leading argument. */ \
434 " addil LT'_dl_skip_args,%r19\n" \
435 " ldw RT'_dl_skip_args(%r1),%r20\n" \
436 " ldw 0(%r20),%r20\n" \
438 " ldw -40(%sp),%r25\n" /* argc */ \
439 " comib,= 0,%r20,.Lnofix\n" /* FIXME: Mispredicted branch */\
440 " ldw -44(%sp),%r24\n" /* argv (delay slot) */ \
442 " sub %r25,%r20,%r25\n" \
443 " stw %r25,-40(%sp)\n" \
444 " sh2add %r20,%r24,%r24\n" \
445 " stw %r24,-44(%sp)\n" \
447 ".Lnofix:\n" \
448 " addil LT'_rtld_local,%r19\n" \
449 " ldw RT'_rtld_local(%r1),%r26\n" \
450 " bl set_dp, %r2\n" \
451 " ldw 0(%r26),%r26\n" \
453 /* Call _dl_init(_dl_loaded, argc, argv, envp). */ \
454 " copy %r28,%r26\n" \
456 /* envp = argv + argc + 1 */ \
457 " sh2add %r25,%r24,%r23\n" \
458 " bl _dl_init,%r2\n" \
459 " ldo 4(%r23),%r23\n" /* delay slot */ \
461 /* Reload argc, argv to the registers start.S expects. */ \
462 " ldw -40(%sp),%r25\n" \
463 " ldw -44(%sp),%r24\n" \
465 /* _dl_fini is a local function in the loader, so we construct \
466 a false OPD here and pass this to the application. */ \
467 /* FIXME: Should be able to use P%, and LR RR to have the \
468 the linker construct a proper OPD. */ \
469 " .section .data\n" \
470 "__dl_fini_plabel:\n" \
471 " .word _dl_fini\n" \
472 " .word 0xdeadbeef\n" \
473 " .previous\n" \
475 /* %r3 contains a function pointer, we need to mask out the \
476 lower bits and load the gp and jump address. */ \
477 " depi 0,31,2,%r3\n" \
478 " ldw 0(%r3),%r2\n" \
479 " addil LT'__dl_fini_plabel,%r19\n" \
480 " ldw RT'__dl_fini_plabel(%r1),%r23\n" \
481 " stw %r19,4(%r23)\n" \
482 " ldw 4(%r3),%r19\n" /* load the object's gp */ \
483 " bv %r0(%r2)\n" \
484 " depi 2,31,2,%r23\n" /* delay slot */ \
487 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
488 a TLS variable, so references should not be allowed to define the value.
489 ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
490 of the main executable's symbols, as for a COPY reloc. */
491 #if !defined RTLD_BOOTSTRAP
492 # define elf_machine_type_class(type) \
493 ((((type) == R_PARISC_IPLT \
494 || (type) == R_PARISC_EPLT \
495 || (type) == R_PARISC_TLS_DTPMOD32 \
496 || (type) == R_PARISC_TLS_DTPOFF32 \
497 || (type) == R_PARISC_TLS_TPREL32) \
498 * ELF_RTYPE_CLASS_PLT) \
499 | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
500 #else
501 #define elf_machine_type_class(type) \
502 ((((type) == R_PARISC_IPLT \
503 || (type) == R_PARISC_EPLT) \
504 * ELF_RTYPE_CLASS_PLT) \
505 | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
506 #endif
508 /* Used by the runtime in fixup to figure out if reloc is *really* PLT */
509 #define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
510 #define ELF_MACHINE_SIZEOF_JMP_SLOT PLT_ENTRY_SIZE
512 /* We only use RELA. */
513 #define ELF_MACHINE_NO_REL 1
514 #define ELF_MACHINE_NO_RELA 0
516 /* Return the address of the entry point. */
517 #define ELF_MACHINE_START_ADDRESS(map, start) \
518 ({ \
519 ElfW(Addr) addr; \
520 DL_DT_FUNCTION_ADDRESS(map, start, static, addr) \
521 addr; \
524 /* We define an initialization functions. This is called very early in
525 * _dl_sysdep_start. */
526 #define DL_PLATFORM_INIT dl_platform_init ()
528 static inline void __attribute__ ((unused))
529 dl_platform_init (void)
531 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
532 /* Avoid an empty string which would disturb us. */
533 GLRO(dl_platform) = NULL;
536 #endif /* !dl_machine_h */
538 /* These are only actually used where RESOLVE_MAP is defined, anyway. */
539 #ifdef RESOLVE_MAP
541 #define reassemble_21(as21) \
542 ( (((as21) & 0x100000) >> 20) \
543 | (((as21) & 0x0ffe00) >> 8) \
544 | (((as21) & 0x000180) << 7) \
545 | (((as21) & 0x00007c) << 14) \
546 | (((as21) & 0x000003) << 12))
548 #define reassemble_14(as14) \
549 ( (((as14) & 0x1fff) << 1) \
550 | (((as14) & 0x2000) >> 13))
552 auto void __attribute__((always_inline))
553 elf_machine_rela (struct link_map *map,
554 const Elf32_Rela *reloc,
555 const Elf32_Sym *sym,
556 const struct r_found_version *version,
557 void *const reloc_addr_arg,
558 int skip_ifunc)
560 Elf32_Addr *const reloc_addr = reloc_addr_arg;
561 const Elf32_Sym *const refsym = sym;
562 unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
563 struct link_map *sym_map;
564 Elf32_Addr value;
566 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED
567 /* This is defined in rtld.c, but nowhere in the static libc.a; make the
568 reference weak so static programs can still link. This declaration
569 cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP)
570 because rtld.c contains the common defn for _dl_rtld_map, which is
571 incompatible with a weak decl in the same file. */
572 weak_extern (GL(dl_rtld_map));
573 # endif
575 /* RESOLVE_MAP will return a null value for undefined syms, and
576 non-null for all other syms. In particular, relocs with no
577 symbol (symbol index of zero), also called *ABS* relocs, will be
578 resolved to MAP. (The first entry in a symbol table is all
579 zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
580 See RESOLVE_MAP definition in elf/dl-reloc.c */
581 # ifdef RTLD_BOOTSTRAP
582 /* RESOLVE_MAP in rtld.c doesn't have the local sym test. */
583 sym_map = (ELF32_ST_BIND (sym->st_info) != STB_LOCAL
584 ? RESOLVE_MAP (&sym, version, r_type) : map);
585 # else
586 sym_map = RESOLVE_MAP (&sym, version, r_type);
587 # endif
589 if (sym_map)
591 value = SYMBOL_ADDRESS (sym_map, sym, true);
592 value += reloc->r_addend;
594 else
595 value = 0;
597 switch (r_type)
599 case R_PARISC_DIR32:
600 /* .eh_frame can have unaligned relocs. */
601 if ((unsigned long) reloc_addr_arg & 3)
603 char *rel_addr = (char *) reloc_addr_arg;
604 rel_addr[0] = value >> 24;
605 rel_addr[1] = value >> 16;
606 rel_addr[2] = value >> 8;
607 rel_addr[3] = value;
608 return;
610 break;
612 case R_PARISC_DIR21L:
614 unsigned int insn = *(unsigned int *)reloc_addr;
615 value = (SYMBOL_ADDRESS (sym_map, sym, true)
616 + ((reloc->r_addend + 0x1000) & -0x2000));
617 value = value >> 11;
618 insn = (insn &~ 0x1fffff) | reassemble_21 (value);
619 *(unsigned int *)reloc_addr = insn;
621 return;
623 case R_PARISC_DIR14R:
625 unsigned int insn = *(unsigned int *)reloc_addr;
626 value = ((SYMBOL_ADDRESS (sym_map, sym, true) & 0x7ff)
627 + (((reloc->r_addend & 0x1fff) ^ 0x1000) - 0x1000));
628 insn = (insn &~ 0x3fff) | reassemble_14 (value);
629 *(unsigned int *)reloc_addr = insn;
631 return;
633 case R_PARISC_PLABEL32:
634 /* Easy rule: If there is a symbol and it is global, then we
635 need to make a dynamic function descriptor. Otherwise we
636 have the address of a PLT slot for a local symbol which we
637 know to be unique. */
638 if (sym == NULL
639 || sym_map == NULL
640 || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
642 break;
644 /* Set bit 30 to indicate to $$dyncall that this is a PLABEL.
645 We have to do this outside of the generic function descriptor
646 code, since it doesn't know about our requirement for setting
647 protection bits */
648 value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
649 break;
651 case R_PARISC_PLABEL21L:
652 case R_PARISC_PLABEL14R:
654 unsigned int insn = *(unsigned int *)reloc_addr;
656 if (__builtin_expect (sym == NULL, 0))
657 break;
659 value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
661 if (r_type == R_PARISC_PLABEL21L)
663 value >>= 11;
664 insn = (insn &~ 0x1fffff) | reassemble_21 (value);
666 else
668 value &= 0x7ff;
669 insn = (insn &~ 0x3fff) | reassemble_14 (value);
672 *(unsigned int *)reloc_addr = insn;
674 return;
676 case R_PARISC_IPLT:
677 if (__builtin_expect (sym_map != NULL, 1))
679 elf_machine_fixup_plt (NULL, sym_map, NULL, NULL, reloc, reloc_addr,
680 DL_FIXUP_MAKE_VALUE(sym_map, value));
682 else
684 /* If we get here, it's a (weak) undefined sym. */
685 elf_machine_fixup_plt (NULL, map, NULL, NULL, reloc, reloc_addr,
686 DL_FIXUP_MAKE_VALUE(map, value));
688 return;
690 case R_PARISC_COPY:
691 if (__builtin_expect (sym == NULL, 0))
692 /* This can happen in trace mode if an object could not be
693 found. */
694 break;
695 if (__builtin_expect (sym->st_size > refsym->st_size, 0)
696 || (__builtin_expect (sym->st_size < refsym->st_size, 0)
697 && __builtin_expect (GLRO(dl_verbose), 0)))
699 const char *strtab;
701 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
702 _dl_error_printf ("%s: Symbol `%s' has different size in shared object, "
703 "consider re-linking\n",
704 RTLD_PROGNAME, strtab + refsym->st_name);
706 memcpy (reloc_addr_arg, (void *) value,
707 MIN (sym->st_size, refsym->st_size));
708 return;
710 #if !defined RTLD_BOOTSTRAP
711 case R_PARISC_TLS_DTPMOD32:
712 value = sym_map->l_tls_modid;
713 break;
715 case R_PARISC_TLS_DTPOFF32:
716 /* During relocation all TLS symbols are defined and used.
717 Therefore the offset is already correct. */
718 if (sym != NULL)
719 *reloc_addr = sym->st_value + reloc->r_addend;
720 return;
722 case R_PARISC_TLS_TPREL32:
723 /* The offset is negative, forward from the thread pointer */
724 if (sym != NULL)
726 CHECK_STATIC_TLS (map, sym_map);
727 value = sym_map->l_tls_offset + sym->st_value + reloc->r_addend;
729 break;
730 #endif /* use TLS */
732 case R_PARISC_NONE: /* Alright, Wilbur. */
733 return;
735 default:
736 _dl_reloc_bad_type (map, r_type, 0);
739 *reloc_addr = value;
742 /* hppa doesn't have an R_PARISC_RELATIVE reloc, but uses relocs with
743 ELF32_R_SYM (info) == 0 for a similar purpose. */
744 auto void __attribute__((always_inline))
745 elf_machine_rela_relative (Elf32_Addr l_addr,
746 const Elf32_Rela *reloc,
747 void *const reloc_addr_arg)
749 unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
750 Elf32_Addr *const reloc_addr = reloc_addr_arg;
751 static char msgbuf[] = { "Unknown" };
752 struct link_map map;
753 Elf32_Addr value;
755 value = l_addr + reloc->r_addend;
757 if (ELF32_R_SYM (reloc->r_info) != 0){
758 _dl_error_printf ("%s: In elf_machine_rela_relative "
759 "ELF32_R_SYM (reloc->r_info) != 0. Aborting.",
760 RTLD_PROGNAME);
761 ABORT_INSTRUCTION; /* Crash. */
764 switch (r_type)
766 case R_PARISC_DIR32:
767 /* .eh_frame can have unaligned relocs. */
768 if ((unsigned long) reloc_addr_arg & 3)
770 char *rel_addr = (char *) reloc_addr_arg;
771 rel_addr[0] = value >> 24;
772 rel_addr[1] = value >> 16;
773 rel_addr[2] = value >> 8;
774 rel_addr[3] = value;
775 return;
777 break;
779 case R_PARISC_PLABEL32:
780 break;
782 case R_PARISC_IPLT: /* elf_machine_runtime_setup already set gp */
783 break;
785 case R_PARISC_NONE:
786 return;
788 default: /* Bad reloc, map unknown (really it's the current map) */
789 map.l_name = msgbuf;
790 _dl_reloc_bad_type (&map, r_type, 0);
791 return;
794 *reloc_addr = value;
797 auto void __attribute__((always_inline))
798 elf_machine_lazy_rel (struct link_map *map,
799 Elf32_Addr l_addr, const Elf32_Rela *reloc,
800 int skip_ifunc)
802 /* We don't have anything to do here. elf_machine_runtime_setup has
803 done all the relocs already. */
806 #endif /* RESOLVE_MAP */