Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  i386 version.
00002    Copyright (C) 1995-2005, 2006 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 #ifndef dl_machine_h
00021 #define dl_machine_h
00022 
00023 #define ELF_MACHINE_NAME "i386"
00024 
00025 #include <sys/param.h>
00026 #include <sysdep.h>
00027 #include <tls.h>
00028 #include <dl-tlsdesc.h>
00029 
00030 /* Return nonzero iff ELF header is compatible with the running host.  */
00031 static inline int __attribute__ ((unused))
00032 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
00033 {
00034   return ehdr->e_machine == EM_386;
00035 }
00036 
00037 
00038 #ifdef PI_STATIC_AND_HIDDEN
00039 
00040 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00041    first element of the GOT, a special entry that is never relocated.  */
00042 static inline Elf32_Addr __attribute__ ((unused, const))
00043 elf_machine_dynamic (void)
00044 {
00045   /* This produces a GOTOFF reloc that resolves to zero at link time, so in
00046      fact just loads from the GOT register directly.  By doing it without
00047      an asm we can let the compiler choose any register.  */
00048   extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
00049   return _GLOBAL_OFFSET_TABLE_[0];
00050 }
00051 
00052 /* Return the run-time load address of the shared object.  */
00053 static inline Elf32_Addr __attribute__ ((unused))
00054 elf_machine_load_address (void)
00055 {
00056   /* Compute the difference between the runtime address of _DYNAMIC as seen
00057      by a GOTOFF reference, and the link-time address found in the special
00058      unrelocated first GOT entry.  */
00059   extern Elf32_Dyn bygotoff[] asm ("_DYNAMIC") attribute_hidden;
00060   return (Elf32_Addr) &bygotoff - elf_machine_dynamic ();
00061 }
00062 
00063 #else  /* Without .hidden support, we can't compile the code above.  */
00064 
00065 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00066    first element of the GOT.  This must be inlined in a function which
00067    uses global data.  */
00068 static inline Elf32_Addr __attribute__ ((unused))
00069 elf_machine_dynamic (void)
00070 {
00071   register Elf32_Addr *got asm ("%ebx");
00072   return *got;
00073 }
00074 
00075 
00076 /* Return the run-time load address of the shared object.  */
00077 static inline Elf32_Addr __attribute__ ((unused))
00078 elf_machine_load_address (void)
00079 {
00080   /* It doesn't matter what variable this is, the reference never makes
00081      it to assembly.  We need a dummy reference to some global variable
00082      via the GOT to make sure the compiler initialized %ebx in time.  */
00083   extern int _dl_argc;
00084   Elf32_Addr addr;
00085   asm ("leal _dl_start@GOTOFF(%%ebx), %0\n"
00086        "subl _dl_start@GOT(%%ebx), %0"
00087        : "=r" (addr) : "m" (_dl_argc) : "cc");
00088   return addr;
00089 }
00090 
00091 #endif
00092 
00093 
00094 /* Set up the loaded object described by L so its unrelocated PLT
00095    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00096 
00097 static inline int __attribute__ ((unused, always_inline))
00098 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00099 {
00100   Elf32_Addr *got;
00101   extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
00102   extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
00103 
00104   if (l->l_info[DT_JMPREL] && lazy)
00105     {
00106       /* The GOT entries for functions in the PLT have not yet been filled
00107         in.  Their initial contents will arrange when called to push an
00108         offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
00109         and then jump to _GLOBAL_OFFSET_TABLE[2].  */
00110       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
00111       /* If a library is prelinked but we have to relocate anyway,
00112         we have to be able to undo the prelinking of .got.plt.
00113         The prelinker saved us here address of .plt + 0x16.  */
00114       if (got[1])
00115        {
00116          l->l_mach.plt = got[1] + l->l_addr;
00117          l->l_mach.gotplt = (Elf32_Addr) &got[3];
00118        }
00119       got[1] = (Elf32_Addr) l;     /* Identify this shared object.  */
00120 
00121       /* The got[2] entry contains the address of a function which gets
00122         called to get the address of a so far unresolved function and
00123         jump to it.  The profiling extension of the dynamic linker allows
00124         to intercept the calls to collect information.  In this case we
00125         don't store the address in the GOT so that all future calls also
00126         end in this function.  */
00127       if (__builtin_expect (profile, 0))
00128        {
00129          got[2] = (Elf32_Addr) &_dl_runtime_profile;
00130 
00131          if (GLRO(dl_profile) != NULL
00132              && _dl_name_match_p (GLRO(dl_profile), l))
00133            /* This is the object we are looking for.  Say that we really
00134               want profiling and the timers are started.  */
00135            GL(dl_profile_map) = l;
00136        }
00137       else
00138        /* This function will get called to fix up the GOT entry indicated by
00139           the offset on the stack, and then jump to the resolved address.  */
00140        got[2] = (Elf32_Addr) &_dl_runtime_resolve;
00141     }
00142 
00143   return lazy;
00144 }
00145 
00146 #ifdef IN_DL_RUNTIME
00147 
00148 # if !defined PROF && !__BOUNDED_POINTERS__
00149 /* We add a declaration of this function here so that in dl-runtime.c
00150    the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
00151    in registers.
00152 
00153    We cannot use this scheme for profiling because the _mcount call
00154    destroys the passed register information.  */
00155 /* GKM FIXME: Fix trampoline to pass bounds so we can do
00156    without the `__unbounded' qualifier.  */
00157 #define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused))
00158 
00159 extern ElfW(Addr) _dl_fixup (struct link_map *__unbounded l,
00160                           ElfW(Word) reloc_offset)
00161      ARCH_FIXUP_ATTRIBUTE;
00162 extern ElfW(Addr) _dl_profile_fixup (struct link_map *l,
00163                                  ElfW(Word) reloc_offset,
00164                                  ElfW(Addr) retaddr, void *regs,
00165                                  long int *framesizep)
00166      ARCH_FIXUP_ATTRIBUTE;
00167 # endif
00168 
00169 #endif
00170 
00171 /* Mask identifying addresses reserved for the user program,
00172    where the dynamic linker should not map anything.  */
00173 #define ELF_MACHINE_USER_ADDRESS_MASK     0xf8000000UL
00174 
00175 /* Initial entry point code for the dynamic linker.
00176    The C function `_dl_start' is the real entry point;
00177    its return value is the user program's entry point.  */
00178 
00179 #define RTLD_START asm ("\n\
00180        .text\n\
00181        .align 16\n\
00182 0:     movl (%esp), %ebx\n\
00183        ret\n\
00184        .align 16\n\
00185 .globl _start\n\
00186 .globl _dl_start_user\n\
00187 _start:\n\
00188        # Note that _dl_start gets the parameter in %eax.\n\
00189        movl %esp, %eax\n\
00190        call _dl_start\n\
00191 _dl_start_user:\n\
00192        # Save the user entry point address in %edi.\n\
00193        movl %eax, %edi\n\
00194        # Point %ebx at the GOT.\n\
00195        call 0b\n\
00196        addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\
00197        # See if we were run as a command with the executable file\n\
00198        # name as an extra leading argument.\n\
00199        movl _dl_skip_args@GOTOFF(%ebx), %eax\n\
00200        # Pop the original argument count.\n\
00201        popl %edx\n\
00202        # Adjust the stack pointer to skip _dl_skip_args words.\n\
00203        leal (%esp,%eax,4), %esp\n\
00204        # Subtract _dl_skip_args from argc.\n\
00205        subl %eax, %edx\n\
00206        # Push argc back on the stack.\n\
00207        push %edx\n\
00208        # The special initializer gets called with the stack just\n\
00209        # as the application's entry point will see it; it can\n\
00210        # switch stacks if it moves these contents over.\n\
00211 " RTLD_START_SPECIAL_INIT "\n\
00212        # Load the parameters again.\n\
00213        # (eax, edx, ecx, *--esp) = (_dl_loaded, argc, argv, envp)\n\
00214        movl _rtld_local@GOTOFF(%ebx), %eax\n\
00215        leal 8(%esp,%edx,4), %esi\n\
00216        leal 4(%esp), %ecx\n\
00217        movl %esp, %ebp\n\
00218        # Make sure _dl_init is run with 16 byte aligned stack.\n\
00219        andl $-16, %esp\n\
00220        pushl %eax\n\
00221        pushl %eax\n\
00222        pushl %ebp\n\
00223        pushl %esi\n\
00224        # Clear %ebp, so that even constructors have terminated backchain.\n\
00225        xorl %ebp, %ebp\n\
00226        # Call the function to run the initializers.\n\
00227        call _dl_init_internal@PLT\n\
00228        # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
00229        leal _dl_fini@GOTOFF(%ebx), %edx\n\
00230        # Restore %esp _start expects.\n\
00231        movl (%esp), %esp\n\
00232        # Jump to the user's entry point.\n\
00233        jmp *%edi\n\
00234        .previous\n\
00235 ");
00236 
00237 #ifndef RTLD_START_SPECIAL_INIT
00238 # define RTLD_START_SPECIAL_INIT /* nothing */
00239 #endif
00240 
00241 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
00242    TLS variable, so undefined references should not be allowed to
00243    define the value.
00244    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
00245    of the main executable's symbols, as for a COPY reloc.  */
00246 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00247 # define elf_machine_type_class(type) \
00248   ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32               \
00249      || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32         \
00250      || (type) == R_386_TLS_TPOFF || (type) == R_386_TLS_DESC)              \
00251     * ELF_RTYPE_CLASS_PLT)                                           \
00252    | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
00253 #else
00254 # define elf_machine_type_class(type) \
00255   ((((type) == R_386_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)                       \
00256    | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
00257 #endif
00258 
00259 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00260 #define ELF_MACHINE_JMP_SLOT       R_386_JMP_SLOT
00261 
00262 /* The i386 never uses Elf32_Rela relocations for the dynamic linker.
00263    Prelinked libraries may use Elf32_Rela though.  */
00264 #define ELF_MACHINE_PLT_REL 1
00265 
00266 /* We define an initialization functions.  This is called very early in
00267    _dl_sysdep_start.  */
00268 #define DL_PLATFORM_INIT dl_platform_init ()
00269 
00270 static inline void __attribute__ ((unused))
00271 dl_platform_init (void)
00272 {
00273   if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
00274     /* Avoid an empty string which would disturb us.  */
00275     GLRO(dl_platform) = NULL;
00276 }
00277 
00278 static inline Elf32_Addr
00279 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00280                      const Elf32_Rel *reloc,
00281                      Elf32_Addr *reloc_addr, Elf32_Addr value)
00282 {
00283   return *reloc_addr = value;
00284 }
00285 
00286 /* Return the final value of a plt relocation.  */
00287 static inline Elf32_Addr
00288 elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
00289                      Elf32_Addr value)
00290 {
00291   return value;
00292 }
00293 
00294 
00295 /* Names of the architecture-specific auditing callback functions.  */
00296 #define ARCH_LA_PLTENTER i86_gnu_pltenter
00297 #define ARCH_LA_PLTEXIT i86_gnu_pltexit
00298 
00299 #endif /* !dl_machine_h */
00300 
00301 /* The i386 never uses Elf32_Rela relocations for the dynamic linker.
00302    Prelinked libraries may use Elf32_Rela though.  */
00303 #define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP
00304 
00305 #ifdef RESOLVE_MAP
00306 
00307 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00308    MAP is the object containing the reloc.  */
00309 
00310 auto inline void
00311 __attribute ((always_inline))
00312 elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
00313                const Elf32_Sym *sym, const struct r_found_version *version,
00314                void *const reloc_addr_arg)
00315 {
00316   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00317   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00318 
00319 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
00320   if (__builtin_expect (r_type == R_386_RELATIVE, 0))
00321     {
00322 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
00323       /* This is defined in rtld.c, but nowhere in the static libc.a;
00324         make the reference weak so static programs can still link.
00325         This declaration cannot be done when compiling rtld.c
00326         (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
00327         common defn for _dl_rtld_map, which is incompatible with a
00328         weak decl in the same file.  */
00329 #  ifndef SHARED
00330       weak_extern (_dl_rtld_map);
00331 #  endif
00332       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
00333 # endif
00334        *reloc_addr += map->l_addr;
00335     }
00336 # ifndef RTLD_BOOTSTRAP
00337   else if (__builtin_expect (r_type == R_386_NONE, 0))
00338     return;
00339 # endif
00340   else
00341 #endif /* !RTLD_BOOTSTRAP and have no -z combreloc */
00342     {
00343       const Elf32_Sym *const refsym = sym;
00344       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
00345       Elf32_Addr value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
00346 
00347       switch (r_type)
00348        {
00349        case R_386_GLOB_DAT:
00350        case R_386_JMP_SLOT:
00351          *reloc_addr = value;
00352          break;
00353 
00354 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00355        case R_386_TLS_DTPMOD32:
00356 # ifdef RTLD_BOOTSTRAP
00357          /* During startup the dynamic linker is always the module
00358             with index 1.
00359             XXX If this relocation is necessary move before RESOLVE
00360             call.  */
00361          *reloc_addr = 1;
00362 # else
00363          /* Get the information from the link map returned by the
00364             resolv function.  */
00365          if (sym_map != NULL)
00366            *reloc_addr = sym_map->l_tls_modid;
00367 # endif
00368          break;
00369        case R_386_TLS_DTPOFF32:
00370 # ifndef RTLD_BOOTSTRAP
00371          /* During relocation all TLS symbols are defined and used.
00372             Therefore the offset is already correct.  */
00373          if (sym != NULL)
00374            *reloc_addr = sym->st_value;
00375 # endif
00376          break;
00377        case R_386_TLS_DESC:
00378          {
00379            struct tlsdesc volatile *td =
00380              (struct tlsdesc volatile *)reloc_addr;
00381 
00382 # ifndef RTLD_BOOTSTRAP
00383            if (! sym)
00384              td->entry = _dl_tlsdesc_undefweak;
00385            else
00386 # endif
00387              {
00388 # ifndef RTLD_BOOTSTRAP
00389 #  ifndef SHARED
00390               CHECK_STATIC_TLS (map, sym_map);
00391 #  else
00392               if (!TRY_STATIC_TLS (map, sym_map))
00393                 {
00394                   td->arg = _dl_make_tlsdesc_dynamic
00395                     (sym_map, sym->st_value + (ElfW(Word))td->arg);
00396                   td->entry = _dl_tlsdesc_dynamic;
00397                 }
00398               else
00399 #  endif
00400 # endif
00401                 {
00402                   td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
00403                                   + (ElfW(Word))td->arg);
00404                   td->entry = _dl_tlsdesc_return;
00405                 }
00406              }
00407            break;
00408          }
00409        case R_386_TLS_TPOFF32:
00410          /* The offset is positive, backward from the thread pointer.  */
00411 # ifdef RTLD_BOOTSTRAP
00412          *reloc_addr += map->l_tls_offset - sym->st_value;
00413 # else
00414          /* We know the offset of object the symbol is contained in.
00415             It is a positive value which will be subtracted from the
00416             thread pointer.  To get the variable position in the TLS
00417             block we subtract the offset from that of the TLS block.  */
00418          if (sym != NULL)
00419            {
00420              CHECK_STATIC_TLS (map, sym_map);
00421              *reloc_addr += sym_map->l_tls_offset - sym->st_value;
00422            }
00423 # endif
00424          break;
00425        case R_386_TLS_TPOFF:
00426          /* The offset is negative, forward from the thread pointer.  */
00427 # ifdef RTLD_BOOTSTRAP
00428          *reloc_addr += sym->st_value - map->l_tls_offset;
00429 # else
00430          /* We know the offset of object the symbol is contained in.
00431             It is a negative value which will be added to the
00432             thread pointer.  */
00433          if (sym != NULL)
00434            {
00435              CHECK_STATIC_TLS (map, sym_map);
00436              *reloc_addr += sym->st_value - sym_map->l_tls_offset;
00437            }
00438 # endif
00439          break;
00440 #endif /* use TLS */
00441 
00442 #ifndef RTLD_BOOTSTRAP
00443        case R_386_32:
00444          *reloc_addr += value;
00445          break;
00446        case R_386_PC32:
00447          *reloc_addr += (value - (Elf32_Addr) reloc_addr);
00448          break;
00449        case R_386_COPY:
00450          if (sym == NULL)
00451            /* This can happen in trace mode if an object could not be
00452               found.  */
00453            break;
00454          if (__builtin_expect (sym->st_size > refsym->st_size, 0)
00455              || (__builtin_expect (sym->st_size < refsym->st_size, 0)
00456                 && GLRO(dl_verbose)))
00457            {
00458              const char *strtab;
00459 
00460              strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
00461              _dl_error_printf ("\
00462 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00463                             rtld_progname ?: "<program name unknown>",
00464                             strtab + refsym->st_name);
00465            }
00466          memcpy (reloc_addr_arg, (void *) value,
00467                 MIN (sym->st_size, refsym->st_size));
00468          break;
00469        default:
00470          _dl_reloc_bad_type (map, r_type, 0);
00471          break;
00472 #endif /* !RTLD_BOOTSTRAP */
00473        }
00474     }
00475 }
00476 
00477 #ifndef RTLD_BOOTSTRAP
00478 auto inline void
00479 __attribute__ ((always_inline))
00480 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
00481                 const Elf32_Sym *sym, const struct r_found_version *version,
00482                 void *const reloc_addr_arg)
00483 {
00484   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00485   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00486 
00487   if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
00488     *reloc_addr = map->l_addr + reloc->r_addend;
00489   else if (r_type != R_386_NONE)
00490     {
00491 # ifndef RESOLVE_CONFLICT_FIND_MAP
00492       const Elf32_Sym *const refsym = sym;
00493 # endif
00494       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
00495       Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
00496 
00497       switch (ELF32_R_TYPE (reloc->r_info))
00498        {
00499        case R_386_GLOB_DAT:
00500        case R_386_JMP_SLOT:
00501        case R_386_32:
00502          *reloc_addr = value + reloc->r_addend;
00503          break;
00504 # ifndef RESOLVE_CONFLICT_FIND_MAP
00505          /* Not needed for dl-conflict.c.  */
00506        case R_386_PC32:
00507          *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
00508          break;
00509 
00510        case R_386_TLS_DTPMOD32:
00511          /* Get the information from the link map returned by the
00512             resolv function.  */
00513          if (sym_map != NULL)
00514            *reloc_addr = sym_map->l_tls_modid;
00515          break;
00516        case R_386_TLS_DTPOFF32:
00517          /* During relocation all TLS symbols are defined and used.
00518             Therefore the offset is already correct.  */
00519          *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
00520          break;
00521        case R_386_TLS_DESC:
00522          {
00523            struct tlsdesc volatile *td =
00524              (struct tlsdesc volatile *)reloc_addr;
00525 
00526 # ifndef RTLD_BOOTSTRAP
00527            if (!sym)
00528              {
00529               td->arg = (void*)reloc->r_addend;
00530               td->entry = _dl_tlsdesc_undefweak;
00531              }
00532            else
00533 # endif
00534              {
00535 # ifndef RTLD_BOOTSTRAP
00536 #  ifndef SHARED
00537               CHECK_STATIC_TLS (map, sym_map);
00538 #  else
00539               if (!TRY_STATIC_TLS (map, sym_map))
00540                 {
00541                   td->arg = _dl_make_tlsdesc_dynamic
00542                     (sym_map, sym->st_value + reloc->r_addend);
00543                   td->entry = _dl_tlsdesc_dynamic;
00544                 }
00545               else
00546 #  endif
00547 # endif
00548                 {
00549                   td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
00550                                   + reloc->r_addend);
00551                   td->entry = _dl_tlsdesc_return;
00552                 }
00553              }
00554          }
00555          break;
00556        case R_386_TLS_TPOFF32:
00557          /* The offset is positive, backward from the thread pointer.  */
00558          /* We know the offset of object the symbol is contained in.
00559             It is a positive value which will be subtracted from the
00560             thread pointer.  To get the variable position in the TLS
00561             block we subtract the offset from that of the TLS block.  */
00562          if (sym != NULL)
00563            {
00564              CHECK_STATIC_TLS (map, sym_map);
00565              *reloc_addr = sym_map->l_tls_offset - sym->st_value
00566                          + reloc->r_addend;
00567            }
00568          break;
00569        case R_386_TLS_TPOFF:
00570          /* The offset is negative, forward from the thread pointer.  */
00571          /* We know the offset of object the symbol is contained in.
00572             It is a negative value which will be added to the
00573             thread pointer.  */
00574          if (sym != NULL)
00575            {
00576              CHECK_STATIC_TLS (map, sym_map);
00577              *reloc_addr = sym->st_value - sym_map->l_tls_offset
00578                          + reloc->r_addend;
00579            }
00580          break;
00581        case R_386_COPY:
00582          if (sym == NULL)
00583            /* This can happen in trace mode if an object could not be
00584               found.  */
00585            break;
00586          if (__builtin_expect (sym->st_size > refsym->st_size, 0)
00587              || (__builtin_expect (sym->st_size < refsym->st_size, 0)
00588                 && GLRO(dl_verbose)))
00589            {
00590              const char *strtab;
00591 
00592              strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
00593              _dl_error_printf ("\
00594 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00595                             rtld_progname ?: "<program name unknown>",
00596                             strtab + refsym->st_name);
00597            }
00598          memcpy (reloc_addr_arg, (void *) value,
00599                 MIN (sym->st_size, refsym->st_size));
00600          break;
00601 # endif /* !RESOLVE_CONFLICT_FIND_MAP */
00602        default:
00603          /* We add these checks in the version to relocate ld.so only
00604             if we are still debugging.  */
00605          _dl_reloc_bad_type (map, r_type, 0);
00606          break;
00607        }
00608     }
00609 }
00610 #endif /* !RTLD_BOOTSTRAP */
00611 
00612 auto inline void
00613 __attribute ((always_inline))
00614 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
00615                        void *const reloc_addr_arg)
00616 {
00617   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00618   assert (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE);
00619   *reloc_addr += l_addr;
00620 }
00621 
00622 #ifndef RTLD_BOOTSTRAP
00623 auto inline void
00624 __attribute__ ((always_inline))
00625 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
00626                         void *const reloc_addr_arg)
00627 {
00628   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00629   *reloc_addr = l_addr + reloc->r_addend;
00630 }
00631 #endif /* !RTLD_BOOTSTRAP */
00632 
00633 auto inline void
00634 __attribute__ ((always_inline))
00635 elf_machine_lazy_rel (struct link_map *map,
00636                     Elf32_Addr l_addr, const Elf32_Rel *reloc)
00637 {
00638   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
00639   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00640   /* Check for unexpected PLT reloc type.  */
00641   if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
00642     {
00643       if (__builtin_expect (map->l_mach.plt, 0) == 0)
00644        *reloc_addr += l_addr;
00645       else
00646        *reloc_addr = (map->l_mach.plt
00647                      + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4);
00648     }
00649   else if (__builtin_expect (r_type == R_386_TLS_DESC, 1))
00650     {
00651       struct tlsdesc volatile * __attribute__((__unused__)) td =
00652        (struct tlsdesc volatile *)reloc_addr;
00653 
00654       /* Handle relocations that reference the local *ABS* in a simple
00655         way, so as to preserve a potential addend.  */
00656       if (ELF32_R_SYM (reloc->r_info) == 0)
00657        td->entry = _dl_tlsdesc_resolve_abs_plus_addend;
00658       /* Given a known-zero addend, we can store a pointer to the
00659         reloc in the arg position.  */
00660       else if (td->arg == 0)
00661        {
00662          td->arg = (void*)reloc;
00663          td->entry = _dl_tlsdesc_resolve_rel;
00664        }
00665       else
00666        {
00667          /* We could handle non-*ABS* relocations with non-zero addends
00668             by allocating dynamically an arg to hold a pointer to the
00669             reloc, but that sounds pointless.  */
00670          const Elf32_Rel *const r = reloc;
00671          /* The code below was borrowed from elf_dynamic_do_rel().  */
00672          const ElfW(Sym) *const symtab =
00673            (const void *) D_PTR (map, l_info[DT_SYMTAB]);
00674 
00675 #ifdef RTLD_BOOTSTRAP
00676          /* The dynamic linker always uses versioning.  */
00677          assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
00678 #else
00679          if (map->l_info[VERSYMIDX (DT_VERSYM)])
00680 #endif
00681            {
00682              const ElfW(Half) *const version =
00683               (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
00684              ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
00685              elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
00686                             &map->l_versions[ndx],
00687                             (void *) (l_addr + r->r_offset));
00688            }
00689 #ifndef RTLD_BOOTSTRAP
00690          else
00691            elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
00692                           (void *) (l_addr + r->r_offset));
00693 #endif
00694        }
00695     }
00696   else
00697     _dl_reloc_bad_type (map, r_type, 1);
00698 }
00699 
00700 #ifndef RTLD_BOOTSTRAP
00701 
00702 auto inline void
00703 __attribute__ ((always_inline))
00704 elf_machine_lazy_rela (struct link_map *map,
00705                      Elf32_Addr l_addr, const Elf32_Rela *reloc)
00706 {
00707   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
00708   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00709   if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
00710     ;
00711   else if (__builtin_expect (r_type == R_386_TLS_DESC, 1))
00712     {
00713       struct tlsdesc volatile * __attribute__((__unused__)) td =
00714        (struct tlsdesc volatile *)reloc_addr;
00715 
00716       td->arg = (void*)reloc;
00717       td->entry = _dl_tlsdesc_resolve_rela;
00718     }
00719   else
00720     _dl_reloc_bad_type (map, r_type, 1);
00721 }
00722 
00723 #endif /* !RTLD_BOOTSTRAP */
00724 
00725 #endif /* RESOLVE_MAP */