]>
Commit | Line | Data |
---|---|---|
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 */ |
61 | static 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 | 78 | static inline int |
f1dba308 | 79 | elf_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 |
85 | static inline Elf32_Addr |
86 | elf_machine_dynamic (void) __attribute__ ((const)); | |
87 | ||
3eb9e706 UD |
88 | static inline Elf32_Addr |
89 | elf_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 |
102 | static inline Elf32_Addr |
103 | elf_machine_load_address (void) __attribute__ ((const)); | |
104 | ||
3eb9e706 UD |
105 | static inline Elf32_Addr |
106 | elf_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. */ |
120 | static inline struct fdesc __attribute__ ((always_inline)) | |
3eb9e706 | 121 | elf_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 | 155 | static inline struct fdesc |
3eb9e706 | 156 | elf_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 | ||
166 | static inline int | |
490e6c62 FS |
167 | elf_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. */ \ |
351 | static struct link_map * __attribute__((used)) \ | |
352 | set_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 |
360 | asm ( \ |
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 |
528 | static inline void __attribute__ ((unused)) |
529 | dl_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 |
552 | static void __attribute__((always_inline)) |
553 | elf_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 | 733 | static void __attribute__((always_inline)) |
32e5b41b | 734 | elf_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 |
786 | static void __attribute__((always_inline)) |
787 | elf_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 */ |