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