sparc64: Remove unwind information from signal return stubs [BZ#31244]
[glibc.git] / sysdeps / hppa / dl-machine.h
blob35e45289eb4297e2a7a134a6049216898b20880b
1 /* Machine-dependent ELF dynamic relocation inline functions. PA-RISC version.
2 Copyright (C) 1995-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library. If not, see
17 <https://www.gnu.org/licenses/>. */
19 #ifndef dl_machine_h
20 #define dl_machine_h 1
22 #define ELF_MACHINE_NAME "hppa"
24 #include <sys/param.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <link.h>
28 #include <errno.h>
29 #include <dl-fptr.h>
30 #include <abort-instr.h>
31 #include <tls.h>
32 #include <dl-static-tls.h>
33 #include <dl-machine-rel.h>
35 /* These two definitions must match the definition of the stub in
36 bfd/elf32-hppa.c (see plt_stub[]).
38 a. Define the size of the *entire* stub we place at the end of the PLT
39 table (right up against the GOT).
41 b. Define the number of bytes back from the GOT to the entry point of
42 the PLT stub. You see the PLT stub must be entered in the middle
43 so it can depwi to find it's own address (long jump stub)
45 c. Define the size of a single PLT entry so we can jump over the
46 last entry to get the stub address */
48 #define SIZEOF_PLT_STUB (7*4)
49 #define GOT_FROM_PLT_STUB (4*4)
50 #define PLT_ENTRY_SIZE (2*4)
52 /* The gp slot in the function descriptor contains the relocation offset
53 before resolution. To distinguish between a resolved gp value and an
54 unresolved relocation offset we set an unused bit in the relocation
55 offset. This would allow us to do a synchronzied two word update
56 using this bit (interlocked update), but instead of waiting for the
57 update we simply recompute the gp value given that we know the ip. */
58 #define PA_GP_RELOC 1
60 /* Initialize the function descriptor table before relocations */
61 static inline void
62 __hppa_init_bootstrap_fdesc_table (struct link_map *map)
64 ElfW(Addr) *boot_table;
66 /* Careful: this will be called before got has been relocated... */
67 ELF_MACHINE_LOAD_ADDRESS(boot_table,_dl_boot_fptr_table);
69 map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
70 map->l_mach.fptr_table = boot_table;
73 #define ELF_MACHINE_BEFORE_RTLD_RELOC(map, dynamic_info) \
74 __hppa_init_bootstrap_fdesc_table (map); \
75 _dl_fptr_init();
77 /* Return nonzero iff ELF header is compatible with the running host. */
78 static inline int
79 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
81 return ehdr->e_machine == EM_PARISC;
84 /* Return the link-time address of _DYNAMIC. */
85 static inline Elf32_Addr
86 elf_machine_dynamic (void) __attribute__ ((const));
88 static inline Elf32_Addr
89 elf_machine_dynamic (void)
91 Elf32_Addr dynamic;
93 asm ("bl 1f,%0\n"
94 " addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 1),%0\n"
95 "1: ldw R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
96 : "=r" (dynamic) : : "r1");
98 return dynamic;
101 /* Return the run-time load address of the shared object. */
102 static inline Elf32_Addr
103 elf_machine_load_address (void) __attribute__ ((const));
105 static inline Elf32_Addr
106 elf_machine_load_address (void)
108 Elf32_Addr dynamic;
110 asm (
111 " bl 1f,%0\n"
112 " addil L'_DYNAMIC - ($PIC_pcrel$0 - 1),%0\n"
113 "1: ldo R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
114 : "=r" (dynamic) : : "r1");
116 return dynamic - elf_machine_dynamic ();
119 /* Fixup a PLT entry to bounce directly to the function at VALUE. */
120 static inline struct fdesc __attribute__ ((always_inline))
121 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
122 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
123 const Elf32_Rela *reloc,
124 Elf32_Addr *reloc_addr, struct fdesc value)
126 volatile Elf32_Addr *rfdesc = reloc_addr;
127 /* map is the link_map for the caller, t is the link_map for the object
128 being called */
130 /* We would like the function descriptor to be double word aligned. This
131 helps performance (ip and gp then reside on the same cache line) and
132 we can update the pair atomically with a single store. The linker
133 now ensures this alignment but we still have to handle old code. */
134 if ((unsigned int)reloc_addr & 7)
136 /* Need to ensure that the gp is visible before the code
137 entry point is updated */
138 rfdesc[1] = value.gp;
139 atomic_full_barrier();
140 rfdesc[0] = value.ip;
142 else
144 /* Update pair atomically with floating point store. */
145 union { ElfW(Word) v[2]; double d; } u;
147 u.v[0] = value.ip;
148 u.v[1] = value.gp;
149 *(volatile double *)rfdesc = u.d;
151 return value;
154 /* Return the final value of a plt relocation. */
155 static inline struct fdesc
156 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
157 struct fdesc value)
159 /* We are rela only, return a function descriptor as a plt entry. */
160 return (struct fdesc) { value.ip + reloc->r_addend, value.gp };
163 /* Set up the loaded object described by L so its unrelocated PLT
164 entries will jump to the on-demand fixup code in dl-runtime.c. */
166 static inline int
167 elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
168 int lazy, int profile)
170 Elf32_Addr *got = NULL;
171 Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type, r_sym;
172 const Elf32_Rela *reloc;
173 struct fdesc *fptr;
174 static union {
175 unsigned char c[8];
176 Elf32_Addr i[2];
177 } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
179 /* Initialize dp register for main executable. */
180 if (l->l_main_map)
182 register Elf32_Addr dp asm ("%r27");
184 dp = D_PTR (l, l_info[DT_PLTGOT]);
185 asm volatile ("" : : "r" (dp));
188 /* If we don't have a PLT we can just skip all this... */
189 if (__builtin_expect (l->l_info[DT_JMPREL] == NULL,0))
190 return lazy;
192 /* All paths use these values */
193 l_addr = l->l_addr;
194 jmprel = D_PTR(l, l_info[DT_JMPREL]);
195 end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
197 extern void _dl_runtime_resolve (void);
199 /* Linking lazily */
200 if (lazy)
202 /* FIXME: Search for the got, but backwards through the relocs, technically we should
203 find it on the first try. However, assuming the relocs got out of order the
204 routine is made a bit more robust by searching them all in case of failure. */
205 for (iplt = (end_jmprel - sizeof (Elf32_Rela)); iplt >= jmprel; iplt -= sizeof (Elf32_Rela))
208 reloc = (const Elf32_Rela *) iplt;
209 r_type = ELF32_R_TYPE (reloc->r_info);
210 r_sym = ELF32_R_SYM (reloc->r_info);
212 got = (Elf32_Addr *) (reloc->r_offset + l_addr + PLT_ENTRY_SIZE + SIZEOF_PLT_STUB);
214 /* If we aren't an IPLT, and we aren't NONE then it's a bad reloc */
215 if (__builtin_expect (r_type != R_PARISC_IPLT, 0))
217 if (__builtin_expect (r_type != R_PARISC_NONE, 0))
218 _dl_reloc_bad_type (l, r_type, 1);
219 continue;
222 /* Check for the plt_stub that binutils placed here for us
223 to use with _dl_runtime_resolve */
224 if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
226 got = NULL; /* Not the stub... keep looking */
228 else
230 /* Found the GOT! */
231 register Elf32_Addr ltp __asm__ ("%r19");
233 /* Identify this shared object. Second entry in the got. */
234 got[1] = (Elf32_Addr) l;
236 /* This function will be called to perform the relocation. */
237 #ifdef SHARED
238 extern void _dl_runtime_profile (void);
239 if (__glibc_unlikely (profile))
241 if (GLRO(dl_profile) != NULL
242 && _dl_name_match_p (GLRO(dl_profile), l))
244 /* This is the object we are looking for. Say that
245 we really want profiling and the timers are
246 started. */
247 GL(dl_profile_map) = l;
250 if((unsigned long) &_dl_runtime_profile & 3)
252 got[-2] = (Elf32_Addr) ((struct fdesc *)
253 ((unsigned long) &_dl_runtime_profile & ~3))->ip;
255 else
257 /* Static executable */
258 got[-2] = (Elf32_Addr) &_dl_runtime_profile;
261 else
262 #endif
264 /* If a static application called us, then _dl_runtime_resolve is not
265 a function descriptor, but the *real* address of the function... */
266 if((unsigned long) &_dl_runtime_resolve & 3)
268 got[-2] = (Elf32_Addr) ((struct fdesc *)
269 ((unsigned long) &_dl_runtime_resolve & ~3))->ip;
271 else
273 /* Static executable! */
274 got[-2] = (Elf32_Addr) &_dl_runtime_resolve;
277 /* Plunk in the gp of this function descriptor so we
278 can make the call to _dl_runtime_xxxxxx */
279 got[-1] = ltp;
280 break;
281 /* Done looking for the GOT, and stub is setup */
282 } /* else we found the GOT */
283 } /* for, walk the relocs backwards */
285 if(!got)
286 return 0; /* No lazy linking for you! */
288 /* Process all the relocs, now that we know the GOT... */
289 for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
291 reloc = (const Elf32_Rela *) iplt;
292 r_type = ELF32_R_TYPE (reloc->r_info);
293 r_sym = ELF32_R_SYM (reloc->r_info);
295 if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
297 fptr = (struct fdesc *) (reloc->r_offset + l_addr);
298 if (r_sym != 0)
300 /* Relocate the pointer to the stub. */
301 fptr->ip = (Elf32_Addr) got - GOT_FROM_PLT_STUB;
303 /* Instead of the LTP value, we put the reloc offset
304 here. The trampoline code will load the proper
305 LTP and pass the reloc offset to the fixup
306 function. */
307 fptr->gp = (iplt - jmprel) | PA_GP_RELOC;
308 } /* r_sym != 0 */
309 else
311 /* Relocate this *ABS* entry. */
312 fptr->ip = reloc->r_addend + l_addr;
313 fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
315 } /* r_type == R_PARISC_IPLT */
316 } /* for all the relocations */
317 } /* if lazy */
318 else
320 for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
322 reloc = (const Elf32_Rela *) iplt;
323 r_type = ELF32_R_TYPE (reloc->r_info);
324 r_sym = ELF32_R_SYM (reloc->r_info);
326 if (__builtin_expect ((r_type == R_PARISC_IPLT) && (r_sym == 0), 1))
328 fptr = (struct fdesc *) (reloc->r_offset + l_addr);
329 /* Relocate this *ABS* entry, set only the gp, the rest is set later
330 when elf_machine_rela_relative is called (WITHOUT the linkmap) */
331 fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
332 } /* r_type == R_PARISC_IPLT */
333 } /* for all the relocations */
335 return lazy;
339 /* Names of the architecture-specific auditing callback functions. */
340 #define ARCH_LA_PLTENTER hppa_gnu_pltenter
341 #define ARCH_LA_PLTEXIT hppa_gnu_pltexit
343 /* Adjust DL_STACK_END to get value we want in __libc_stack_end. */
344 #define DL_STACK_END(cookie) \
345 ((void *) (((long) (cookie)) + 0x160))
347 /* Initial entry point code for the dynamic linker.
348 The C function `_dl_start' is the real entry point;
349 its return value is the user program's entry point. */
351 #define RTLD_START \
352 /* Set up dp for any non-PIC lib constructors that may be called. */ \
353 static struct link_map * __attribute__((used)) \
354 set_dp (struct link_map *map) \
356 register Elf32_Addr dp asm ("%r27"); \
357 dp = D_PTR (map, l_info[DT_PLTGOT]); \
358 asm volatile ("" : : "r" (dp)); \
359 return map; \
362 asm ( \
363 " .text\n" \
364 " .globl _start\n" \
365 " .type _start,@function\n" \
366 "_start:\n" \
367 /* The kernel does not give us an initial stack frame. */ \
368 " ldo 64(%sp),%sp\n" \
370 /* We need the LTP, and we need it now. \
371 $PIC_pcrel$0 points 8 bytes past the current instruction, \
372 just like a branch reloc. This sequence gets us the \
373 runtime address of _DYNAMIC. */ \
374 " bl 0f,%r19\n" \
375 " addil L'_DYNAMIC - ($PIC_pcrel$0 - 1),%r19\n" \
376 "0: ldo R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%r1),%r26\n" \
378 /* The link time address is stored in the first entry of the \
379 GOT. */ \
380 " addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 9),%r19\n" \
381 " ldw R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 13)(%r1),%r20\n" \
383 " sub %r26,%r20,%r20\n" /* Calculate load offset */ \
385 /* Rummage through the dynamic entries, looking for \
386 DT_PLTGOT. */ \
387 " ldw,ma 8(%r26),%r19\n" \
388 "1: cmpib,=,n 3,%r19,2f\n" /* tag == DT_PLTGOT? */ \
389 " cmpib,<>,n 0,%r19,1b\n" \
390 " ldw,ma 8(%r26),%r19\n" \
392 /* Uh oh! We didn't find one. Abort. */ \
393 " iitlbp %r0,(%sr0,%r0)\n" \
395 "2: ldw -4(%r26),%r19\n" /* Found it, load value. */ \
396 " add %r19,%r20,%r19\n" /* And add the load offset. */ \
398 /* Our initial stack layout is rather different from everyone \
399 else's due to the unique PA-RISC ABI. As far as I know it \
400 looks like this: \
402 ----------------------------------- (this frame created above) \
403 | 32 bytes of magic | \
404 |---------------------------------| \
405 | 32 bytes argument/sp save area | \
406 |---------------------------------| ((current->mm->env_end) \
407 | N bytes of slack | + 63 & ~63) \
408 |---------------------------------| \
409 | envvar and arg strings | \
410 |---------------------------------| \
411 | ELF auxiliary info | \
412 | (up to 28 words) | \
413 |---------------------------------| \
414 | Environment variable pointers | \
415 | upwards to NULL | \
416 |---------------------------------| \
417 | Argument pointers | \
418 | upwards to NULL | \
419 |---------------------------------| \
420 | argc (1 word) | \
421 ----------------------------------- \
423 So, obviously, we can't just pass %sp to _dl_start. That's \
424 okay, argv-4 will do just fine. \
426 This is always within range so we'll be okay. */ \
427 " bl _dl_start,%rp\n" \
428 " ldo -4(%r24),%r26\n" \
430 " .globl _dl_start_user\n" \
431 " .type _dl_start_user,@function\n" \
432 "_dl_start_user:\n" \
433 /* Save the entry point in %r3. */ \
434 " copy %ret0,%r3\n" \
436 /* The loader adjusts argc, argv, env, and the aux vectors \
437 directly on the stack to remove any arguments used for \
438 direct loader invocation. Thus, argc and argv must be \
439 reloaded from from _dl_argc and _dl_argv. */ \
441 /* Load main_map from _rtld_local and setup dp. */ \
442 " addil LT'_rtld_local,%r19\n" \
443 " ldw RT'_rtld_local(%r1),%r26\n" \
444 " bl set_dp, %r2\n" \
445 " ldw 0(%r26),%r26\n" \
446 " copy %ret0,%r26\n" \
448 /* Load argc from _dl_argc. */ \
449 " addil LT'_dl_argc,%r19\n" \
450 " ldw RT'_dl_argc(%r1),%r20\n" \
451 " ldw 0(%r20),%r25\n" \
452 " stw %r25,-40(%sp)\n" \
454 /* Same for argv with _dl_argv. */ \
455 " addil LT'_dl_argv,%r19\n" \
456 " ldw RT'_dl_argv(%r1),%r20\n" \
457 " ldw 0(%r20),%r24\n" \
458 " stw %r24,-44(%sp)\n" \
460 /* envp = argv + argc + 1 */ \
461 " sh2add %r25,%r24,%r23\n" \
463 /* Call _dl_init(main_map, argc, argv, envp). */ \
464 " bl _dl_init,%r2\n" \
465 " ldo 4(%r23),%r23\n" /* delay slot */ \
467 /* Reload argc, argv to the registers start.S expects. */ \
468 " ldw -40(%sp),%r25\n" \
469 " ldw -44(%sp),%r24\n" \
471 /* _dl_fini is a local function in the loader, so we construct \
472 a false OPD here and pass this to the application. */ \
473 /* FIXME: Should be able to use P%, and LR RR to have the \
474 the linker construct a proper OPD. */ \
475 " .section .data\n" \
476 "__dl_fini_plabel:\n" \
477 " .word _dl_fini\n" \
478 " .word 0xdeadbeef\n" \
479 " .previous\n" \
481 /* %r3 contains a function pointer, we need to mask out the \
482 lower bits and load the gp and jump address. */ \
483 " depi 0,31,2,%r3\n" \
484 " ldw 0(%r3),%r2\n" \
485 " addil LT'__dl_fini_plabel,%r19\n" \
486 " ldw RT'__dl_fini_plabel(%r1),%r23\n" \
487 " stw %r19,4(%r23)\n" \
488 " ldw 4(%r3),%r19\n" /* load the object's gp */ \
489 " bv %r0(%r2)\n" \
490 " depi 2,31,2,%r23\n" /* delay slot */ \
493 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
494 a TLS variable, so references should not be allowed to define the value.
495 ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
496 of the main executable's symbols, as for a COPY reloc. */
497 #if !defined RTLD_BOOTSTRAP
498 # define elf_machine_type_class(type) \
499 ((((type) == R_PARISC_IPLT \
500 || (type) == R_PARISC_EPLT \
501 || (type) == R_PARISC_TLS_DTPMOD32 \
502 || (type) == R_PARISC_TLS_DTPOFF32 \
503 || (type) == R_PARISC_TLS_TPREL32) \
504 * ELF_RTYPE_CLASS_PLT) \
505 | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
506 #else
507 #define elf_machine_type_class(type) \
508 ((((type) == R_PARISC_IPLT \
509 || (type) == R_PARISC_EPLT) \
510 * ELF_RTYPE_CLASS_PLT) \
511 | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
512 #endif
514 /* Used by the runtime in fixup to figure out if reloc is *really* PLT */
515 #define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
516 #define ELF_MACHINE_SIZEOF_JMP_SLOT PLT_ENTRY_SIZE
518 /* Return the address of the entry point. */
519 #define ELF_MACHINE_START_ADDRESS(map, start) \
520 ({ \
521 ElfW(Addr) addr; \
522 DL_DT_FUNCTION_ADDRESS(map, start, static, addr) \
523 addr; \
526 /* We define an initialization functions. This is called very early in
527 * _dl_sysdep_start. */
528 #define DL_PLATFORM_INIT dl_platform_init ()
530 static inline void __attribute__ ((unused))
531 dl_platform_init (void)
533 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
534 /* Avoid an empty string which would disturb us. */
535 GLRO(dl_platform) = NULL;
538 #endif /* !dl_machine_h */
540 /* These are only actually used where RESOLVE_MAP is defined, anyway. */
541 #ifdef RESOLVE_MAP
543 #define reassemble_21(as21) \
544 ( (((as21) & 0x100000) >> 20) \
545 | (((as21) & 0x0ffe00) >> 8) \
546 | (((as21) & 0x000180) << 7) \
547 | (((as21) & 0x00007c) << 14) \
548 | (((as21) & 0x000003) << 12))
550 #define reassemble_14(as14) \
551 ( (((as14) & 0x1fff) << 1) \
552 | (((as14) & 0x2000) >> 13))
554 static void __attribute__((always_inline))
555 elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
556 const Elf32_Rela *reloc,
557 const Elf32_Sym *sym,
558 const struct r_found_version *version,
559 void *const reloc_addr_arg,
560 int skip_ifunc)
562 Elf32_Addr *const reloc_addr = reloc_addr_arg;
563 const Elf32_Sym *const refsym = sym;
564 unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
565 struct link_map *sym_map;
566 Elf32_Addr value;
568 /* RESOLVE_MAP will return a null value for undefined syms, and
569 non-null for all other syms. In particular, relocs with no
570 symbol (symbol index of zero), also called *ABS* relocs, will be
571 resolved to MAP. (The first entry in a symbol table is all
572 zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
573 See RESOLVE_MAP definition in elf/dl-reloc.c */
574 # ifdef RTLD_BOOTSTRAP
575 sym_map = map;
576 # else
577 sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type);
578 # endif
580 if (sym_map)
582 value = SYMBOL_ADDRESS (sym_map, sym, true);
583 value += reloc->r_addend;
585 else
586 value = 0;
588 switch (r_type)
590 case R_PARISC_DIR32:
591 /* .eh_frame can have unaligned relocs. */
592 if ((unsigned long) reloc_addr_arg & 3)
594 char *rel_addr = (char *) reloc_addr_arg;
595 rel_addr[0] = value >> 24;
596 rel_addr[1] = value >> 16;
597 rel_addr[2] = value >> 8;
598 rel_addr[3] = value;
599 return;
601 break;
603 case R_PARISC_DIR21L:
605 unsigned int insn = *(unsigned int *)reloc_addr;
606 value = (SYMBOL_ADDRESS (sym_map, sym, true)
607 + ((reloc->r_addend + 0x1000) & -0x2000));
608 value = value >> 11;
609 insn = (insn &~ 0x1fffff) | reassemble_21 (value);
610 *(unsigned int *)reloc_addr = insn;
612 return;
614 case R_PARISC_DIR14R:
616 unsigned int insn = *(unsigned int *)reloc_addr;
617 value = ((SYMBOL_ADDRESS (sym_map, sym, true) & 0x7ff)
618 + (((reloc->r_addend & 0x1fff) ^ 0x1000) - 0x1000));
619 insn = (insn &~ 0x3fff) | reassemble_14 (value);
620 *(unsigned int *)reloc_addr = insn;
622 return;
624 case R_PARISC_PLABEL32:
625 /* Easy rule: If there is a symbol and it is global, then we
626 need to make a dynamic function descriptor. Otherwise we
627 have the address of a PLT slot for a local symbol which we
628 know to be unique. */
629 if (sym == NULL
630 || sym_map == NULL
631 || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
633 break;
635 /* Set bit 30 to indicate to $$dyncall that this is a PLABEL.
636 We have to do this outside of the generic function descriptor
637 code, since it doesn't know about our requirement for setting
638 protection bits */
639 value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
640 break;
642 case R_PARISC_PLABEL21L:
643 case R_PARISC_PLABEL14R:
645 unsigned int insn = *(unsigned int *)reloc_addr;
647 if (__builtin_expect (sym == NULL, 0))
648 break;
650 value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
652 if (r_type == R_PARISC_PLABEL21L)
654 value >>= 11;
655 insn = (insn &~ 0x1fffff) | reassemble_21 (value);
657 else
659 value &= 0x7ff;
660 insn = (insn &~ 0x3fff) | reassemble_14 (value);
663 *(unsigned int *)reloc_addr = insn;
665 return;
667 case R_PARISC_IPLT:
668 if (__builtin_expect (sym_map != NULL, 1))
670 elf_machine_fixup_plt (NULL, sym_map, NULL, NULL, reloc, reloc_addr,
671 DL_FIXUP_MAKE_VALUE(sym_map, value));
673 else
675 /* If we get here, it's a (weak) undefined sym. */
676 elf_machine_fixup_plt (NULL, map, NULL, NULL, reloc, reloc_addr,
677 DL_FIXUP_MAKE_VALUE(map, value));
679 return;
681 case R_PARISC_COPY:
682 if (__builtin_expect (sym == NULL, 0))
683 /* This can happen in trace mode if an object could not be
684 found. */
685 break;
686 if (__builtin_expect (sym->st_size > refsym->st_size, 0)
687 || (__builtin_expect (sym->st_size < refsym->st_size, 0)
688 && __builtin_expect (GLRO(dl_verbose), 0)))
690 const char *strtab;
692 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
693 _dl_error_printf ("%s: Symbol `%s' has different size in shared object, "
694 "consider re-linking\n",
695 RTLD_PROGNAME, strtab + refsym->st_name);
697 memcpy (reloc_addr_arg, (void *) value,
698 MIN (sym->st_size, refsym->st_size));
699 return;
701 #if !defined RTLD_BOOTSTRAP
702 case R_PARISC_TLS_DTPMOD32:
703 value = sym_map->l_tls_modid;
704 break;
706 case R_PARISC_TLS_DTPOFF32:
707 /* During relocation all TLS symbols are defined and used.
708 Therefore the offset is already correct. */
709 if (sym != NULL)
710 *reloc_addr = sym->st_value + reloc->r_addend;
711 return;
713 case R_PARISC_TLS_TPREL32:
714 /* The offset is negative, forward from the thread pointer */
715 if (sym != NULL)
717 CHECK_STATIC_TLS (map, sym_map);
718 value = sym_map->l_tls_offset + sym->st_value + reloc->r_addend;
720 break;
721 #endif /* use TLS */
723 case R_PARISC_NONE: /* Alright, Wilbur. */
724 return;
726 default:
727 _dl_reloc_bad_type (map, r_type, 0);
730 *reloc_addr = value;
733 /* hppa doesn't have an R_PARISC_RELATIVE reloc, but uses relocs with
734 ELF32_R_SYM (info) == 0 for a similar purpose. */
735 static void __attribute__((always_inline))
736 elf_machine_rela_relative (Elf32_Addr l_addr,
737 const Elf32_Rela *reloc,
738 void *const reloc_addr_arg)
740 unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
741 Elf32_Addr *const reloc_addr = reloc_addr_arg;
742 static char msgbuf[] = { "Unknown" };
743 struct link_map map;
744 Elf32_Addr value;
746 value = l_addr + reloc->r_addend;
748 if (ELF32_R_SYM (reloc->r_info) != 0){
749 _dl_error_printf ("%s: In elf_machine_rela_relative "
750 "ELF32_R_SYM (reloc->r_info) != 0. Aborting.",
751 RTLD_PROGNAME);
752 ABORT_INSTRUCTION; /* Crash. */
755 switch (r_type)
757 case R_PARISC_DIR32:
758 /* .eh_frame can have unaligned relocs. */
759 if ((unsigned long) reloc_addr_arg & 3)
761 char *rel_addr = (char *) reloc_addr_arg;
762 rel_addr[0] = value >> 24;
763 rel_addr[1] = value >> 16;
764 rel_addr[2] = value >> 8;
765 rel_addr[3] = value;
766 return;
768 break;
770 case R_PARISC_PLABEL32:
771 break;
773 case R_PARISC_IPLT: /* elf_machine_runtime_setup already set gp */
774 break;
776 case R_PARISC_NONE:
777 return;
779 default: /* Bad reloc, map unknown (really it's the current map) */
780 map.l_name = msgbuf;
781 _dl_reloc_bad_type (&map, r_type, 0);
782 return;
785 *reloc_addr = value;
788 static void __attribute__((always_inline))
789 elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
790 Elf32_Addr l_addr, const Elf32_Rela *reloc,
791 int skip_ifunc)
793 /* We don't have anything to do here. elf_machine_runtime_setup has
794 done all the relocs already. */
797 #endif /* RESOLVE_MAP */