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