Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  Alpha version.
00002    Copyright (C) 1996-2005, 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Richard Henderson <rth@tamu.edu>.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 /* This was written in the absence of an ABI -- don't expect
00022    it to remain unchanged.  */
00023 
00024 #ifndef dl_machine_h
00025 #define dl_machine_h 1
00026 
00027 #define ELF_MACHINE_NAME "alpha"
00028 
00029 #include <string.h>
00030 
00031 
00032 /* Mask identifying addresses reserved for the user program,
00033    where the dynamic linker should not map anything.  */
00034 #define ELF_MACHINE_USER_ADDRESS_MASK     0x120000000UL
00035 
00036 /* Translate a processor specific dynamic tag to the index in l_info array.  */
00037 #define DT_ALPHA(x) (DT_ALPHA_##x - DT_LOPROC + DT_NUM)
00038 
00039 /* Return nonzero iff ELF header is compatible with the running host.  */
00040 static inline int
00041 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
00042 {
00043   return ehdr->e_machine == EM_ALPHA;
00044 }
00045 
00046 /* Return the link-time address of _DYNAMIC.  The multiple-got-capable
00047    linker no longer allocates the first .got entry for this.  But not to
00048    worry, no special tricks are needed.  */
00049 static inline Elf64_Addr
00050 elf_machine_dynamic (void)
00051 {
00052 #ifndef NO_AXP_MULTI_GOT_LD
00053   return (Elf64_Addr) &_DYNAMIC;
00054 #else
00055   register Elf64_Addr *gp __asm__ ("$29");
00056   return gp[-4096];
00057 #endif
00058 }
00059 
00060 /* Return the run-time load address of the shared object.  */
00061 
00062 static inline Elf64_Addr
00063 elf_machine_load_address (void)
00064 {
00065   /* This relies on the compiler using gp-relative addresses for static symbols.  */
00066   static void *dot = &dot;
00067   return (void *)&dot - dot;
00068 }
00069 
00070 /* Set up the loaded object described by L so its unrelocated PLT
00071    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00072 
00073 static inline int
00074 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
00075 {
00076   extern char _dl_runtime_resolve_new[] attribute_hidden;
00077   extern char _dl_runtime_profile_new[] attribute_hidden;
00078   extern char _dl_runtime_resolve_old[] attribute_hidden;
00079   extern char _dl_runtime_profile_old[] attribute_hidden;
00080 
00081   struct pltgot {
00082     char *resolve;
00083     struct link_map *link;
00084   };
00085 
00086   struct pltgot *pg;
00087   long secureplt;
00088   char *resolve;
00089 
00090   if (map->l_info[DT_JMPREL] == 0 || !lazy)
00091     return lazy;
00092 
00093   /* Check to see if we're using the read-only plt form.  */
00094   secureplt = map->l_info[DT_ALPHA(PLTRO)] != 0;
00095 
00096   /* If the binary uses the read-only secure plt format, PG points to
00097      the .got.plt section, which is the right place for ld.so to place
00098      its hooks.  Otherwise, PG is currently pointing at the start of
00099      the plt; the hooks go at offset 16.  */
00100   pg = (struct pltgot *) D_PTR (map, l_info[DT_PLTGOT]);
00101   pg += !secureplt;
00102 
00103   /* This function will be called to perform the relocation.  They're
00104      not declared as functions to convince the compiler to use gp
00105      relative relocations for them.  */
00106   if (secureplt)
00107     resolve = _dl_runtime_resolve_new;
00108   else
00109     resolve = _dl_runtime_resolve_old;
00110 
00111   if (__builtin_expect (profile, 0))
00112     {
00113       if (secureplt)
00114        resolve = _dl_runtime_profile_new;
00115       else
00116        resolve = _dl_runtime_profile_old;
00117 
00118       if (GLRO(dl_profile) && _dl_name_match_p (GLRO(dl_profile), map))
00119        {
00120          /* This is the object we are looking for.  Say that we really
00121             want profiling and the timers are started.  */
00122          GL(dl_profile_map) = map;
00123        }
00124     }
00125 
00126   pg->resolve = resolve;
00127   pg->link = map;
00128 
00129   return lazy;
00130 }
00131 
00132 /* Initial entry point code for the dynamic linker.
00133    The C function `_dl_start' is the real entry point;
00134    its return value is the user program's entry point.  */
00135 
00136 #define RTLD_START asm ("\
00137        .section .text                                          \n\
00138        .set at                                                 \n\
00139        .globl _start                                    \n\
00140        .ent _start                                      \n\
00141 _start:                                                        \n\
00142        .frame $31,0,$31,0                               \n\
00143        br     $gp, 0f                                          \n\
00144 0:     ldgp   $gp, 0($gp)                               \n\
00145        .prologue 0                                      \n\
00146        /* Pass pointer to argument block to _dl_start.  */     \n\
00147        mov    $sp, $16                                  \n\
00148        bsr    $26, _dl_start              !samegp                     \n\
00149        .end _start                                      \n\
00150        /* FALLTHRU */                                          \n\
00151        .globl _dl_start_user                                   \n\
00152        .ent _dl_start_user                              \n\
00153 _dl_start_user:                                                \n\
00154        .frame $31,0,$31,0                               \n\
00155        .prologue 0                                      \n\
00156        /* Save the user entry point address in s0.  */         \n\
00157        mov    $0, $9                                    \n\
00158        /* See if we were run as a command with the executable  \n\
00159           file name as an extra leading argument.  */          \n\
00160        ldah   $1, _dl_skip_args($gp)      !gprelhigh           \n\
00161        ldl    $1, _dl_skip_args($1)       !gprellow            \n\
00162        bne    $1, $fixup_stack                          \n\
00163 $fixup_stack_ret:                                       \n\
00164        /* The special initializer gets called with the stack   \n\
00165           just as the application's entry point will see it;   \n\
00166           it can switch stacks if it moves these contents      \n\
00167           over.  */                                     \n\
00168 " RTLD_START_SPECIAL_INIT "                             \n\
00169        /* Call _dl_init(_dl_loaded, argc, argv, envp) to run   \n\
00170           initializers.  */                             \n\
00171        ldah   $16, _rtld_local($gp)       !gprelhigh           \n\
00172        ldq    $16, _rtld_local($16)       !gprellow            \n\
00173        ldq    $17, 0($sp)                               \n\
00174        lda    $18, 8($sp)                               \n\
00175        s8addq $17, 8, $19                               \n\
00176        addq   $19, $18, $19                             \n\
00177        bsr    $26, _dl_init_internal      !samegp                     \n\
00178        /* Pass our finalizer function to the user in $0. */    \n\
00179        ldah   $0, _dl_fini($gp)    !gprelhigh           \n\
00180        lda    $0, _dl_fini($0)     !gprellow            \n\
00181        /* Jump to the user's entry point.  */                  \n\
00182        mov    $9, $27                                          \n\
00183        jmp    ($9)                                      \n\
00184 $fixup_stack:                                           \n\
00185        /* Adjust the stack pointer to skip _dl_skip_args words.\n\
00186           This involves copying everything down, since the     \n\
00187           stack pointer must always be 16-byte aligned.  */    \n\
00188        ldah   $7, _dl_argv_internal($gp) !gprelhigh            \n\
00189        ldq    $2, 0($sp)                                \n\
00190        ldq    $5, _dl_argv_internal($7) !gprellow              \n\
00191        subq   $31, $1, $6                               \n\
00192        subq   $2, $1, $2                                \n\
00193        s8addq $6, $5, $5                                \n\
00194        mov    $sp, $4                                          \n\
00195        s8addq $1, $sp, $3                               \n\
00196        stq    $2, 0($sp)                                \n\
00197        stq    $5, _dl_argv_internal($7) !gprellow              \n\
00198        /* Copy down argv.  */                                  \n\
00199 0:     ldq    $5, 8($3)                                 \n\
00200        addq   $4, 8, $4                                 \n\
00201        addq   $3, 8, $3                                 \n\
00202        stq    $5, 0($4)                                 \n\
00203        bne    $5, 0b                                    \n\
00204        /* Copy down envp.  */                                  \n\
00205 1:     ldq    $5, 8($3)                                 \n\
00206        addq   $4, 8, $4                                 \n\
00207        addq   $3, 8, $3                                 \n\
00208        stq    $5, 0($4)                                 \n\
00209        bne    $5, 1b                                    \n\
00210        /* Copy down auxiliary table.  */                \n\
00211 2:     ldq    $5, 8($3)                                 \n\
00212        ldq    $6, 16($3)                                \n\
00213        addq   $4, 16, $4                                \n\
00214        addq   $3, 16, $3                                \n\
00215        stq    $5, -8($4)                                \n\
00216        stq    $6, 0($4)                                 \n\
00217        bne    $5, 2b                                    \n\
00218        br     $fixup_stack_ret                          \n\
00219        .end _dl_start_user                              \n\
00220        .set noat                                        \n\
00221 .previous");
00222 
00223 #ifndef RTLD_START_SPECIAL_INIT
00224 #define RTLD_START_SPECIAL_INIT /* nothing */
00225 #endif
00226 
00227 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry
00228    or TLS variables, so undefined references should not be allowed
00229    to define the value.
00230 
00231    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve
00232    to one of the main executable's symbols, as for a COPY reloc.
00233    This is unused on Alpha.  */
00234 
00235 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00236 # define elf_machine_type_class(type)     \
00237   (((type) == R_ALPHA_JMP_SLOT            \
00238     || (type) == R_ALPHA_DTPMOD64  \
00239     || (type) == R_ALPHA_DTPREL64  \
00240     || (type) == R_ALPHA_TPREL64) * ELF_RTYPE_CLASS_PLT)
00241 #else
00242 # define elf_machine_type_class(type)     \
00243   (((type) == R_ALPHA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)
00244 #endif
00245 
00246 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00247 #define ELF_MACHINE_JMP_SLOT        R_ALPHA_JMP_SLOT
00248 
00249 /* The alpha never uses Elf64_Rel relocations.  */
00250 #define ELF_MACHINE_NO_REL 1
00251 
00252 /* Fix up the instructions of a PLT entry to invoke the function
00253    rather than the dynamic linker.  */
00254 static inline Elf64_Addr
00255 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00256                      const Elf64_Rela *reloc,
00257                      Elf64_Addr *got_addr, Elf64_Addr value)
00258 {
00259   const Elf64_Rela *rela_plt;
00260   Elf64_Word *plte;
00261   long int edisp;
00262 
00263   /* Store the value we are going to load.  */
00264   *got_addr = value;
00265 
00266   /* If this binary uses the read-only secure plt format, we're done.  */
00267   if (map->l_info[DT_ALPHA(PLTRO)])
00268     return value;
00269 
00270   /* Otherwise we have to modify the plt entry in place to do the branch.  */
00271 
00272   /* Recover the PLT entry address by calculating reloc's index into the
00273      .rela.plt, and finding that entry in the .plt.  */
00274   rela_plt = (const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]);
00275   plte = (Elf64_Word *) (D_PTR (map, l_info[DT_PLTGOT]) + 32);
00276   plte += 3 * (reloc - rela_plt);
00277 
00278   /* Find the displacement from the plt entry to the function.  */
00279   edisp = (long int) (value - (Elf64_Addr)&plte[3]) / 4;
00280 
00281   if (edisp >= -0x100000 && edisp < 0x100000)
00282     {
00283       /* If we are in range, use br to perfect branch prediction and
00284         elide the dependency on the address load.  This case happens,
00285         e.g., when a shared library call is resolved to the same library.  */
00286 
00287       int hi, lo;
00288       hi = value - (Elf64_Addr)&plte[0];
00289       lo = (short int) hi;
00290       hi = (hi - lo) >> 16;
00291 
00292       /* Emit "lda $27,lo($27)" */
00293       plte[1] = 0x237b0000 | (lo & 0xffff);
00294 
00295       /* Emit "br $31,function" */
00296       plte[2] = 0xc3e00000 | (edisp & 0x1fffff);
00297 
00298       /* Think about thread-safety -- the previous instructions must be
00299         committed to memory before the first is overwritten.  */
00300       __asm__ __volatile__("wmb" : : : "memory");
00301 
00302       /* Emit "ldah $27,hi($27)" */
00303       plte[0] = 0x277b0000 | (hi & 0xffff);
00304     }
00305   else
00306     {
00307       /* Don't bother with the hint since we already know the hint is
00308         wrong.  Eliding it prevents the wrong page from getting pulled
00309         into the cache.  */
00310 
00311       int hi, lo;
00312       hi = (Elf64_Addr)got_addr - (Elf64_Addr)&plte[0];
00313       lo = (short)hi;
00314       hi = (hi - lo) >> 16;
00315 
00316       /* Emit "ldq $27,lo($27)" */
00317       plte[1] = 0xa77b0000 | (lo & 0xffff);
00318 
00319       /* Emit "jmp $31,($27)" */
00320       plte[2] = 0x6bfb0000;
00321 
00322       /* Think about thread-safety -- the previous instructions must be
00323         committed to memory before the first is overwritten.  */
00324       __asm__ __volatile__("wmb" : : : "memory");
00325 
00326       /* Emit "ldah $27,hi($27)" */
00327       plte[0] = 0x277b0000 | (hi & 0xffff);
00328     }
00329 
00330   /* At this point, if we've been doing runtime resolution, Icache is dirty.
00331      This will be taken care of in _dl_runtime_resolve.  If instead we are
00332      doing this as part of non-lazy startup relocation, that bit of code
00333      hasn't made it into Icache yet, so there's nothing to clean up.  */
00334 
00335   return value;
00336 }
00337 
00338 /* Return the final value of a plt relocation.  */
00339 static inline Elf64_Addr
00340 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
00341                      Elf64_Addr value)
00342 {
00343   return value + reloc->r_addend;
00344 }
00345 
00346 /* Names of the architecture-specific auditing callback functions.  */
00347 #define ARCH_LA_PLTENTER    alpha_gnu_pltenter
00348 #define ARCH_LA_PLTEXIT            alpha_gnu_pltexit
00349 
00350 #endif /* !dl_machine_h */
00351 
00352 #ifdef RESOLVE_MAP
00353 
00354 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00355    MAP is the object containing the reloc.  */
00356 auto inline void
00357 __attribute__ ((always_inline))
00358 elf_machine_rela (struct link_map *map,
00359                 const Elf64_Rela *reloc,
00360                 const Elf64_Sym *sym,
00361                 const struct r_found_version *version,
00362                 void *const reloc_addr_arg)
00363 {
00364   Elf64_Addr *const reloc_addr = reloc_addr_arg;
00365   unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
00366 
00367 #if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED
00368   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
00369      reference weak so static programs can still link.  This declaration
00370      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
00371      because rtld.c contains the common defn for _dl_rtld_map, which is
00372      incompatible with a weak decl in the same file.  */
00373   weak_extern (_dl_rtld_map);
00374 #endif
00375 
00376   /* We cannot use a switch here because we cannot locate the switch
00377      jump table until we've self-relocated.  */
00378 
00379 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
00380   if (__builtin_expect (r_type == R_ALPHA_RELATIVE, 0))
00381     {
00382 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
00383       /* Already done in dynamic linker.  */
00384       if (map != &GL(dl_rtld_map))
00385 # endif
00386        {
00387          /* XXX Make some timings.  Maybe it's preferable to test for
00388             unaligned access and only do it the complex way if necessary.  */
00389          Elf64_Addr reloc_addr_val;
00390 
00391          /* Load value without causing unaligned trap. */
00392          memcpy (&reloc_addr_val, reloc_addr_arg, 8);
00393          reloc_addr_val += map->l_addr;
00394 
00395          /* Store value without causing unaligned trap. */
00396          memcpy (reloc_addr_arg, &reloc_addr_val, 8);
00397        }
00398     }
00399   else
00400 #endif
00401     if (__builtin_expect (r_type == R_ALPHA_NONE, 0))
00402       return;
00403   else
00404     {
00405       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
00406       Elf64_Addr sym_value;
00407       Elf64_Addr sym_raw_value;
00408 
00409       sym_raw_value = sym_value = reloc->r_addend;
00410       if (sym_map)
00411        {
00412          sym_raw_value += sym->st_value;
00413          sym_value = sym_raw_value + sym_map->l_addr;
00414        }
00415 
00416       if (r_type == R_ALPHA_GLOB_DAT)
00417        *reloc_addr = sym_value;
00418 #ifdef RESOLVE_CONFLICT_FIND_MAP
00419       /* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have
00420         R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits
00421         are .rela.plt index.  */
00422       else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT)
00423        {
00424          /* elf_machine_fixup_plt needs the map reloc_addr points into,
00425             while in _dl_resolve_conflicts map is _dl_loaded.  */
00426          RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
00427          reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
00428                 + (r_type >> 8);
00429          elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
00430        }
00431 #else
00432       else if (r_type == R_ALPHA_JMP_SLOT)
00433        elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
00434 #endif
00435 #ifndef RTLD_BOOTSTRAP
00436       else if (r_type == R_ALPHA_REFQUAD)
00437        {
00438          /* Store value without causing unaligned trap.  */
00439          memcpy (reloc_addr_arg, &sym_value, 8);
00440        }
00441 #endif
00442 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00443       else if (r_type == R_ALPHA_DTPMOD64)
00444        {
00445 # ifdef RTLD_BOOTSTRAP
00446          /* During startup the dynamic linker is always index 1.  */
00447          *reloc_addr = 1;
00448 # else
00449          /* Get the information from the link map returned by the
00450             resolv function.  */
00451          if (sym_map != NULL)
00452            *reloc_addr = sym_map->l_tls_modid;
00453 # endif
00454        }
00455       else if (r_type == R_ALPHA_DTPREL64)
00456        {
00457 # ifndef RTLD_BOOTSTRAP
00458          /* During relocation all TLS symbols are defined and used.
00459             Therefore the offset is already correct.  */
00460          *reloc_addr = sym_raw_value;
00461 # endif
00462        }
00463       else if (r_type == R_ALPHA_TPREL64)
00464        {
00465 # ifdef RTLD_BOOTSTRAP
00466          *reloc_addr = sym_raw_value + map->l_tls_offset;
00467 # else
00468          if (sym_map)
00469            {
00470              CHECK_STATIC_TLS (map, sym_map);
00471              *reloc_addr = sym_raw_value + sym_map->l_tls_offset;
00472            }
00473 # endif
00474        }
00475 #endif
00476       else
00477        _dl_reloc_bad_type (map, r_type, 0);
00478     }
00479 }
00480 
00481 /* Let do-rel.h know that on Alpha if l_addr is 0, all RELATIVE relocs
00482    can be skipped.  */
00483 #define ELF_MACHINE_REL_RELATIVE 1
00484 
00485 auto inline void
00486 __attribute__ ((always_inline))
00487 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
00488                         void *const reloc_addr_arg)
00489 {
00490   /* XXX Make some timings.  Maybe it's preferable to test for
00491      unaligned access and only do it the complex way if necessary.  */
00492   Elf64_Addr reloc_addr_val;
00493 
00494   /* Load value without causing unaligned trap. */
00495   memcpy (&reloc_addr_val, reloc_addr_arg, 8);
00496   reloc_addr_val += l_addr;
00497 
00498   /* Store value without causing unaligned trap. */
00499   memcpy (reloc_addr_arg, &reloc_addr_val, 8);
00500 }
00501 
00502 auto inline void
00503 __attribute__ ((always_inline))
00504 elf_machine_lazy_rel (struct link_map *map,
00505                     Elf64_Addr l_addr, const Elf64_Rela *reloc)
00506 {
00507   Elf64_Addr * const reloc_addr = (void *)(l_addr + reloc->r_offset);
00508   unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
00509 
00510   if (r_type == R_ALPHA_JMP_SLOT)
00511     {
00512       /* Perform a RELATIVE reloc on the .got entry that transfers
00513         to the .plt.  */
00514       *reloc_addr += l_addr;
00515     }
00516   else if (r_type == R_ALPHA_NONE)
00517     return;
00518   else
00519     _dl_reloc_bad_type (map, r_type, 1);
00520 }
00521 
00522 #endif /* RESOLVE_MAP */