Implement linux-style statfs and co.
[kopensolaris-gnu/glibc.git] / sysdeps / alpha / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  Alpha version.
2    Copyright (C) 1996-2005, 2006 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Richard Henderson <rth@tamu.edu>.
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 /* This was written in the absence of an ABI -- don't expect
22    it to remain unchanged.  */
23
24 #ifndef dl_machine_h
25 #define dl_machine_h 1
26
27 #define ELF_MACHINE_NAME "alpha"
28
29 #include <string.h>
30
31
32 /* Mask identifying addresses reserved for the user program,
33    where the dynamic linker should not map anything.  */
34 #define ELF_MACHINE_USER_ADDRESS_MASK   0x120000000UL
35
36 /* Translate a processor specific dynamic tag to the index in l_info array.  */
37 #define DT_ALPHA(x) (DT_ALPHA_##x - DT_LOPROC + DT_NUM)
38
39 /* Return nonzero iff ELF header is compatible with the running host.  */
40 static inline int
41 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
42 {
43   return ehdr->e_machine == EM_ALPHA;
44 }
45
46 /* Return the link-time address of _DYNAMIC.  The multiple-got-capable
47    linker no longer allocates the first .got entry for this.  But not to
48    worry, no special tricks are needed.  */
49 static inline Elf64_Addr
50 elf_machine_dynamic (void)
51 {
52 #ifndef NO_AXP_MULTI_GOT_LD
53   return (Elf64_Addr) &_DYNAMIC;
54 #else
55   register Elf64_Addr *gp __asm__ ("$29");
56   return gp[-4096];
57 #endif
58 }
59
60 /* Return the run-time load address of the shared object.  */
61
62 static inline Elf64_Addr
63 elf_machine_load_address (void)
64 {
65   /* This relies on the compiler using gp-relative addresses for static symbols.  */
66   static void *dot = &dot;
67   return (void *)&dot - dot;
68 }
69
70 /* Set up the loaded object described by L so its unrelocated PLT
71    entries will jump to the on-demand fixup code in dl-runtime.c.  */
72
73 static inline int
74 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
75 {
76   extern char _dl_runtime_resolve_new[] attribute_hidden;
77   extern char _dl_runtime_profile_new[] attribute_hidden;
78   extern char _dl_runtime_resolve_old[] attribute_hidden;
79   extern char _dl_runtime_profile_old[] attribute_hidden;
80
81   struct pltgot {
82     char *resolve;
83     struct link_map *link;
84   };
85
86   struct pltgot *pg;
87   long secureplt;
88   char *resolve;
89
90   if (map->l_info[DT_JMPREL] == 0 || !lazy)
91     return lazy;
92
93   /* Check to see if we're using the read-only plt form.  */
94   secureplt = map->l_info[DT_ALPHA(PLTRO)] != 0;
95
96   /* If the binary uses the read-only secure plt format, PG points to
97      the .got.plt section, which is the right place for ld.so to place
98      its hooks.  Otherwise, PG is currently pointing at the start of
99      the plt; the hooks go at offset 16.  */
100   pg = (struct pltgot *) D_PTR (map, l_info[DT_PLTGOT]);
101   pg += !secureplt;
102
103   /* This function will be called to perform the relocation.  They're
104      not declared as functions to convince the compiler to use gp
105      relative relocations for them.  */
106   if (secureplt)
107     resolve = _dl_runtime_resolve_new;
108   else
109     resolve = _dl_runtime_resolve_old;
110
111   if (__builtin_expect (profile, 0))
112     {
113       if (secureplt)
114         resolve = _dl_runtime_profile_new;
115       else
116         resolve = _dl_runtime_profile_old;
117
118       if (GLRO(dl_profile) && _dl_name_match_p (GLRO(dl_profile), map))
119         {
120           /* This is the object we are looking for.  Say that we really
121              want profiling and the timers are started.  */
122           GL(dl_profile_map) = map;
123         }
124     }
125
126   pg->resolve = resolve;
127   pg->link = map;
128
129   return lazy;
130 }
131
132 /* Initial entry point code for the dynamic linker.
133    The C function `_dl_start' is the real entry point;
134    its return value is the user program's entry point.  */
135
136 #define RTLD_START asm ("\
137         .section .text                                          \n\
138         .set at                                                 \n\
139         .globl _start                                           \n\
140         .ent _start                                             \n\
141 _start:                                                         \n\
142         .frame $31,0,$31,0                                      \n\
143         br      $gp, 0f                                         \n\
144 0:      ldgp    $gp, 0($gp)                                     \n\
145         .prologue 0                                             \n\
146         /* Pass pointer to argument block to _dl_start.  */     \n\
147         mov     $sp, $16                                        \n\
148         bsr     $26, _dl_start          !samegp                 \n\
149         .end _start                                             \n\
150         /* FALLTHRU */                                          \n\
151         .globl _dl_start_user                                   \n\
152         .ent _dl_start_user                                     \n\
153 _dl_start_user:                                                 \n\
154         .frame $31,0,$31,0                                      \n\
155         .prologue 0                                             \n\
156         /* Save the user entry point address in s0.  */         \n\
157         mov     $0, $9                                          \n\
158         /* See if we were run as a command with the executable  \n\
159            file name as an extra leading argument.  */          \n\
160         ldah    $1, _dl_skip_args($gp)  !gprelhigh              \n\
161         ldl     $1, _dl_skip_args($1)   !gprellow               \n\
162         bne     $1, $fixup_stack                                \n\
163 $fixup_stack_ret:                                               \n\
164         /* The special initializer gets called with the stack   \n\
165            just as the application's entry point will see it;   \n\
166            it can switch stacks if it moves these contents      \n\
167            over.  */                                            \n\
168 " RTLD_START_SPECIAL_INIT "                                     \n\
169         /* Call _dl_init(_dl_loaded, argc, argv, envp) to run   \n\
170            initializers.  */                                    \n\
171         ldah    $16, _rtld_local($gp)   !gprelhigh              \n\
172         ldq     $16, _rtld_local($16)   !gprellow               \n\
173         ldq     $17, 0($sp)                                     \n\
174         lda     $18, 8($sp)                                     \n\
175         s8addq  $17, 8, $19                                     \n\
176         addq    $19, $18, $19                                   \n\
177         bsr     $26, _dl_init_internal  !samegp                 \n\
178         /* Pass our finalizer function to the user in $0. */    \n\
179         ldah    $0, _dl_fini($gp)       !gprelhigh              \n\
180         lda     $0, _dl_fini($0)        !gprellow               \n\
181         /* Jump to the user's entry point.  */                  \n\
182         mov     $9, $27                                         \n\
183         jmp     ($9)                                            \n\
184 $fixup_stack:                                                   \n\
185         /* Adjust the stack pointer to skip _dl_skip_args words.\n\
186            This involves copying everything down, since the     \n\
187            stack pointer must always be 16-byte aligned.  */    \n\
188         ldah    $7, _dl_argv_internal($gp) !gprelhigh           \n\
189         ldq     $2, 0($sp)                                      \n\
190         ldq     $5, _dl_argv_internal($7) !gprellow             \n\
191         subq    $31, $1, $6                                     \n\
192         subq    $2, $1, $2                                      \n\
193         s8addq  $6, $5, $5                                      \n\
194         mov     $sp, $4                                         \n\
195         s8addq  $1, $sp, $3                                     \n\
196         stq     $2, 0($sp)                                      \n\
197         stq     $5, _dl_argv_internal($7) !gprellow             \n\
198         /* Copy down argv.  */                                  \n\
199 0:      ldq     $5, 8($3)                                       \n\
200         addq    $4, 8, $4                                       \n\
201         addq    $3, 8, $3                                       \n\
202         stq     $5, 0($4)                                       \n\
203         bne     $5, 0b                                          \n\
204         /* Copy down envp.  */                                  \n\
205 1:      ldq     $5, 8($3)                                       \n\
206         addq    $4, 8, $4                                       \n\
207         addq    $3, 8, $3                                       \n\
208         stq     $5, 0($4)                                       \n\
209         bne     $5, 1b                                          \n\
210         /* Copy down auxiliary table.  */                       \n\
211 2:      ldq     $5, 8($3)                                       \n\
212         ldq     $6, 16($3)                                      \n\
213         addq    $4, 16, $4                                      \n\
214         addq    $3, 16, $3                                      \n\
215         stq     $5, -8($4)                                      \n\
216         stq     $6, 0($4)                                       \n\
217         bne     $5, 2b                                          \n\
218         br      $fixup_stack_ret                                \n\
219         .end _dl_start_user                                     \n\
220         .set noat                                               \n\
221 .previous");
222
223 #ifndef RTLD_START_SPECIAL_INIT
224 #define RTLD_START_SPECIAL_INIT /* nothing */
225 #endif
226
227 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry
228    or TLS variables, so undefined references should not be allowed
229    to define the value.
230
231    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve
232    to one of the main executable's symbols, as for a COPY reloc.
233    This is unused on Alpha.  */
234
235 #if !defined RTLD_BOOTSTRAP || USE___THREAD
236 # define elf_machine_type_class(type)   \
237   (((type) == R_ALPHA_JMP_SLOT          \
238     || (type) == R_ALPHA_DTPMOD64       \
239     || (type) == R_ALPHA_DTPREL64       \
240     || (type) == R_ALPHA_TPREL64) * ELF_RTYPE_CLASS_PLT)
241 #else
242 # define elf_machine_type_class(type)   \
243   (((type) == R_ALPHA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)
244 #endif
245
246 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
247 #define ELF_MACHINE_JMP_SLOT     R_ALPHA_JMP_SLOT
248
249 /* The alpha never uses Elf64_Rel relocations.  */
250 #define ELF_MACHINE_NO_REL 1
251
252 /* Fix up the instructions of a PLT entry to invoke the function
253    rather than the dynamic linker.  */
254 static inline Elf64_Addr
255 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
256                        const Elf64_Rela *reloc,
257                        Elf64_Addr *got_addr, Elf64_Addr value)
258 {
259   const Elf64_Rela *rela_plt;
260   Elf64_Word *plte;
261   long int edisp;
262
263   /* Store the value we are going to load.  */
264   *got_addr = value;
265
266   /* If this binary uses the read-only secure plt format, we're done.  */
267   if (map->l_info[DT_ALPHA(PLTRO)])
268     return value;
269
270   /* Otherwise we have to modify the plt entry in place to do the branch.  */
271
272   /* Recover the PLT entry address by calculating reloc's index into the
273      .rela.plt, and finding that entry in the .plt.  */
274   rela_plt = (const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]);
275   plte = (Elf64_Word *) (D_PTR (map, l_info[DT_PLTGOT]) + 32);
276   plte += 3 * (reloc - rela_plt);
277
278   /* Find the displacement from the plt entry to the function.  */
279   edisp = (long int) (value - (Elf64_Addr)&plte[3]) / 4;
280
281   if (edisp >= -0x100000 && edisp < 0x100000)
282     {
283       /* If we are in range, use br to perfect branch prediction and
284          elide the dependency on the address load.  This case happens,
285          e.g., when a shared library call is resolved to the same library.  */
286
287       int hi, lo;
288       hi = value - (Elf64_Addr)&plte[0];
289       lo = (short int) hi;
290       hi = (hi - lo) >> 16;
291
292       /* Emit "lda $27,lo($27)" */
293       plte[1] = 0x237b0000 | (lo & 0xffff);
294
295       /* Emit "br $31,function" */
296       plte[2] = 0xc3e00000 | (edisp & 0x1fffff);
297
298       /* Think about thread-safety -- the previous instructions must be
299          committed to memory before the first is overwritten.  */
300       __asm__ __volatile__("wmb" : : : "memory");
301
302       /* Emit "ldah $27,hi($27)" */
303       plte[0] = 0x277b0000 | (hi & 0xffff);
304     }
305   else
306     {
307       /* Don't bother with the hint since we already know the hint is
308          wrong.  Eliding it prevents the wrong page from getting pulled
309          into the cache.  */
310
311       int hi, lo;
312       hi = (Elf64_Addr)got_addr - (Elf64_Addr)&plte[0];
313       lo = (short)hi;
314       hi = (hi - lo) >> 16;
315
316       /* Emit "ldq $27,lo($27)" */
317       plte[1] = 0xa77b0000 | (lo & 0xffff);
318
319       /* Emit "jmp $31,($27)" */
320       plte[2] = 0x6bfb0000;
321
322       /* Think about thread-safety -- the previous instructions must be
323          committed to memory before the first is overwritten.  */
324       __asm__ __volatile__("wmb" : : : "memory");
325
326       /* Emit "ldah $27,hi($27)" */
327       plte[0] = 0x277b0000 | (hi & 0xffff);
328     }
329
330   /* At this point, if we've been doing runtime resolution, Icache is dirty.
331      This will be taken care of in _dl_runtime_resolve.  If instead we are
332      doing this as part of non-lazy startup relocation, that bit of code
333      hasn't made it into Icache yet, so there's nothing to clean up.  */
334
335   return value;
336 }
337
338 /* Return the final value of a plt relocation.  */
339 static inline Elf64_Addr
340 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
341                        Elf64_Addr value)
342 {
343   return value + reloc->r_addend;
344 }
345
346 /* Names of the architecture-specific auditing callback functions.  */
347 #define ARCH_LA_PLTENTER        alpha_gnu_pltenter
348 #define ARCH_LA_PLTEXIT         alpha_gnu_pltexit
349
350 #endif /* !dl_machine_h */
351
352 #ifdef RESOLVE_MAP
353
354 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
355    MAP is the object containing the reloc.  */
356 auto inline void
357 __attribute__ ((always_inline))
358 elf_machine_rela (struct link_map *map,
359                   const Elf64_Rela *reloc,
360                   const Elf64_Sym *sym,
361                   const struct r_found_version *version,
362                   void *const reloc_addr_arg)
363 {
364   Elf64_Addr *const reloc_addr = reloc_addr_arg;
365   unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
366
367 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED
368   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
369      reference weak so static programs can still link.  This declaration
370      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
371      because rtld.c contains the common defn for _dl_rtld_map, which is
372      incompatible with a weak decl in the same file.  */
373   weak_extern (_dl_rtld_map);
374 #endif
375
376   /* We cannot use a switch here because we cannot locate the switch
377      jump table until we've self-relocated.  */
378
379 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
380   if (__builtin_expect (r_type == R_ALPHA_RELATIVE, 0))
381     {
382 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
383       /* Already done in dynamic linker.  */
384       if (map != &GL(dl_rtld_map))
385 # endif
386         {
387           /* XXX Make some timings.  Maybe it's preferable to test for
388              unaligned access and only do it the complex way if necessary.  */
389           Elf64_Addr reloc_addr_val;
390
391           /* Load value without causing unaligned trap. */
392           memcpy (&reloc_addr_val, reloc_addr_arg, 8);
393           reloc_addr_val += map->l_addr;
394
395           /* Store value without causing unaligned trap. */
396           memcpy (reloc_addr_arg, &reloc_addr_val, 8);
397         }
398     }
399   else
400 #endif
401     if (__builtin_expect (r_type == R_ALPHA_NONE, 0))
402       return;
403   else
404     {
405       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
406       Elf64_Addr sym_value;
407       Elf64_Addr sym_raw_value;
408
409       sym_raw_value = sym_value = reloc->r_addend;
410       if (sym_map)
411         {
412           sym_raw_value += sym->st_value;
413           sym_value = sym_raw_value + sym_map->l_addr;
414         }
415
416       if (r_type == R_ALPHA_GLOB_DAT)
417         *reloc_addr = sym_value;
418 #ifdef RESOLVE_CONFLICT_FIND_MAP
419       /* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have
420          R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits
421          are .rela.plt index.  */
422       else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT)
423         {
424           /* elf_machine_fixup_plt needs the map reloc_addr points into,
425              while in _dl_resolve_conflicts map is _dl_loaded.  */
426           RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
427           reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
428                   + (r_type >> 8);
429           elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
430         }
431 #else
432       else if (r_type == R_ALPHA_JMP_SLOT)
433         elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
434 #endif
435 #ifndef RTLD_BOOTSTRAP
436       else if (r_type == R_ALPHA_REFQUAD)
437         {
438           /* Store value without causing unaligned trap.  */
439           memcpy (reloc_addr_arg, &sym_value, 8);
440         }
441 #endif
442 #if !defined RTLD_BOOTSTRAP || USE___THREAD
443       else if (r_type == R_ALPHA_DTPMOD64)
444         {
445 # ifdef RTLD_BOOTSTRAP
446           /* During startup the dynamic linker is always index 1.  */
447           *reloc_addr = 1;
448 # else
449           /* Get the information from the link map returned by the
450              resolv function.  */
451           if (sym_map != NULL)
452             *reloc_addr = sym_map->l_tls_modid;
453 # endif
454         }
455       else if (r_type == R_ALPHA_DTPREL64)
456         {
457 # ifndef RTLD_BOOTSTRAP
458           /* During relocation all TLS symbols are defined and used.
459              Therefore the offset is already correct.  */
460           *reloc_addr = sym_raw_value;
461 # endif
462         }
463       else if (r_type == R_ALPHA_TPREL64)
464         {
465 # ifdef RTLD_BOOTSTRAP
466           *reloc_addr = sym_raw_value + map->l_tls_offset;
467 # else
468           if (sym_map)
469             {
470               CHECK_STATIC_TLS (map, sym_map);
471               *reloc_addr = sym_raw_value + sym_map->l_tls_offset;
472             }
473 # endif
474         }
475 #endif
476       else
477         _dl_reloc_bad_type (map, r_type, 0);
478     }
479 }
480
481 /* Let do-rel.h know that on Alpha if l_addr is 0, all RELATIVE relocs
482    can be skipped.  */
483 #define ELF_MACHINE_REL_RELATIVE 1
484
485 auto inline void
486 __attribute__ ((always_inline))
487 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
488                            void *const reloc_addr_arg)
489 {
490   /* XXX Make some timings.  Maybe it's preferable to test for
491      unaligned access and only do it the complex way if necessary.  */
492   Elf64_Addr reloc_addr_val;
493
494   /* Load value without causing unaligned trap. */
495   memcpy (&reloc_addr_val, reloc_addr_arg, 8);
496   reloc_addr_val += l_addr;
497
498   /* Store value without causing unaligned trap. */
499   memcpy (reloc_addr_arg, &reloc_addr_val, 8);
500 }
501
502 auto inline void
503 __attribute__ ((always_inline))
504 elf_machine_lazy_rel (struct link_map *map,
505                       Elf64_Addr l_addr, const Elf64_Rela *reloc)
506 {
507   Elf64_Addr * const reloc_addr = (void *)(l_addr + reloc->r_offset);
508   unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
509
510   if (r_type == R_ALPHA_JMP_SLOT)
511     {
512       /* Perform a RELATIVE reloc on the .got entry that transfers
513          to the .plt.  */
514       *reloc_addr += l_addr;
515     }
516   else if (r_type == R_ALPHA_NONE)
517     return;
518   else
519     _dl_reloc_bad_type (map, r_type, 1);
520 }
521
522 #endif /* RESOLVE_MAP */