sqrt implementation.
[kopensolaris-gnu/glibc.git] / sysdeps / hppa / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  PA-RISC version.
2    Copyright (C) 1995-1997,1999,2000,2001,2002 Free Software Foundation, Inc.
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
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.
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
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #ifndef dl_machine_h
22 #define dl_machine_h 1
23
24 #define ELF_MACHINE_NAME "hppa"
25
26 #include <sys/param.h>
27 #include <string.h>
28 #include <link.h>
29 #include <assert.h>
30
31 /* These must match the definition of the stub in bfd/elf32-hppa.c. */
32 #define SIZEOF_PLT_STUB (4*4)
33 #define GOT_FROM_PLT_STUB (4*4)
34
35 /* A PLABEL is a function descriptor.  Properly they consist of just
36    FUNC and GP.  But we want to traverse a binary tree too.  See
37    dl-fptr.c for the code (it may be made common between HPPA and
38    IA-64 in the future).
39
40    We call these 'fptr' to make it easier to steal code from IA-64. */
41
42 /* ld.so currently has 12 PLABEL32 relocs.  We'll keep this constant
43    large for now in case we require more, as the rest of these will be
44    used by the dynamic program itself (libc.so has quite a few
45    PLABEL32 relocs in it). */
46 #define HPPA_BOOT_FPTR_SIZE     256
47
48 struct hppa_fptr
49 {
50   Elf32_Addr func;
51   Elf32_Addr gp;
52   struct hppa_fptr *next;
53 };
54
55 extern struct hppa_fptr __boot_ldso_fptr[];
56 extern struct hppa_fptr *__fptr_root;
57 extern int __fptr_count;
58
59 extern Elf32_Addr __hppa_make_fptr (const struct link_map *, Elf32_Addr,
60                                     struct hppa_fptr **, struct hppa_fptr *);
61
62 /* Return nonzero iff ELF header is compatible with the running host.  */
63 static inline int
64 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
65 {
66   return ehdr->e_machine == EM_PARISC;
67 }
68
69
70 /* Return the link-time address of _DYNAMIC.  */
71 static inline Elf32_Addr
72 elf_machine_dynamic (void)
73 {
74   Elf32_Addr dynamic;
75
76 #if 0
77   /* Use this method if GOT address not yet set up.  */
78   asm (
79 "       b,l     1f,%0\n"
80 "       depi    0,31,2,%0\n"
81 "1:     addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 8),%0\n"
82 "       ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 12)(%%r1),%0\n"
83       : "=r" (dynamic) : : "r1");
84 #else
85   /* This works because we already have our GOT address available.  */
86   dynamic = (Elf32_Addr) &_DYNAMIC;
87 #endif
88
89   return dynamic;
90 }
91
92 /* Return the run-time load address of the shared object.  */
93 static inline Elf32_Addr
94 elf_machine_load_address (void)
95 {
96   Elf32_Addr dynamic, dynamic_linkaddress;
97
98   asm (
99 "       b,l     1f,%0\n"
100 "       depi    0,31,2,%0\n"
101 "1:     addil   L'_DYNAMIC - ($PIC_pcrel$0 - 8),%0\n"
102 "       ldo     R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%%r1),%1\n"
103 "       addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%0\n"
104 "       ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%%r1),%0\n"
105    : "=r" (dynamic_linkaddress), "=r" (dynamic) : : "r1");
106
107   return dynamic - dynamic_linkaddress;
108 }
109
110 /* Fixup a PLT entry to bounce directly to the function at VALUE.  */
111 static inline Elf32_Addr
112 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
113                        const Elf32_Rela *reloc,
114                        Elf32_Addr *reloc_addr, Elf32_Addr value)
115 {
116   /* l is the link_map for the caller, t is the link_map for the object
117    * being called */
118   reloc_addr[1] = D_PTR (t, l_info[DT_PLTGOT]);
119   reloc_addr[0] = value;
120   /* Return the PLT slot rather than the function value so that the
121      trampoline can load the new LTP. */
122   return (Elf32_Addr) reloc_addr;
123 }
124
125 /* Return the final value of a plt relocation.  */
126 static inline Elf32_Addr
127 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
128                        Elf32_Addr value)
129 {
130   /* We are rela only */
131   return value + reloc->r_addend;
132 }
133
134 /* Set up the loaded object described by L so its unrelocated PLT
135    entries will jump to the on-demand fixup code in dl-runtime.c.  */
136
137 static inline int
138 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
139 {
140   extern void _dl_runtime_resolve (void);
141   extern void _dl_runtime_profile (void);
142   Elf32_Addr jmprel = D_PTR(l, l_info[DT_JMPREL]);
143
144   if (lazy && jmprel)
145     {
146       Elf32_Addr *got = NULL;
147       Elf32_Addr l_addr;
148       Elf32_Addr end_jmprel;
149       Elf32_Addr iplt;
150
151       /* Relocate all the PLT slots.  */
152       l_addr = l->l_addr;
153       end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
154       for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
155         {
156           const Elf32_Rela *reloc;
157           Elf32_Word r_type;
158           Elf32_Word r_sym;
159           struct hppa_fptr *fptr;
160
161           reloc = (const Elf32_Rela *) iplt;
162           r_type = ELF32_R_TYPE (reloc->r_info);
163           r_sym = ELF32_R_SYM (reloc->r_info);
164
165           if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
166             {
167               fptr = (struct hppa_fptr *) (reloc->r_offset + l_addr);
168               if (r_sym != 0)
169                 {
170                   /* Relocate the pointer to the stub.  */
171                   fptr->func += l_addr;
172                   /* Instead of the LTP value, we put the reloc offset
173                      here.  The trampoline code will load the proper
174                      LTP and pass the reloc offset to the fixup
175                      function.  */
176                   fptr->gp = iplt - jmprel;
177                   if (!got)
178                     {
179                       static union {
180                         unsigned char c[8];
181                         Elf32_Addr i[2];
182                       } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
183
184                       /* Find our .got section.  It's right after the
185                          stub.  */
186                       got = (Elf32_Addr *) (fptr->func + GOT_FROM_PLT_STUB);
187
188                       /* Sanity check to see if the address we are
189                          going to check below is within a reasonable
190                          approximation of the bounds of the PLT (or,
191                          at least, is at an address that won't fault
192                          on read).  Then check for the magic signature
193                          above. */
194                       if (fptr->func < (Elf32_Addr) fptr + sizeof(*fptr))
195                           return 0;
196                       if (fptr->func >
197                           ((Elf32_Addr) fptr
198                            + SIZEOF_PLT_STUB
199                            + ((l->l_info[DT_PLTRELSZ]->d_un.d_val / sizeof (Elf32_Rela))
200                               * 8)))
201                         return 0;
202                       if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
203                         return 0; /* No lazy linking for you! */
204                     }
205                 }
206               else
207                 {
208                   /* Relocate this *ABS* entry.  */
209                   fptr->func = reloc->r_addend + l_addr;
210                   fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
211                 }
212             }
213           else if (__builtin_expect (r_type != R_PARISC_NONE, 0))
214             _dl_reloc_bad_type (l, r_type, 1);
215         }
216
217       if (got)
218         {
219           register Elf32_Addr ltp __asm__ ("%r19");
220           /* Identify this shared object. */
221           got[1] = (Elf32_Addr) l;
222
223           /* This function will be called to perform the relocation. */
224           if (__builtin_expect (!profile, 1))
225             got[-2] =
226               (Elf32_Addr) ((struct hppa_fptr *)
227                             ((unsigned long) &_dl_runtime_resolve & ~3))->func;
228           else
229             {
230               if (_dl_name_match_p (GL(dl_profile), l))
231                 {
232                   /* This is the object we are looking for.  Say that
233                      we really want profiling and the timers are
234                      started.  */
235                   GL(dl_profile_map) = l;
236                 }
237               got[-2] =
238                 (Elf32_Addr) ((struct hppa_fptr *)
239                               ((unsigned long) &_dl_runtime_profile & ~3))->func;
240             }
241           got[-1] = ltp;
242         }
243     }
244   return lazy;
245 }
246
247 /* Initial entry point code for the dynamic linker.
248    The C function `_dl_start' is the real entry point;
249    its return value is the user program's entry point.  */
250
251 #define RTLD_START \
252 /* Set up dp for any non-PIC lib constructors that may be called.  */   \
253 static struct link_map *                                                \
254 set_dp (struct link_map *map)                                           \
255 {                                                                       \
256   register Elf32_Addr dp asm ("%r27");                                  \
257   dp = D_PTR (map, l_info[DT_PLTGOT]);                                  \
258   asm volatile ("" : : "r" (dp));                                       \
259   return map;                                                           \
260 }                                                                       \
261                                                                         \
262 asm (                                                                   \
263 "       .text\n"                                                        \
264 "       .globl _start\n"                                                \
265 "       .type _start,@function\n"                                       \
266 "_start:\n"                                                             \
267         /* The kernel does not give us an initial stack frame. */       \
268 "       ldo     64(%sp),%sp\n"                                          \
269         /* Save the relevant arguments (yes, those are the correct      \
270            registers, the kernel is weird) in their stack slots. */     \
271 "       stw     %r25,-40(%sp)\n" /* argc */                             \
272 "       stw     %r24,-44(%sp)\n" /* argv */                             \
273                                                                         \
274         /* We need the LTP, and we need it now. */                      \
275         /* $PIC_pcrel$0 points 8 bytes past the current instruction,    \
276            just like a branch reloc.  This sequence gets us the runtime \
277            address of _DYNAMIC. */                                      \
278 "       bl      0f,%r19\n"                                              \
279 "       depi    0,31,2,%r19\n"  /* clear priviledge bits */             \
280 "0:     addil   L'_DYNAMIC - ($PIC_pcrel$0 - 8),%r19\n"                 \
281 "       ldo     R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%r1),%r26\n"           \
282                                                                         \
283         /* Also get the link time address from the first entry of the GOT.  */ \
284 "       addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%r19\n"   \
285 "       ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%r1),%r20\n" \
286                                                                         \
287 "       sub     %r26,%r20,%r20\n"       /* Calculate load offset */     \
288                                                                         \
289         /* Rummage through the dynamic entries, looking for DT_PLTGOT.  */ \
290 "       ldw,ma  8(%r26),%r19\n"                                         \
291 "1:     cmpib,=,n 3,%r19,2f\n"  /* tag == DT_PLTGOT? */                 \
292 "       cmpib,<>,n 0,%r19,1b\n"                                         \
293 "       ldw,ma  8(%r26),%r19\n"                                         \
294                                                                         \
295         /* Uh oh!  We didn't find one.  Abort. */                       \
296 "       iitlbp  %r0,(%r0)\n"                                            \
297                                                                         \
298 "2:     ldw     -4(%r26),%r19\n"        /* Found it, load value. */     \
299 "       add     %r19,%r20,%r19\n"       /* And add the load offset. */  \
300                                                                         \
301         /* Our initial stack layout is rather different from everyone   \
302            else's due to the unique PA-RISC ABI.  As far as I know it   \
303            looks like this:                                             \
304                                                                         \
305            -----------------------------------  (this frame created above) \
306            |         32 bytes of magic       |                          \
307            |---------------------------------|                          \
308            | 32 bytes argument/sp save area  |                          \
309            |---------------------------------|  ((current->mm->env_end) + 63 & ~63) \
310            |         N bytes of slack        |                          \
311            |---------------------------------|                          \
312            |      envvar and arg strings     |                          \
313            |---------------------------------|                          \
314            |        ELF auxiliary info       |                          \
315            |         (up to 28 words)        |                          \
316            |---------------------------------|                          \
317            |  Environment variable pointers  |                          \
318            |         upwards to NULL         |                          \
319            |---------------------------------|                          \
320            |        Argument pointers        |                          \
321            |         upwards to NULL         |                          \
322            |---------------------------------|                          \
323            |          argc (1 word)          |                          \
324            -----------------------------------                          \
325                                                                         \
326           So, obviously, we can't just pass %sp to _dl_start.  That's   \
327           okay, argv-4 will do just fine.                               \
328                                                                         \
329           The pleasant part of this is that if we need to skip          \
330           arguments we can just decrement argc and move argv, because   \
331           the stack pointer is utterly unrelated to the location of     \
332           the environment and argument vectors. */                      \
333                                                                         \
334         /* This is always within range so we'll be okay. */             \
335 "       bl      _dl_start,%rp\n"                                        \
336 "       ldo     -4(%r24),%r26\n"                                        \
337                                                                         \
338 "       .globl _dl_start_user\n"                                        \
339 "       .type _dl_start_user,@function\n"                               \
340 "_dl_start_user:\n"                                                     \
341         /* Save the entry point in %r3. */                              \
342 "       copy    %ret0,%r3\n"                                            \
343                                                                         \
344         /* Remember the lowest stack address. */                        \
345 "       addil   LT'__libc_stack_end,%r19\n"                             \
346 "       ldw     RT'__libc_stack_end(%r1),%r20\n"                        \
347 "       stw     %sp,0(%r20)\n"                                          \
348                                                                         \
349         /* See if we were called as a command with the executable file  \
350            name as an extra leading argument. */                        \
351 "       addil   LT'_dl_skip_args,%r19\n"                                \
352 "       ldw     RT'_dl_skip_args(%r1),%r20\n"                           \
353 "       ldw     0(%r20),%r20\n"                                         \
354                                                                         \
355 "       ldw     -40(%sp),%r25\n"        /* argc */                      \
356 "       comib,= 0,%r20,.Lnofix\n"       /* FIXME: will be mispredicted */ \
357 "       ldw     -44(%sp),%r24\n"        /* argv (delay slot) */         \
358                                                                         \
359 "       sub     %r25,%r20,%r25\n"                                       \
360 "       stw     %r25,-40(%sp)\n"                                        \
361 "       sh2add  %r20,%r24,%r24\n"                                       \
362 "       stw     %r24,-44(%sp)\n"                                        \
363                                                                         \
364 ".Lnofix:\n"                                                            \
365 "       addil   LT'_rtld_local,%r19\n"                                  \
366 "       ldw     RT'_rtld_local(%r1),%r26\n"                             \
367 "       bl      set_dp, %r2\n"                                          \
368 "       ldw     0(%r26),%r26\n"                                         \
369                                                                         \
370         /* Call _dl_init(_dl_loaded, argc, argv, envp). */              \
371 "       copy    %r28,%r26\n"                                            \
372                                                                         \
373         /* envp = argv + argc + 1 */                                    \
374 "       sh2add  %r25,%r24,%r23\n"                                       \
375 "       bl      _dl_init_internal,%r2\n"                                \
376 "       ldo     4(%r23),%r23\n" /* delay slot */                        \
377                                                                         \
378         /* Reload argc, argv  to the registers start.S expects them in (feh) */ \
379 "       ldw     -40(%sp),%r25\n"                                        \
380 "       ldw     -44(%sp),%r24\n"                                        \
381                                                                         \
382         /* _dl_fini does have a PLT slot now.  I don't know how to get  \
383            to it though, so this hack will remain. */                   \
384 "       .section .data\n"                                               \
385 "__dl_fini_plabel:\n"                                                   \
386 "       .word   _dl_fini\n"                                             \
387 "       .word   0xdeadbeef\n"                                           \
388 "       .previous\n"                                                    \
389                                                                         \
390         /* %r3 contains a function pointer, we need to mask out the lower \
391          * bits and load the gp and jump address. */                    \
392 "       depi    0,31,2,%r3\n"                                           \
393 "       ldw     0(%r3),%r2\n"                                           \
394 "       addil   LT'__dl_fini_plabel,%r19\n"                             \
395 "       ldw     RT'__dl_fini_plabel(%r1),%r23\n"                        \
396 "       stw     %r19,4(%r23)\n"                                         \
397 "       ldw     4(%r3),%r19\n"  /* load the object's gp */              \
398 "       bv      %r0(%r2)\n"                                             \
399 "       depi    2,31,2,%r23\n"  /* delay slot */                        \
400         );
401
402
403 /* This code gets called via the .plt stub, and is used in
404    dl-runtime.c to call the `fixup' function and then redirect to the
405    address it returns.
406    Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp.  */
407 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
408   extern void tramp_name (void);                    \
409   asm ( "\
410         /* Trampoline for " #tramp_name " */
411         .globl " #tramp_name "
412         .type " #tramp_name ",@function
413 " #tramp_name ":
414         /* Save return pointer */
415         stw     %r2,-20(%sp)
416         /* Save argument registers in the call stack frame. */
417         stw     %r26,-36(%sp)
418         stw     %r25,-40(%sp)
419         stw     %r24,-44(%sp)
420         stw     %r23,-48(%sp)
421         /* Build a call frame. */
422         stwm    %sp,64(%sp)
423
424         /* Set up args to fixup func.  */
425         ldw     8+4(%r20),%r26  /* got[1] == struct link_map *  */
426         copy    %r19,%r25       /* reloc offset  */
427
428         /* Call the real address resolver. */
429         bl      " #fixup_name ",%r2
430         copy    %r21,%r19       /* delay slot, set fixup func ltp */
431
432         ldwm    -64(%sp),%sp
433         /* Arguments. */
434         ldw     -36(%sp),%r26
435         ldw     -40(%sp),%r25
436         ldw     -44(%sp),%r24
437         ldw     -48(%sp),%r23
438         /* Return pointer. */
439         ldw     -20(%sp),%r2
440         /* Call the real function. */
441         ldw     0(%r28),%r22
442         bv      %r0(%r22)
443         ldw     4(%r28),%r19
444 ");
445
446 #ifndef PROF
447 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                  \
448   TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup);     \
449   TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup);
450 #else
451 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                  \
452   TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup);     \
453   strong_alias (_dl_runtime_resolve, _dl_runtime_profile);
454 #endif
455
456
457 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
458    PLT entries should not be allowed to define the value.
459    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
460    of the main executable's symbols, as for a COPY reloc.  */
461 #define elf_machine_type_class(type) \
462   ((((type) == R_PARISC_IPLT || (type) == R_PARISC_EPLT)        \
463     * ELF_RTYPE_CLASS_PLT)                                      \
464    | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
465
466 /* Used by ld.so for ... something ... */
467 #define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
468
469 /* We only use RELA. */
470 #define ELF_MACHINE_NO_REL 1
471
472 /* Return the address of the entry point. */
473 #define ELF_MACHINE_START_ADDRESS(map, start) \
474   DL_FUNCTION_ADDRESS (map, start)
475
476 #endif /* !dl_machine_h */
477
478 /* These are only actually used where RESOLVE_MAP is defined, anyway. */
479 #ifdef RESOLVE_MAP
480
481 static inline void
482 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
483                   const Elf32_Sym *sym, const struct r_found_version *version,
484                   Elf32_Addr *const reloc_addr)
485 {
486   const Elf32_Sym *const refsym = sym;
487   unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
488   struct link_map *sym_map;
489   Elf32_Addr value;
490
491 #if !defined RTLD_BOOTSTRAP && !defined SHARED
492   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
493      reference weak so static programs can still link.  This declaration
494      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
495      because rtld.c contains the common defn for _dl_rtld_map, which is
496      incompatible with a weak decl in the same file.  */
497   weak_extern (GL(dl_rtld_map));
498 #endif
499
500   /* RESOLVE_MAP will return a null value for undefined syms, and
501      non-null for all other syms.  In particular, relocs with no
502      symbol (symbol index of zero), also called *ABS* relocs, will be
503      resolved to MAP.  (The first entry in a symbol table is all
504      zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
505      See RESOLVE_MAP definition in elf/dl-reloc.c  */
506 #ifdef RTLD_BOOTSTRAP
507   /* RESOLVE_MAP in rtld.c doesn't have the local sym test.  */
508   sym_map = (ELF32_ST_BIND (sym->st_info) != STB_LOCAL
509              ? RESOLVE_MAP (&sym, version, r_type) : map);
510 #else
511   sym_map = RESOLVE_MAP (&sym, version, r_type);
512 #endif
513   if (sym_map)
514     {
515       value = sym ? sym_map->l_addr + sym->st_value : 0;
516       value += reloc->r_addend;
517     }
518   else
519     value = 0;
520
521   switch (r_type)
522     {
523     case R_PARISC_DIR32:
524 #ifndef RTLD_BOOTSTRAP
525       /* All hell breaks loose if we try to relocate these twice,
526          because any initialized variables in ld.so that refer to
527          other ones will have their values reset.  In particular,
528          __fptr_next will be reset, sometimes causing endless loops in
529          __hppa_make_fptr().  So don't do that. */
530       if (map == &GL(dl_rtld_map))
531         return;
532 #endif
533       /* .eh_frame can have unaligned relocs.  */
534       if (reloc_addr & 3)
535         {
536           char *rel_addr = (char *) reloc_addr;
537           rel_addr[0] = value >> 24;
538           rel_addr[1] = value >> 16;
539           rel_addr[2] = value >> 8;
540           rel_addr[3] = value;
541           return;
542         }
543       break;
544
545     case R_PARISC_PLABEL32:
546       /* Easy rule: If there is a symbol and it is global, then we
547          need to make a dynamic function descriptor.  Otherwise we
548          have the address of a PLT slot for a local symbol which we
549          know to be unique. */
550       if (sym == NULL
551           || sym_map == NULL
552           || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
553         break;
554
555       /* Okay, we need to make ourselves a PLABEL then.  See the IA64
556          code for an explanation of how this works.  */
557 #ifndef RTLD_BOOTSTRAP
558       value = __hppa_make_fptr (sym_map, value, &__fptr_root, NULL);
559 #else
560       {
561         struct hppa_fptr *p_boot_ldso_fptr;
562         struct hppa_fptr **p_fptr_root;
563         int *p_fptr_count;
564         unsigned long dot;
565
566         /* Go from the top of __boot_ldso_fptr.  As on IA64, we
567            probably haven't relocated the necessary values by this
568            point so we have to find them ourselves. */
569
570         asm ("bl        0f,%0
571               depi      0,31,2,%0
572 0:            addil     L'__boot_ldso_fptr - ($PIC_pcrel$0 - 8),%0
573               ldo       R'__boot_ldso_fptr - ($PIC_pcrel$0 - 12)(%%r1),%1
574               addil     L'__fptr_root - ($PIC_pcrel$0 - 16),%0
575               ldo       R'__fptr_root - ($PIC_pcrel$0 - 20)(%%r1),%2
576               addil     L'__fptr_count - ($PIC_pcrel$0 - 24),%0
577               ldo       R'__fptr_count - ($PIC_pcrel$0 - 28)(%%r1),%3"
578              :
579              "=r" (dot),
580              "=r" (p_boot_ldso_fptr),
581              "=r" (p_fptr_root),
582              "=r" (p_fptr_count));
583
584         value = __hppa_make_fptr (sym_map, value, p_fptr_root,
585                                   &p_boot_ldso_fptr[--*p_fptr_count]);
586       }
587 #endif
588       break;
589
590     case R_PARISC_IPLT:
591       if (__builtin_expect (sym_map != NULL, 1))
592         elf_machine_fixup_plt (NULL, sym_map, reloc, reloc_addr, value);
593       else
594         {
595           /* If we get here, it's a (weak) undefined sym.  */
596           elf_machine_fixup_plt (NULL, map, reloc, reloc_addr, value);
597         }
598       return;
599
600     case R_PARISC_COPY:
601       if (__builtin_expect (sym == NULL, 0))
602         /* This can happen in trace mode if an object could not be
603            found.  */
604         break;
605       if (__builtin_expect (sym->st_size > refsym->st_size, 0)
606           || (__builtin_expect (sym->st_size < refsym->st_size, 0)
607               && __builtin_expect (GL(dl_verbose), 0)))
608         {
609           const char *strtab;
610
611           strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
612           _dl_error_printf ("\
613 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
614                             rtld_progname ?: "<program name unknown>",
615                             strtab + refsym->st_name);
616         }
617       memcpy (reloc_addr, (void *) value,
618               MIN (sym->st_size, refsym->st_size));
619       return;
620
621     case R_PARISC_NONE: /* Alright, Wilbur. */
622       return;
623
624     default:
625       _dl_reloc_bad_type (map, r_type, 0);
626     }
627
628   *reloc_addr = value;
629 }
630
631 static inline void
632 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
633                            Elf32_Addr *const reloc_addr)
634 {
635   /* XXX Nothing to do.  There is no relative relocation, right?  */
636 }
637
638 static inline void
639 elf_machine_lazy_rel (struct link_map *map,
640                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
641 {
642   /* We don't have anything to do here.  elf_machine_runtime_setup has
643      done all the relocs already.  */
644 }
645
646 #endif /* RESOLVE_MAP */