Replace use of old output functions with the new ones.
[kopensolaris-gnu/glibc.git] / sysdeps / hppa / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  PA-RISC version.
2    Copyright (C) 1995,1996,1997,1999,2000,2001 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 Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    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    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If
18    not, write to the Free Software Foundation, Inc.,
19    59 Temple Place - Suite 330, Boston, MA 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
80         depi    0,31,2,%0
81 1:      addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 8),%0
82         ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 12)(%%r1),%0"
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
100         depi    0,31,2,%0
101 1:      addil   L'_DYNAMIC - ($PIC_pcrel$0 - 8),%0
102         ldo     R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%%r1),%1
103         addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%0
104         ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%%r1),%0"
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 (_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                   _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 asm ("\
252         .text
253         .globl _start
254         .type _start,@function
255 _start:
256         /* The kernel does not give us an initial stack frame. */
257         ldo     64(%sp),%sp
258         /* Save the relevant arguments (yes, those are the correct
259            registers, the kernel is weird) in their stack slots. */
260         stw     %r25,-40(%sp) /* argc */
261         stw     %r24,-44(%sp) /* argv */
262
263         /* We need the LTP, and we need it now. */
264         /* $PIC_pcrel$0 points 8 bytes past the current instruction,
265            just like a branch reloc.  This sequence gets us the runtime
266            address of _DYNAMIC. */
267         bl      0f,%r19
268         depi    0,31,2,%r19     /* clear priviledge bits */
269 0:      addil   L'_DYNAMIC - ($PIC_pcrel$0 - 8),%r19
270         ldo     R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%r1),%r26
271
272         /* Also get the link time address from the first entry of the GOT.  */
273         addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%r19
274         ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%r1),%r20
275
276         sub     %r26,%r20,%r20  /* Calculate load offset */
277
278         /* Rummage through the dynamic entries, looking for DT_PLTGOT.  */
279         ldw,ma  8(%r26),%r19
280 1:      cmpib,=,n 3,%r19,2f     /* tag == DT_PLTGOT? */
281         cmpib,<>,n 0,%r19,1b
282         ldw,ma  8(%r26),%r19
283
284         /* Uh oh!  We didn't find one.  Abort. */
285         iitlbp  %r0,(%r0)
286
287 2:      ldw     -4(%r26),%r19   /* Found it, load value. */
288         add     %r19,%r20,%r19  /* And add the load offset. */
289
290         /* Our initial stack layout is rather different from everyone
291            else's due to the unique PA-RISC ABI.  As far as I know it
292            looks like this:
293
294            -----------------------------------  (this frame created above)
295            |         32 bytes of magic       |
296            |---------------------------------|
297            | 32 bytes argument/sp save area  |
298            |---------------------------------|  ((current->mm->env_end) + 63 & ~63)
299            |         N bytes of slack        |
300            |---------------------------------|
301            |      envvar and arg strings     |
302            |---------------------------------|
303            |        ELF auxiliary info       |
304            |         (up to 28 words)        |
305            |---------------------------------|
306            |  Environment variable pointers  |
307            |         upwards to NULL         |
308            |---------------------------------|
309            |        Argument pointers        |
310            |         upwards to NULL         |
311            |---------------------------------|
312            |          argc (1 word)          |
313            -----------------------------------
314
315           So, obviously, we can't just pass %sp to _dl_start.  That's
316           okay, argv-4 will do just fine.
317
318           The pleasant part of this is that if we need to skip
319           arguments we can just decrement argc and move argv, because
320           the stack pointer is utterly unrelated to the location of
321           the environment and argument vectors. */
322
323         /* This is always within range so we'll be okay. */
324         bl      _dl_start,%rp
325         ldo     -4(%r24),%r26
326
327         /* FALLTHRU */
328         .globl _dl_start_user
329         .type _dl_start_user,@function
330 _dl_start_user:
331         /* Save the entry point in %r3. */
332         copy    %ret0,%r3
333
334         /* Remember the lowest stack address. */
335         addil   LT'__libc_stack_end,%r19
336         ldw     RT'__libc_stack_end(%r1),%r20
337         stw     %sp,0(%r20)
338
339         /* See if we were called as a command with the executable file
340            name as an extra leading argument. */
341         addil   LT'_dl_skip_args,%r19
342         ldw     RT'_dl_skip_args(%r1),%r20
343         ldw     0(%r20),%r20
344
345         ldw     -40(%sp),%r25   /* argc */
346         comib,= 0,%r20,.Lnofix  /* FIXME: will be mispredicted */
347         ldw     -44(%sp),%r24   /* argv (delay slot) */
348
349         sub     %r25,%r20,%r25
350         stw     %r25,-40(%sp)
351         sh2add  %r20,%r24,%r24
352         stw     %r24,-44(%sp)
353
354 .Lnofix:
355         /* Call _dl_init(_dl_loaded, argc, argv, envp). */
356         addil   LT'_dl_loaded,%r19
357         ldw     RT'_dl_loaded(%r1),%r26
358         ldw     0(%r26),%r26
359         /* envp = argv + argc + 1 */
360         sh2add  %r25,%r24,%r23
361         bl      _dl_init,%r2
362         ldo     4(%r23),%r23    /* delay slot */
363
364         /* Reload argc, argv  to the registers start.S expects them in (feh) */
365         ldw     -40(%sp),%r25
366         ldw     -44(%sp),%r24
367
368         /* _dl_fini does have a PLT slot now.  I don't know how to get
369            to it though, so this hack will remain. */
370         .section .data
371 __dl_fini_plabel:
372         .word   _dl_fini
373         .word   0xdeadbeef
374         .previous
375
376         addil   LT'__dl_fini_plabel,%r19
377         ldw     RT'__dl_fini_plabel(%r1),%r23
378         stw     %r19,4(%r23)
379         bv      %r0(%r3)
380         depi    2,31,2,%r23     /* delay slot */");
381
382 /* This code gets called via the .plt stub, and is used in
383    dl-runtime.c to call the `fixup' function and then redirect to the
384    address it returns.
385    Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp.  */
386 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
387   extern void tramp_name (void);                    \
388   asm ( "\
389         /* Trampoline for " #tramp_name " */
390         .globl " #tramp_name "
391         .type " #tramp_name ",@function
392 " #tramp_name ":
393         /* Save return pointer */
394         stw     %r2,-20(%sp)
395         /* Save argument registers in the call stack frame. */
396         stw     %r26,-36(%sp)
397         stw     %r25,-40(%sp)
398         stw     %r24,-44(%sp)
399         stw     %r23,-48(%sp)
400         /* Build a call frame. */
401         stwm    %sp,64(%sp)
402
403         /* Set up args to fixup func.  */
404         ldw     8+4(%r20),%r26  /* got[1] == struct link_map *  */
405         copy    %r19,%r25       /* reloc offset  */
406
407         /* Call the real address resolver. */
408         bl      " #fixup_name ",%r2
409         copy    %r21,%r19       /* delay slot, set fixup func ltp */
410
411         ldwm    -64(%sp),%sp
412         /* Arguments. */
413         ldw     -36(%sp),%r26
414         ldw     -40(%sp),%r25
415         ldw     -44(%sp),%r24
416         ldw     -48(%sp),%r23
417         /* Return pointer. */
418         ldw     -20(%sp),%r2
419         /* Call the real function. */
420         ldw     0(%r28),%r22
421         bv      %r0(%r22)
422         ldw     4(%r28),%r19
423 ");
424
425 #ifndef PROF
426 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                  \
427   TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup);     \
428   TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup);
429 #else
430 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                  \
431   TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup);     \
432   strong_alias (_dl_runtime_resolve, _dl_runtime_profile);
433 #endif
434
435
436 /* Nonzero iff TYPE describes a relocation that should
437    skip the executable when looking up the symbol value.  */
438 #define elf_machine_lookup_noexec_p(type) ((type) == R_PARISC_COPY)
439
440 /* Nonzero iff TYPE describes relocation of a PLT entry, so
441    PLT entries should not be allowed to define the value.  */
442 #define elf_machine_lookup_noplt_p(type) ((type) == R_PARISC_IPLT \
443                                           || (type) == R_PARISC_EPLT)
444
445 /* Used by ld.so for ... something ... */
446 #define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
447
448 /* We only use RELA. */
449 #define ELF_MACHINE_NO_REL 1
450
451 #endif /* !dl_machine_h */
452
453 /* These are only actually used where RESOLVE_MAP is defined, anyway. */
454 #ifdef RESOLVE_MAP
455
456 static inline void
457 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
458                   const Elf32_Sym *sym, const struct r_found_version *version,
459                   Elf32_Addr *const reloc_addr)
460 {
461   const Elf32_Sym *const refsym = sym;
462   unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
463   struct link_map *sym_map;
464   Elf32_Addr value;
465
466 #ifndef RTLD_BOOTSTRAP
467   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
468      reference weak so static programs can still link.  This declaration
469      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
470      because rtld.c contains the common defn for _dl_rtld_map, which is
471      incompatible with a weak decl in the same file.  */
472   weak_extern (_dl_rtld_map);
473 #endif
474
475   /* RESOLVE_MAP will return a null value for undefined syms, and
476      non-null for all other syms.  In particular, relocs with no
477      symbol (symbol index of zero), also called *ABS* relocs, will be
478      resolved to MAP.  (The first entry in a symbol table is all
479      zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
480      See RESOLVE_MAP definition in elf/dl-reloc.c  */
481 #ifdef RTLD_BOOTSTRAP
482   /* RESOLVE_MAP in rtld.c doesn't have the local sym test.  */
483   sym_map = (ELF32_ST_BIND (sym->st_info) != STB_LOCAL
484              ? RESOLVE_MAP (&sym, version, r_type) : map);
485 #else
486   sym_map = RESOLVE_MAP (&sym, version, r_type);
487 #endif
488   if (sym_map)
489     {
490       value = sym ? sym_map->l_addr + sym->st_value : 0;
491       value += reloc->r_addend;
492     }
493   else
494     value = 0;
495
496   switch (r_type)
497     {
498     case R_PARISC_DIR32:
499 #ifndef RTLD_BOOTSTRAP
500       /* All hell breaks loose if we try to relocate these twice,
501          because any initialized variables in ld.so that refer to
502          other ones will have their values reset.  In particular,
503          __fptr_next will be reset, sometimes causing endless loops in
504          __hppa_make_fptr().  So don't do that. */
505       if (map == &_dl_rtld_map)
506         return;
507 #endif
508       /* Otherwise, nothing more to do here. */
509       break;
510
511     case R_PARISC_PLABEL32:
512       /* Easy rule: If there is a symbol and it is global, then we
513          need to make a dynamic function descriptor.  Otherwise we
514          have the address of a PLT slot for a local symbol which we
515          know to be unique. */
516       if (sym == NULL
517           || sym_map == NULL
518           || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
519         break;
520
521       /* Okay, we need to make ourselves a PLABEL then.  See the IA64
522          code for an explanation of how this works.  */
523 #ifndef RTLD_BOOTSTRAP
524       value = __hppa_make_fptr (sym_map, value, &__fptr_root, NULL);
525 #else
526       {
527         struct hppa_fptr *p_boot_ldso_fptr;
528         struct hppa_fptr **p_fptr_root;
529         int *p_fptr_count;
530         unsigned long dot;
531
532         /* Go from the top of __boot_ldso_fptr.  As on IA64, we
533            probably haven't relocated the necessary values by this
534            point so we have to find them ourselves. */
535
536         asm ("bl        0f,%0
537               depi      0,31,2,%0
538 0:            addil     L'__boot_ldso_fptr - ($PIC_pcrel$0 - 8),%0
539               ldo       R'__boot_ldso_fptr - ($PIC_pcrel$0 - 12)(%%r1),%1
540               addil     L'__fptr_root - ($PIC_pcrel$0 - 16),%0
541               ldo       R'__fptr_root - ($PIC_pcrel$0 - 20)(%%r1),%2
542               addil     L'__fptr_count - ($PIC_pcrel$0 - 24),%0
543               ldo       R'__fptr_count - ($PIC_pcrel$0 - 28)(%%r1),%3"
544              :
545              "=r" (dot),
546              "=r" (p_boot_ldso_fptr),
547              "=r" (p_fptr_root),
548              "=r" (p_fptr_count));
549
550         value = __hppa_make_fptr (sym_map, value, p_fptr_root,
551                                   &p_boot_ldso_fptr[--*p_fptr_count]);
552       }
553 #endif
554       break;
555
556     case R_PARISC_IPLT:
557       if (__builtin_expect (sym_map != NULL, 1))
558         elf_machine_fixup_plt (NULL, sym_map, reloc, reloc_addr, value);
559       else
560         {
561           /* If we get here, it's a (weak) undefined sym.  */
562           elf_machine_fixup_plt (NULL, map, reloc, reloc_addr, value);
563         }
564       return;
565
566     case R_PARISC_COPY:
567       if (__builtin_expect (sym == NULL, 0))
568         /* This can happen in trace mode if an object could not be
569            found.  */
570         break;
571       if (__builtin_expect (sym->st_size > refsym->st_size, 0)
572           || (__builtin_expect (sym->st_size < refsym->st_size, 0)
573               && __builtin_expect (_dl_verbose, 0)))
574         {
575           const char *strtab;
576
577           strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
578           _dl_error_printf ("\
579 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
580                             _dl_argv[0] ?: "<program name unknown>",
581                             strtab + refsym->st_name);
582         }
583       memcpy (reloc_addr, (void *) value,
584               MIN (sym->st_size, refsym->st_size));
585       return;
586
587     case R_PARISC_NONE: /* Alright, Wilbur. */
588       return;
589
590     default:
591       _dl_reloc_bad_type (map, r_type, 0);
592     }
593
594   *reloc_addr = value;
595 }
596
597 static inline void
598 elf_machine_lazy_rel (struct link_map *map,
599                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
600 {
601   /* We don't have anything to do here.  elf_machine_runtime_setup has
602      done all the relocs already.  */
603 }
604
605 #endif /* RESOLVE_MAP */