]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/hppa/dl-machine.h
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / hppa / dl-machine.h
CommitLineData
3eb9e706 1/* Machine-dependent ELF dynamic relocation inline functions. PA-RISC version.
6d7e8eda 2 Copyright (C) 1995-2023 Free Software Foundation, Inc.
3eb9e706
UD
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
3214b89b
AJ
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.
3eb9e706
UD
9
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
3214b89b 13 Lesser General Public License for more details.
3eb9e706 14
3214b89b 15 You should have received a copy of the GNU Lesser General Public
ab84e3ff 16 License along with the GNU C Library. If not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
3eb9e706
UD
18
19#ifndef dl_machine_h
20#define dl_machine_h 1
21
22#define ELF_MACHINE_NAME "hppa"
23
24#include <sys/param.h>
32e5b41b 25#include <assert.h>
3eb9e706
UD
26#include <string.h>
27#include <link.h>
32e5b41b
UD
28#include <errno.h>
29#include <dl-fptr.h>
30#include <abort-instr.h>
084442fc 31#include <tls.h>
d6d89608
AZ
32#include <dl-static-tls.h>
33#include <dl-machine-rel.h>
32e5b41b 34
09272d2c 35/* These two definitions must match the definition of the stub in
32e5b41b 36 bfd/elf32-hppa.c (see plt_stub[]).
09272d2c 37
32e5b41b
UD
38 a. Define the size of the *entire* stub we place at the end of the PLT
39 table (right up against the GOT).
09272d2c 40
32e5b41b
UD
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
09272d2c
AS
43 so it can depwi to find it's own address (long jump stub)
44
32e5b41b
UD
45 c. Define the size of a single PLT entry so we can jump over the
46 last entry to get the stub address */
09272d2c 47
32e5b41b 48#define SIZEOF_PLT_STUB (7*4)
3eb9e706 49#define GOT_FROM_PLT_STUB (4*4)
32e5b41b 50#define PLT_ENTRY_SIZE (2*4)
3eb9e706 51
1a044511
JDA
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
59
32e5b41b
UD
60/* Initialize the function descriptor table before relocations */
61static inline void
62__hppa_init_bootstrap_fdesc_table (struct link_map *map)
3eb9e706 63{
32e5b41b
UD
64 ElfW(Addr) *boot_table;
65
66 /* Careful: this will be called before got has been relocated... */
67 ELF_MACHINE_LOAD_ADDRESS(boot_table,_dl_boot_fptr_table);
3eb9e706 68
32e5b41b
UD
69 map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
70 map->l_mach.fptr_table = boot_table;
71}
3eb9e706 72
490e6c62
FS
73#define ELF_MACHINE_BEFORE_RTLD_RELOC(map, dynamic_info) \
74 __hppa_init_bootstrap_fdesc_table (map); \
dde6fc78 75 _dl_fptr_init();
3eb9e706 76
f1dba308 77/* Return nonzero iff ELF header is compatible with the running host. */
3eb9e706 78static inline int
f1dba308 79elf_machine_matches_host (const Elf32_Ehdr *ehdr)
3eb9e706 80{
f1dba308 81 return ehdr->e_machine == EM_PARISC;
3eb9e706
UD
82}
83
3eb9e706 84/* Return the link-time address of _DYNAMIC. */
32e5b41b
UD
85static inline Elf32_Addr
86elf_machine_dynamic (void) __attribute__ ((const));
87
3eb9e706
UD
88static inline Elf32_Addr
89elf_machine_dynamic (void)
90{
91 Elf32_Addr dynamic;
92
800a496a
JDA
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"
32e5b41b 96 : "=r" (dynamic) : : "r1");
3eb9e706
UD
97
98 return dynamic;
99}
100
101/* Return the run-time load address of the shared object. */
32e5b41b
UD
102static inline Elf32_Addr
103elf_machine_load_address (void) __attribute__ ((const));
104
3eb9e706
UD
105static inline Elf32_Addr
106elf_machine_load_address (void)
107{
32e5b41b 108 Elf32_Addr dynamic;
3eb9e706 109
1e48d4f6 110 asm (
800a496a
JDA
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"
32e5b41b 114 : "=r" (dynamic) : : "r1");
3eb9e706 115
32e5b41b 116 return dynamic - elf_machine_dynamic ();
3eb9e706
UD
117}
118
09272d2c
AS
119/* Fixup a PLT entry to bounce directly to the function at VALUE. */
120static inline struct fdesc __attribute__ ((always_inline))
3eb9e706 121elf_machine_fixup_plt (struct link_map *map, lookup_t t,
0572433b 122 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
3eb9e706 123 const Elf32_Rela *reloc,
084442fc 124 Elf32_Addr *reloc_addr, struct fdesc value)
3eb9e706 125{
0daa0500 126 volatile Elf32_Addr *rfdesc = reloc_addr;
32e5b41b
UD
127 /* map is the link_map for the caller, t is the link_map for the object
128 being called */
1a044511
JDA
129
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)
135 {
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;
141 }
142 else
143 {
144 /* Update pair atomically with floating point store. */
145 union { ElfW(Word) v[2]; double d; } u;
146
147 u.v[0] = value.ip;
148 u.v[1] = value.gp;
149 *(volatile double *)rfdesc = u.d;
150 }
084442fc 151 return value;
32e5b41b
UD
152}
153
3eb9e706 154/* Return the final value of a plt relocation. */
09272d2c 155static inline struct fdesc
3eb9e706 156elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
084442fc 157 struct fdesc value)
3eb9e706 158{
084442fc
CD
159 /* We are rela only, return a function descriptor as a plt entry. */
160 return (struct fdesc) { value.ip + reloc->r_addend, value.gp };
3eb9e706
UD
161}
162
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. */
165
166static inline int
490e6c62
FS
167elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
168 int lazy, int profile)
3eb9e706 169{
32e5b41b
UD
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}};
09272d2c 178
2e20cd63
JDA
179 /* Initialize dp register for main executable. */
180 if (l->l_main_map)
181 {
182 register Elf32_Addr dp asm ("%r27");
183
184 dp = D_PTR (l, l_info[DT_PLTGOT]);
185 asm volatile ("" : : "r" (dp));
186 }
187
32e5b41b
UD
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;
09272d2c
AS
191
192 /* All paths use these values */
32e5b41b
UD
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;
09272d2c 196
3eb9e706
UD
197 extern void _dl_runtime_resolve (void);
198 extern void _dl_runtime_profile (void);
09272d2c 199
32e5b41b
UD
200 /* Linking lazily */
201 if (lazy)
3eb9e706 202 {
32e5b41b 203 /* FIXME: Search for the got, but backwards through the relocs, technically we should
09272d2c
AS
204 find it on the first try. However, assuming the relocs got out of order the
205 routine is made a bit more robust by searching them all in case of failure. */
c4f50205 206 for (iplt = (end_jmprel - sizeof (Elf32_Rela)); iplt >= jmprel; iplt -= sizeof (Elf32_Rela))
09272d2c
AS
207 {
208
32e5b41b 209 reloc = (const Elf32_Rela *) iplt;
09272d2c
AS
210 r_type = ELF32_R_TYPE (reloc->r_info);
211 r_sym = ELF32_R_SYM (reloc->r_info);
32e5b41b 212
09272d2c 213 got = (Elf32_Addr *) (reloc->r_offset + l_addr + PLT_ENTRY_SIZE + SIZEOF_PLT_STUB);
32e5b41b 214
09272d2c
AS
215 /* If we aren't an IPLT, and we aren't NONE then it's a bad reloc */
216 if (__builtin_expect (r_type != R_PARISC_IPLT, 0))
32e5b41b
UD
217 {
218 if (__builtin_expect (r_type != R_PARISC_NONE, 0))
09272d2c 219 _dl_reloc_bad_type (l, r_type, 1);
32e5b41b
UD
220 continue;
221 }
09272d2c
AS
222
223 /* Check for the plt_stub that binutils placed here for us
224 to use with _dl_runtime_resolve */
225 if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
226 {
227 got = NULL; /* Not the stub... keep looking */
228 }
229 else
32e5b41b 230 {
09272d2c
AS
231 /* Found the GOT! */
232 register Elf32_Addr ltp __asm__ ("%r19");
233
234 /* Identify this shared object. Second entry in the got. */
235 got[1] = (Elf32_Addr) l;
236
237 /* This function will be called to perform the relocation. */
238 if (__builtin_expect (!profile, 1))
239 {
240 /* If a static application called us, then _dl_runtime_resolve is not
32e5b41b
UD
241 a function descriptor, but the *real* address of the function... */
242 if((unsigned long) &_dl_runtime_resolve & 3)
243 {
09272d2c
AS
244 got[-2] = (Elf32_Addr) ((struct fdesc *)
245 ((unsigned long) &_dl_runtime_resolve & ~3))->ip;
32e5b41b
UD
246 }
247 else
248 {
249 /* Static executable! */
09272d2c 250 got[-2] = (Elf32_Addr) &_dl_runtime_resolve;
32e5b41b 251 }
09272d2c
AS
252 }
253 else
254 {
255 if (GLRO(dl_profile) != NULL
084442fc 256 && _dl_name_match_p (GLRO(dl_profile), l))
09272d2c 257 {
32e5b41b 258 /* This is the object we are looking for. Say that
09272d2c
AS
259 we really want profiling and the timers are
260 started. */
261 GL(dl_profile_map) = l;
262 }
32e5b41b 263
370b2f2c 264 if((unsigned long) &_dl_runtime_profile & 3)
32e5b41b 265 {
09272d2c
AS
266 got[-2] = (Elf32_Addr) ((struct fdesc *)
267 ((unsigned long) &_dl_runtime_profile & ~3))->ip;
32e5b41b
UD
268 }
269 else
270 {
271 /* Static executable */
09272d2c 272 got[-2] = (Elf32_Addr) &_dl_runtime_profile;
32e5b41b 273 }
09272d2c
AS
274 }
275 /* Plunk in the gp of this function descriptor so we
276 can make the call to _dl_runtime_xxxxxx */
277 got[-1] = ltp;
278 break;
279 /* Done looking for the GOT, and stub is setup */
280 } /* else we found the GOT */
281 } /* for, walk the relocs backwards */
282
283 if(!got)
284 return 0; /* No lazy linking for you! */
285
286 /* Process all the relocs, now that we know the GOT... */
3eb9e706
UD
287 for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
288 {
3eb9e706
UD
289 reloc = (const Elf32_Rela *) iplt;
290 r_type = ELF32_R_TYPE (reloc->r_info);
291 r_sym = ELF32_R_SYM (reloc->r_info);
292
293 if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
294 {
32e5b41b 295 fptr = (struct fdesc *) (reloc->r_offset + l_addr);
3eb9e706
UD
296 if (r_sym != 0)
297 {
298 /* Relocate the pointer to the stub. */
32e5b41b
UD
299 fptr->ip = (Elf32_Addr) got - GOT_FROM_PLT_STUB;
300
3eb9e706
UD
301 /* Instead of the LTP value, we put the reloc offset
302 here. The trampoline code will load the proper
303 LTP and pass the reloc offset to the fixup
304 function. */
1a044511 305 fptr->gp = (iplt - jmprel) | PA_GP_RELOC;
32e5b41b 306 } /* r_sym != 0 */
3eb9e706
UD
307 else
308 {
309 /* Relocate this *ABS* entry. */
32e5b41b 310 fptr->ip = reloc->r_addend + l_addr;
3eb9e706
UD
311 fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
312 }
32e5b41b 313 } /* r_type == R_PARISC_IPLT */
09272d2c 314 } /* for all the relocations */
32e5b41b
UD
315 } /* if lazy */
316 else
317 {
318 for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
09272d2c
AS
319 {
320 reloc = (const Elf32_Rela *) iplt;
321 r_type = ELF32_R_TYPE (reloc->r_info);
322 r_sym = ELF32_R_SYM (reloc->r_info);
323
324 if (__builtin_expect ((r_type == R_PARISC_IPLT) && (r_sym == 0), 1))
325 {
326 fptr = (struct fdesc *) (reloc->r_offset + l_addr);
327 /* Relocate this *ABS* entry, set only the gp, the rest is set later
328 when elf_machine_rela_relative is called (WITHOUT the linkmap) */
329 fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
330 } /* r_type == R_PARISC_IPLT */
331 } /* for all the relocations */
332 }
3eb9e706
UD
333 return lazy;
334}
335
084442fc
CD
336
337/* Names of the architecture-specific auditing callback functions. */
338#define ARCH_LA_PLTENTER hppa_gnu_pltenter
339#define ARCH_LA_PLTEXIT hppa_gnu_pltexit
340
5d20a49a
JDA
341/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */
342#define DL_STACK_END(cookie) \
343 ((void *) (((long) (cookie)) + 0x160))
344
3eb9e706
UD
345/* Initial entry point code for the dynamic linker.
346 The C function `_dl_start' is the real entry point;
347 its return value is the user program's entry point. */
348
c9ae5095 349#define RTLD_START \
b7bd9406
JDA
350/* Set up dp for any non-PIC lib constructors that may be called. */ \
351static struct link_map * __attribute__((used)) \
352set_dp (struct link_map *map) \
353{ \
354 register Elf32_Addr dp asm ("%r27"); \
355 dp = D_PTR (map, l_info[DT_PLTGOT]); \
356 asm volatile ("" : : "r" (dp)); \
357 return map; \
358} \
359 \
1e48d4f6
AJ
360asm ( \
361" .text\n" \
362" .globl _start\n" \
363" .type _start,@function\n" \
364"_start:\n" \
365 /* The kernel does not give us an initial stack frame. */ \
366" ldo 64(%sp),%sp\n" \
1e48d4f6 367 \
32e5b41b
UD
368 /* We need the LTP, and we need it now. \
369 $PIC_pcrel$0 points 8 bytes past the current instruction, \
370 just like a branch reloc. This sequence gets us the \
371 runtime address of _DYNAMIC. */ \
1e48d4f6 372" bl 0f,%r19\n" \
800a496a
JDA
373" addil L'_DYNAMIC - ($PIC_pcrel$0 - 1),%r19\n" \
374"0: ldo R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%r1),%r26\n" \
1e48d4f6 375 \
32e5b41b
UD
376 /* The link time address is stored in the first entry of the \
377 GOT. */ \
800a496a
JDA
378" addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 9),%r19\n" \
379" ldw R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 13)(%r1),%r20\n" \
1e48d4f6
AJ
380 \
381" sub %r26,%r20,%r20\n" /* Calculate load offset */ \
382 \
32e5b41b
UD
383 /* Rummage through the dynamic entries, looking for \
384 DT_PLTGOT. */ \
1e48d4f6
AJ
385" ldw,ma 8(%r26),%r19\n" \
386"1: cmpib,=,n 3,%r19,2f\n" /* tag == DT_PLTGOT? */ \
387" cmpib,<>,n 0,%r19,1b\n" \
388" ldw,ma 8(%r26),%r19\n" \
389 \
390 /* Uh oh! We didn't find one. Abort. */ \
084442fc 391" iitlbp %r0,(%sr0,%r0)\n" \
1e48d4f6
AJ
392 \
393"2: ldw -4(%r26),%r19\n" /* Found it, load value. */ \
394" add %r19,%r20,%r19\n" /* And add the load offset. */ \
395 \
396 /* Our initial stack layout is rather different from everyone \
397 else's due to the unique PA-RISC ABI. As far as I know it \
398 looks like this: \
399 \
400 ----------------------------------- (this frame created above) \
401 | 32 bytes of magic | \
402 |---------------------------------| \
403 | 32 bytes argument/sp save area | \
32e5b41b
UD
404 |---------------------------------| ((current->mm->env_end) \
405 | N bytes of slack | + 63 & ~63) \
1e48d4f6
AJ
406 |---------------------------------| \
407 | envvar and arg strings | \
408 |---------------------------------| \
409 | ELF auxiliary info | \
410 | (up to 28 words) | \
411 |---------------------------------| \
412 | Environment variable pointers | \
413 | upwards to NULL | \
414 |---------------------------------| \
415 | Argument pointers | \
416 | upwards to NULL | \
417 |---------------------------------| \
418 | argc (1 word) | \
419 ----------------------------------- \
420 \
421 So, obviously, we can't just pass %sp to _dl_start. That's \
422 okay, argv-4 will do just fine. \
423 \
62426022 424 This is always within range so we'll be okay. */ \
1e48d4f6
AJ
425" bl _dl_start,%rp\n" \
426" ldo -4(%r24),%r26\n" \
427 \
428" .globl _dl_start_user\n" \
429" .type _dl_start_user,@function\n" \
430"_dl_start_user:\n" \
431 /* Save the entry point in %r3. */ \
432" copy %ret0,%r3\n" \
1e48d4f6 433 \
62426022
AZ
434 /* The loader adjusts argc, argv, env, and the aux vectors \
435 directly on the stack to remove any arguments used for \
436 direct loader invocation. Thus, argc and argv must be \
437 reloaded from from _dl_argc and _dl_argv. */ \
1e48d4f6 438 \
b7bd9406
JDA
439 /* Load main_map from _rtld_local and setup dp. */ \
440" addil LT'_rtld_local,%r19\n" \
441" ldw RT'_rtld_local(%r1),%r26\n" \
442" bl set_dp, %r2\n" \
443" ldw 0(%r26),%r26\n" \
444" copy %ret0,%r26\n" \
445 \
62426022
AZ
446 /* Load argc from _dl_argc. */ \
447" addil LT'_dl_argc,%r19\n" \
448" ldw RT'_dl_argc(%r1),%r20\n" \
449" ldw 0(%r20),%r25\n" \
1e48d4f6 450" stw %r25,-40(%sp)\n" \
62426022
AZ
451 \
452 /* Same for argv with _dl_argv. */ \
453" addil LT'_dl_argv,%r19\n" \
454" ldw RT'_dl_argv(%r1),%r20\n" \
455" ldw 0(%r20),%r24\n" \
1e48d4f6
AJ
456" stw %r24,-44(%sp)\n" \
457 \
1e48d4f6
AJ
458 /* envp = argv + argc + 1 */ \
459" sh2add %r25,%r24,%r23\n" \
b7bd9406
JDA
460 \
461 /* Call _dl_init(main_map, argc, argv, envp). */ \
c5684fdb 462" bl _dl_init,%r2\n" \
1e48d4f6
AJ
463" ldo 4(%r23),%r23\n" /* delay slot */ \
464 \
32e5b41b 465 /* Reload argc, argv to the registers start.S expects. */ \
1e48d4f6
AJ
466" ldw -40(%sp),%r25\n" \
467" ldw -44(%sp),%r24\n" \
468 \
2625a1fb 469 /* _dl_fini is a local function in the loader, so we construct \
09272d2c 470 a false OPD here and pass this to the application. */ \
2625a1fb
CD
471 /* FIXME: Should be able to use P%, and LR RR to have the \
472 the linker construct a proper OPD. */ \
1e48d4f6
AJ
473" .section .data\n" \
474"__dl_fini_plabel:\n" \
475" .word _dl_fini\n" \
476" .word 0xdeadbeef\n" \
477" .previous\n" \
478 \
32e5b41b
UD
479 /* %r3 contains a function pointer, we need to mask out the \
480 lower bits and load the gp and jump address. */ \
1e48d4f6
AJ
481" depi 0,31,2,%r3\n" \
482" ldw 0(%r3),%r2\n" \
483" addil LT'__dl_fini_plabel,%r19\n" \
484" ldw RT'__dl_fini_plabel(%r1),%r23\n" \
485" stw %r19,4(%r23)\n" \
486" ldw 4(%r3),%r19\n" /* load the object's gp */ \
487" bv %r0(%r2)\n" \
488" depi 2,31,2,%r23\n" /* delay slot */ \
084442fc 489);
3eb9e706 490
09272d2c 491/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
084442fc 492 a TLS variable, so references should not be allowed to define the value.
209826bc 493 ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
5c6029e5 494 of the main executable's symbols, as for a COPY reloc. */
43329fe1 495#if !defined RTLD_BOOTSTRAP
084442fc 496# define elf_machine_type_class(type) \
5abebba4 497 ((((type) == R_PARISC_IPLT \
084442fc
CD
498 || (type) == R_PARISC_EPLT \
499 || (type) == R_PARISC_TLS_DTPMOD32 \
500 || (type) == R_PARISC_TLS_DTPOFF32 \
501 || (type) == R_PARISC_TLS_TPREL32) \
502 * ELF_RTYPE_CLASS_PLT) \
503 | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
504#else
5abebba4 505#define elf_machine_type_class(type) \
084442fc
CD
506 ((((type) == R_PARISC_IPLT \
507 || (type) == R_PARISC_EPLT) \
508 * ELF_RTYPE_CLASS_PLT) \
5c6029e5 509 | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
084442fc 510#endif
3eb9e706 511
32e5b41b 512/* Used by the runtime in fixup to figure out if reloc is *really* PLT */
3eb9e706 513#define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
32e5b41b 514#define ELF_MACHINE_SIZEOF_JMP_SLOT PLT_ENTRY_SIZE
3eb9e706 515
9c564366 516/* Return the address of the entry point. */
daf75146
GM
517#define ELF_MACHINE_START_ADDRESS(map, start) \
518({ \
519 ElfW(Addr) addr; \
520 DL_DT_FUNCTION_ADDRESS(map, start, static, addr) \
521 addr; \
522})
32e5b41b
UD
523
524/* We define an initialization functions. This is called very early in
525 * _dl_sysdep_start. */
526#define DL_PLATFORM_INIT dl_platform_init ()
9c564366 527
32e5b41b
UD
528static inline void __attribute__ ((unused))
529dl_platform_init (void)
530{
531 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
532 /* Avoid an empty string which would disturb us. */
533 GLRO(dl_platform) = NULL;
534}
09272d2c 535
3eb9e706
UD
536#endif /* !dl_machine_h */
537
538/* These are only actually used where RESOLVE_MAP is defined, anyway. */
539#ifdef RESOLVE_MAP
540
084442fc
CD
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))
547
548#define reassemble_14(as14) \
549 ( (((as14) & 0x1fff) << 1) \
550 | (((as14) & 0x2000) >> 13))
551
490e6c62
FS
552static void __attribute__((always_inline))
553elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
5abebba4 554 const Elf32_Rela *reloc,
09272d2c 555 const Elf32_Sym *sym,
084442fc 556 const struct r_found_version *version,
09272d2c
AS
557 void *const reloc_addr_arg,
558 int skip_ifunc)
3eb9e706 559{
5027ae10 560 Elf32_Addr *const reloc_addr = reloc_addr_arg;
3eb9e706
UD
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;
565
3eb9e706
UD
566 /* RESOLVE_MAP will return a null value for undefined syms, and
567 non-null for all other syms. In particular, relocs with no
568 symbol (symbol index of zero), also called *ABS* relocs, will be
569 resolved to MAP. (The first entry in a symbol table is all
570 zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
571 See RESOLVE_MAP definition in elf/dl-reloc.c */
32e5b41b 572# ifdef RTLD_BOOTSTRAP
490e6c62 573 sym_map = map;
32e5b41b 574# else
490e6c62 575 sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type);
32e5b41b 576# endif
09272d2c 577
3eb9e706
UD
578 if (sym_map)
579 {
10a446dd 580 value = SYMBOL_ADDRESS (sym_map, sym, true);
3eb9e706
UD
581 value += reloc->r_addend;
582 }
583 else
584 value = 0;
585
586 switch (r_type)
587 {
588 case R_PARISC_DIR32:
69ab1cbb 589 /* .eh_frame can have unaligned relocs. */
5027ae10 590 if ((unsigned long) reloc_addr_arg & 3)
69ab1cbb 591 {
5027ae10 592 char *rel_addr = (char *) reloc_addr_arg;
69ab1cbb
UD
593 rel_addr[0] = value >> 24;
594 rel_addr[1] = value >> 16;
595 rel_addr[2] = value >> 8;
596 rel_addr[3] = value;
597 return;
598 }
3eb9e706
UD
599 break;
600
084442fc
CD
601 case R_PARISC_DIR21L:
602 {
603 unsigned int insn = *(unsigned int *)reloc_addr;
10a446dd
MR
604 value = (SYMBOL_ADDRESS (sym_map, sym, true)
605 + ((reloc->r_addend + 0x1000) & -0x2000));
084442fc
CD
606 value = value >> 11;
607 insn = (insn &~ 0x1fffff) | reassemble_21 (value);
608 *(unsigned int *)reloc_addr = insn;
609 }
610 return;
611
612 case R_PARISC_DIR14R:
613 {
614 unsigned int insn = *(unsigned int *)reloc_addr;
10a446dd
MR
615 value = ((SYMBOL_ADDRESS (sym_map, sym, true) & 0x7ff)
616 + (((reloc->r_addend & 0x1fff) ^ 0x1000) - 0x1000));
084442fc
CD
617 insn = (insn &~ 0x3fff) | reassemble_14 (value);
618 *(unsigned int *)reloc_addr = insn;
619 }
620 return;
621
3eb9e706
UD
622 case R_PARISC_PLABEL32:
623 /* Easy rule: If there is a symbol and it is global, then we
09272d2c
AS
624 need to make a dynamic function descriptor. Otherwise we
625 have the address of a PLT slot for a local symbol which we
626 know to be unique. */
3eb9e706
UD
627 if (sym == NULL
628 || sym_map == NULL
629 || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
09272d2c 630 {
32e5b41b 631 break;
09272d2c 632 }
32e5b41b 633 /* Set bit 30 to indicate to $$dyncall that this is a PLABEL.
09272d2c 634 We have to do this outside of the generic function descriptor
32e5b41b
UD
635 code, since it doesn't know about our requirement for setting
636 protection bits */
637 value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
3eb9e706
UD
638 break;
639
084442fc
CD
640 case R_PARISC_PLABEL21L:
641 case R_PARISC_PLABEL14R:
642 {
643 unsigned int insn = *(unsigned int *)reloc_addr;
644
09272d2c
AS
645 if (__builtin_expect (sym == NULL, 0))
646 break;
084442fc 647
09272d2c 648 value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
084442fc 649
09272d2c 650 if (r_type == R_PARISC_PLABEL21L)
084442fc
CD
651 {
652 value >>= 11;
653 insn = (insn &~ 0x1fffff) | reassemble_21 (value);
654 }
09272d2c 655 else
084442fc
CD
656 {
657 value &= 0x7ff;
658 insn = (insn &~ 0x3fff) | reassemble_14 (value);
659 }
660
661 *(unsigned int *)reloc_addr = insn;
662 }
663 return;
664
3eb9e706
UD
665 case R_PARISC_IPLT:
666 if (__builtin_expect (sym_map != NULL, 1))
09272d2c 667 {
27f29b2d 668 elf_machine_fixup_plt (NULL, sym_map, NULL, NULL, reloc, reloc_addr,
5abebba4 669 DL_FIXUP_MAKE_VALUE(sym_map, value));
09272d2c
AS
670 }
671 else
672 {
3eb9e706 673 /* If we get here, it's a (weak) undefined sym. */
0572433b 674 elf_machine_fixup_plt (NULL, map, NULL, NULL, reloc, reloc_addr,
5abebba4 675 DL_FIXUP_MAKE_VALUE(map, value));
09272d2c 676 }
3eb9e706
UD
677 return;
678
679 case R_PARISC_COPY:
680 if (__builtin_expect (sym == NULL, 0))
681 /* This can happen in trace mode if an object could not be
682 found. */
683 break;
684 if (__builtin_expect (sym->st_size > refsym->st_size, 0)
685 || (__builtin_expect (sym->st_size < refsym->st_size, 0)
32e5b41b 686 && __builtin_expect (GLRO(dl_verbose), 0)))
3eb9e706
UD
687 {
688 const char *strtab;
689
690 strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
32e5b41b
UD
691 _dl_error_printf ("%s: Symbol `%s' has different size in shared object, "
692 "consider re-linking\n",
b9375348 693 RTLD_PROGNAME, strtab + refsym->st_name);
3eb9e706 694 }
5027ae10 695 memcpy (reloc_addr_arg, (void *) value,
3eb9e706
UD
696 MIN (sym->st_size, refsym->st_size));
697 return;
084442fc 698
43329fe1 699#if !defined RTLD_BOOTSTRAP
084442fc
CD
700 case R_PARISC_TLS_DTPMOD32:
701 value = sym_map->l_tls_modid;
702 break;
703
704 case R_PARISC_TLS_DTPOFF32:
705 /* During relocation all TLS symbols are defined and used.
09272d2c 706 Therefore the offset is already correct. */
084442fc 707 if (sym != NULL)
0937e209 708 *reloc_addr = sym->st_value + reloc->r_addend;
084442fc
CD
709 return;
710
711 case R_PARISC_TLS_TPREL32:
712 /* The offset is negative, forward from the thread pointer */
713 if (sym != NULL)
09272d2c
AS
714 {
715 CHECK_STATIC_TLS (map, sym_map);
084442fc
CD
716 value = sym_map->l_tls_offset + sym->st_value + reloc->r_addend;
717 }
718 break;
719#endif /* use TLS */
09272d2c 720
3eb9e706
UD
721 case R_PARISC_NONE: /* Alright, Wilbur. */
722 return;
723
724 default:
725 _dl_reloc_bad_type (map, r_type, 0);
726 }
727
728 *reloc_addr = value;
729}
730
926092e8
UD
731/* hppa doesn't have an R_PARISC_RELATIVE reloc, but uses relocs with
732 ELF32_R_SYM (info) == 0 for a similar purpose. */
490e6c62 733static void __attribute__((always_inline))
32e5b41b 734elf_machine_rela_relative (Elf32_Addr l_addr,
926092e8 735 const Elf32_Rela *reloc,
5027ae10 736 void *const reloc_addr_arg)
85bdccdb 737{
926092e8 738 unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
32e5b41b 739 Elf32_Addr *const reloc_addr = reloc_addr_arg;
09272d2c 740 static char msgbuf[] = { "Unknown" };
32e5b41b 741 struct link_map map;
926092e8
UD
742 Elf32_Addr value;
743
744 value = l_addr + reloc->r_addend;
745
09272d2c 746 if (ELF32_R_SYM (reloc->r_info) != 0){
32e5b41b
UD
747 _dl_error_printf ("%s: In elf_machine_rela_relative "
748 "ELF32_R_SYM (reloc->r_info) != 0. Aborting.",
b9375348 749 RTLD_PROGNAME);
32e5b41b
UD
750 ABORT_INSTRUCTION; /* Crash. */
751 }
926092e8
UD
752
753 switch (r_type)
754 {
755 case R_PARISC_DIR32:
756 /* .eh_frame can have unaligned relocs. */
5027ae10 757 if ((unsigned long) reloc_addr_arg & 3)
926092e8 758 {
5027ae10 759 char *rel_addr = (char *) reloc_addr_arg;
926092e8
UD
760 rel_addr[0] = value >> 24;
761 rel_addr[1] = value >> 16;
762 rel_addr[2] = value >> 8;
763 rel_addr[3] = value;
764 return;
765 }
766 break;
767
768 case R_PARISC_PLABEL32:
769 break;
770
32e5b41b
UD
771 case R_PARISC_IPLT: /* elf_machine_runtime_setup already set gp */
772 break;
926092e8
UD
773
774 case R_PARISC_NONE:
775 return;
776
32e5b41b
UD
777 default: /* Bad reloc, map unknown (really it's the current map) */
778 map.l_name = msgbuf;
779 _dl_reloc_bad_type (&map, r_type, 0);
780 return;
926092e8
UD
781 }
782
783 *reloc_addr = value;
85bdccdb
UD
784}
785
490e6c62
FS
786static void __attribute__((always_inline))
787elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
09272d2c
AS
788 Elf32_Addr l_addr, const Elf32_Rela *reloc,
789 int skip_ifunc)
3eb9e706
UD
790{
791 /* We don't have anything to do here. elf_machine_runtime_setup has
792 done all the relocs already. */
793}
794
795#endif /* RESOLVE_MAP */