Back to index

glibc  2.9
dynamic-link.h
Go to the documentation of this file.
00001 /* Inline functions for dynamic linking.
00002    Copyright (C) 1995-2005, 2006, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 /* This macro is used as a callback from elf_machine_rel{a,} when a
00021    static TLS reloc is about to be performed.  Since (in dl-load.c) we
00022    permit dynamic loading of objects that might use such relocs, we
00023    have to check whether each use is actually doable.  If the object
00024    whose TLS segment the reference resolves to was allocated space in
00025    the static TLS block at startup, then it's ok.  Otherwise, we make
00026    an attempt to allocate it in surplus space on the fly.  If that
00027    can't be done, we fall back to the error that DF_STATIC_TLS is
00028    intended to produce.  */
00029 #define CHECK_STATIC_TLS(map, sym_map)                                \
00030     do {                                                       \
00031       if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET  \
00032                          || ((sym_map)->l_tls_offset                  \
00033                             == FORCED_DYNAMIC_TLS_OFFSET), 0)) \
00034        _dl_allocate_static_tls (sym_map);                      \
00035     } while (0)
00036 
00037 #define TRY_STATIC_TLS(map, sym_map)                                  \
00038     (__builtin_expect ((sym_map)->l_tls_offset                        \
00039                      != FORCED_DYNAMIC_TLS_OFFSET, 1)                 \
00040      && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1)      \
00041         || _dl_try_allocate_static_tls (sym_map) == 0))
00042 
00043 int internal_function _dl_try_allocate_static_tls (struct link_map *map);
00044 
00045 #include <elf.h>
00046 #include <assert.h>
00047 
00048 #ifdef RESOLVE_MAP
00049 /* We pass reloc_addr as a pointer to void, as opposed to a pointer to
00050    ElfW(Addr), because not all architectures can assume that the
00051    relocated address is properly aligned, whereas the compiler is
00052    entitled to assume that a pointer to a type is properly aligned for
00053    the type.  Even if we cast the pointer back to some other type with
00054    less strict alignment requirements, the compiler might still
00055    remember that the pointer was originally more aligned, thereby
00056    optimizing away alignment tests or using word instructions for
00057    copying memory, breaking the very code written to handle the
00058    unaligned cases.  */
00059 # if ! ELF_MACHINE_NO_REL
00060 auto inline void __attribute__((always_inline))
00061 elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
00062                const ElfW(Sym) *sym, const struct r_found_version *version,
00063                void *const reloc_addr);
00064 auto inline void __attribute__((always_inline))
00065 elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
00066                        void *const reloc_addr);
00067 # endif
00068 # if ! ELF_MACHINE_NO_RELA
00069 auto inline void __attribute__((always_inline))
00070 elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
00071                 const ElfW(Sym) *sym, const struct r_found_version *version,
00072                 void *const reloc_addr);
00073 auto inline void __attribute__((always_inline))
00074 elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
00075                         void *const reloc_addr);
00076 # endif
00077 # if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
00078 auto inline void __attribute__((always_inline))
00079 elf_machine_lazy_rel (struct link_map *map,
00080                     ElfW(Addr) l_addr, const ElfW(Rel) *reloc);
00081 # else
00082 auto inline void __attribute__((always_inline))
00083 elf_machine_lazy_rel (struct link_map *map,
00084                     ElfW(Addr) l_addr, const ElfW(Rela) *reloc);
00085 # endif
00086 #endif
00087 
00088 #include <dl-machine.h>
00089 
00090 #ifndef VERSYMIDX
00091 # define VERSYMIDX(sym)     (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
00092 #endif
00093 
00094 
00095 /* Read the dynamic section at DYN and fill in INFO with indices DT_*.  */
00096 #ifndef RESOLVE_MAP
00097 static
00098 #else
00099 auto
00100 #endif
00101 inline void __attribute__ ((unused, always_inline))
00102 elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
00103 {
00104   ElfW(Dyn) *dyn = l->l_ld;
00105   ElfW(Dyn) **info;
00106 
00107 #ifndef RTLD_BOOTSTRAP
00108   if (dyn == NULL)
00109     return;
00110 #endif
00111 
00112   info = l->l_info;
00113 
00114   while (dyn->d_tag != DT_NULL)
00115     {
00116       if (dyn->d_tag < DT_NUM)
00117        info[dyn->d_tag] = dyn;
00118       else if (dyn->d_tag >= DT_LOPROC &&
00119               dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
00120        info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
00121       else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
00122        info[VERSYMIDX (dyn->d_tag)] = dyn;
00123       else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
00124        info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
00125             + DT_VERSIONTAGNUM] = dyn;
00126       else if ((Elf32_Word) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
00127        info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
00128             + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
00129       else if ((Elf32_Word) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
00130        info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
00131             + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
00132       ++dyn;
00133     }
00134 
00135 #define DL_RO_DYN_TEMP_CNT  8
00136 
00137 #ifndef DL_RO_DYN_SECTION
00138   /* Don't adjust .dynamic unnecessarily.  */
00139   if (l->l_addr != 0)
00140     {
00141       ElfW(Addr) l_addr = l->l_addr;
00142       int cnt = 0;
00143 
00144 # define ADJUST_DYN_INFO(tag) \
00145       do                                                             \
00146        if (info[tag] != NULL)                                               \
00147          {                                                           \
00148            if (temp)                                                 \
00149              {                                                              \
00150               temp[cnt].d_tag = info[tag]->d_tag;                           \
00151               temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr;        \
00152               info[tag] = temp + cnt++;                              \
00153              }                                                              \
00154            else                                                      \
00155              info[tag]->d_un.d_ptr += l_addr;                               \
00156          }                                                           \
00157       while (0)
00158 
00159       ADJUST_DYN_INFO (DT_HASH);
00160       ADJUST_DYN_INFO (DT_PLTGOT);
00161       ADJUST_DYN_INFO (DT_STRTAB);
00162       ADJUST_DYN_INFO (DT_SYMTAB);
00163 # if ! ELF_MACHINE_NO_RELA
00164       ADJUST_DYN_INFO (DT_RELA);
00165 # endif
00166 # if ! ELF_MACHINE_NO_REL
00167       ADJUST_DYN_INFO (DT_REL);
00168 # endif
00169       ADJUST_DYN_INFO (DT_JMPREL);
00170       ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
00171       ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
00172                      + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
00173 # undef ADJUST_DYN_INFO
00174       assert (cnt <= DL_RO_DYN_TEMP_CNT);
00175     }
00176 #endif
00177   if (info[DT_PLTREL] != NULL)
00178     {
00179 #if ELF_MACHINE_NO_RELA
00180       assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
00181 #elif ELF_MACHINE_NO_REL
00182       assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
00183 #else
00184       assert (info[DT_PLTREL]->d_un.d_val == DT_REL
00185              || info[DT_PLTREL]->d_un.d_val == DT_RELA);
00186 #endif
00187     }
00188 #if ! ELF_MACHINE_NO_RELA
00189   if (info[DT_RELA] != NULL)
00190     assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
00191 # endif
00192 # if ! ELF_MACHINE_NO_REL
00193   if (info[DT_REL] != NULL)
00194     assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
00195 #endif
00196 #ifdef RTLD_BOOTSTRAP
00197   /* Only the bind now flags are allowed.  */
00198   assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL
00199          || info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val == DF_1_NOW);
00200   assert (info[DT_FLAGS] == NULL
00201          || info[DT_FLAGS]->d_un.d_val == DF_BIND_NOW);
00202   /* Flags must not be set for ld.so.  */
00203   assert (info[DT_RUNPATH] == NULL);
00204   assert (info[DT_RPATH] == NULL);
00205 #else
00206   if (info[DT_FLAGS] != NULL)
00207     {
00208       /* Flags are used.  Translate to the old form where available.
00209         Since these l_info entries are only tested for NULL pointers it
00210         is ok if they point to the DT_FLAGS entry.  */
00211       l->l_flags = info[DT_FLAGS]->d_un.d_val;
00212 
00213       if (l->l_flags & DF_SYMBOLIC)
00214        info[DT_SYMBOLIC] = info[DT_FLAGS];
00215       if (l->l_flags & DF_TEXTREL)
00216        info[DT_TEXTREL] = info[DT_FLAGS];
00217       if (l->l_flags & DF_BIND_NOW)
00218        info[DT_BIND_NOW] = info[DT_FLAGS];
00219     }
00220   if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
00221     {
00222       l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
00223 
00224       if (l->l_flags_1 & DF_1_NOW)
00225        info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)];
00226     }
00227   if (info[DT_RUNPATH] != NULL)
00228     /* If both RUNPATH and RPATH are given, the latter is ignored.  */
00229     info[DT_RPATH] = NULL;
00230 #endif
00231 }
00232 
00233 #ifdef RESOLVE_MAP
00234 
00235 # ifdef RTLD_BOOTSTRAP
00236 #  define ELF_DURING_STARTUP (1)
00237 # else
00238 #  define ELF_DURING_STARTUP (0)
00239 # endif
00240 
00241 /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
00242    These functions are almost identical, so we use cpp magic to avoid
00243    duplicating their code.  It cannot be done in a more general function
00244    because we must be able to completely inline.  */
00245 
00246 /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
00247    range.  Note that according to the ELF spec, this is completely legal!
00248    But conditionally define things so that on machines we know this will
00249    not happen we do something more optimal.  */
00250 
00251 # ifdef ELF_MACHINE_PLTREL_OVERLAP
00252 #  define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
00253   do {                                                               \
00254     struct { ElfW(Addr) start, size; int lazy; } ranges[3];                 \
00255     int ranges_index;                                                       \
00256                                                                      \
00257     ranges[0].lazy = ranges[2].lazy = 0;                             \
00258     ranges[1].lazy = 1;                                                     \
00259     ranges[0].size = ranges[1].size = ranges[2].size = 0;                   \
00260                                                                      \
00261     if ((map)->l_info[DT_##RELOC])                                   \
00262       {                                                                     \
00263        ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]);                 \
00264        ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;          \
00265       }                                                                     \
00266                                                                      \
00267     if ((do_lazy)                                                    \
00268        && (map)->l_info[DT_PLTREL]                                   \
00269        && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
00270       {                                                                     \
00271        ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]);                  \
00272        ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;             \
00273        ranges[2].start = ranges[1].start + ranges[1].size;                  \
00274        ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start;  \
00275        ranges[0].size = ranges[1].start - ranges[0].start;                  \
00276       }                                                                     \
00277                                                                      \
00278     for (ranges_index = 0; ranges_index < 3; ++ranges_index)                \
00279       elf_dynamic_do_##reloc ((map),                                        \
00280                            ranges[ranges_index].start,               \
00281                            ranges[ranges_index].size,                \
00282                            ranges[ranges_index].lazy);               \
00283   } while (0)
00284 # else
00285 #  define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
00286   do {                                                               \
00287     struct { ElfW(Addr) start, size; int lazy; } ranges[2];                 \
00288     ranges[0].lazy = 0;                                                     \
00289     ranges[0].size = ranges[1].size = 0;                             \
00290     ranges[0].start = 0;                                             \
00291                                                                      \
00292     if ((map)->l_info[DT_##RELOC])                                   \
00293       {                                                                     \
00294        ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]);                 \
00295        ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val;          \
00296       }                                                                     \
00297     if ((map)->l_info[DT_PLTREL]                                     \
00298        && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
00299       {                                                                     \
00300        ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]);                 \
00301                                                                      \
00302        if (! ELF_DURING_STARTUP                                      \
00303            && ((do_lazy)                                             \
00304               /* This test does not only detect whether the relocation      \
00305                  sections are in the right order, it also checks whether    \
00306                  there is a DT_REL/DT_RELA section.  */              \
00307               || ranges[0].start + ranges[0].size != start))                \
00308          {                                                           \
00309            ranges[1].start = start;                                         \
00310            ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val;         \
00311            ranges[1].lazy = (do_lazy);                                      \
00312          }                                                           \
00313        else                                                          \
00314          {                                                           \
00315            /* Combine processing the sections.  */                          \
00316            assert (ranges[0].start + ranges[0].size == start);              \
00317            ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val;        \
00318          }                                                           \
00319       }                                                                     \
00320                                                                      \
00321     if (ELF_DURING_STARTUP)                                          \
00322       elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0);     \
00323     else                                                             \
00324       {                                                                     \
00325        int ranges_index;                                             \
00326        for (ranges_index = 0; ranges_index < 2; ++ranges_index)             \
00327          elf_dynamic_do_##reloc ((map),                              \
00328                               ranges[ranges_index].start,                   \
00329                               ranges[ranges_index].size,                    \
00330                               ranges[ranges_index].lazy);                   \
00331       }                                                                     \
00332   } while (0)
00333 # endif
00334 
00335 # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
00336 #  define _ELF_CHECK_REL 0
00337 # else
00338 #  define _ELF_CHECK_REL 1
00339 # endif
00340 
00341 # if ! ELF_MACHINE_NO_REL
00342 #  include "do-rel.h"
00343 #  define ELF_DYNAMIC_DO_REL(map, lazy) \
00344   _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
00345 # else
00346 #  define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do.  */
00347 # endif
00348 
00349 # if ! ELF_MACHINE_NO_RELA
00350 #  define DO_RELA
00351 #  include "do-rel.h"
00352 #  define ELF_DYNAMIC_DO_RELA(map, lazy) \
00353   _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
00354 # else
00355 #  define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do.  */
00356 # endif
00357 
00358 /* This can't just be an inline function because GCC is too dumb
00359    to inline functions containing inlines themselves.  */
00360 # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
00361   do {                                                               \
00362     int edr_lazy = elf_machine_runtime_setup ((map), (lazy),                \
00363                                          (consider_profile));        \
00364     ELF_DYNAMIC_DO_REL ((map), edr_lazy);                            \
00365     ELF_DYNAMIC_DO_RELA ((map), edr_lazy);                                  \
00366   } while (0)
00367 
00368 #endif