Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  AM33 version.
00002    Copyright (C) 1995,96,97,98,99,2000,2001, 2004
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public License as
00008    published by the Free Software Foundation; either version 2 of the
00009    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    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public
00017    License along with the GNU C Library; see the file COPYING.LIB.  If not,
00018    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.  */
00020 
00021 #ifndef dl_machine_h
00022 #define dl_machine_h
00023 
00024 #define ELF_MACHINE_NAME "mn10300"
00025 
00026 #include <sys/param.h>
00027 
00028 /* Return nonzero iff ELF header is compatible with the running host.  */
00029 static inline int __attribute__ ((unused))
00030 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
00031 {
00032   return ehdr->e_machine == EM_MN10300;
00033 }
00034 
00035 
00036 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
00037    first element of the GOT.  This must be inlined in a function which
00038    uses global data.  */
00039 static inline Elf32_Addr __attribute__ ((unused))
00040 elf_machine_dynamic (void)
00041 {
00042   register Elf32_Addr *got asm ("a2");
00043   return *got;
00044 }
00045 
00046 
00047 /* Return the run-time load address of the shared object.  */
00048 static inline Elf32_Addr __attribute__ ((unused))
00049 elf_machine_load_address (void)
00050 {
00051   register Elf32_Addr gotaddr asm ("a2");
00052   Elf32_Addr off, gotval;
00053 
00054   asm ("mov _dl_start@GOTOFF,%0" : "=r" (off));
00055   asm ("mov (_dl_start@GOT,%1),%0" : "=r" (gotval) : "r" (gotaddr));
00056 
00057   return off + gotaddr - gotval;
00058 }
00059 
00060 #if !defined PROF && !__BOUNDED_POINTERS__
00061 /* We add a declaration of this function here so that in dl-runtime.c
00062    the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
00063    in registers.
00064 
00065    We cannot use this scheme for profiling because the _mcount call
00066    destroys the passed register information.  */
00067 /* GKM FIXME: Fix trampoline to pass bounds so we can do
00068    without the `__unbounded' qualifier.  */
00069 static ElfW(Addr) fixup (struct link_map *__unbounded l, ElfW(Word) reloc_offset)
00070      __attribute__ ((unused));
00071 static ElfW(Addr) profile_fixup (struct link_map *l, ElfW(Word) reloc_offset,
00072                              ElfW(Addr) retaddr)
00073      __attribute__ ((unused));
00074 #endif
00075 
00076 /* Set up the loaded object described by L so its unrelocated PLT
00077    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00078 
00079 static inline int __attribute__ ((unused))
00080 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00081 {
00082   Elf32_Addr *got;
00083   extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
00084   extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
00085 
00086   if (l->l_info[DT_JMPREL] && lazy)
00087     {
00088       /* The GOT entries for functions in the PLT have not yet been filled
00089         in.  Their initial contents will arrange when called to push an
00090         offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
00091         and then jump to _GLOBAL_OFFSET_TABLE[2].  */
00092       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
00093       got[1] = (Elf32_Addr) l;     /* Identify this shared object.  */
00094 
00095       /* The got[2] entry contains the address of a function which gets
00096         called to get the address of a so far unresolved function and
00097         jump to it.  The profiling extension of the dynamic linker allows
00098         to intercept the calls to collect information.  In this case we
00099         don't store the address in the GOT so that all future calls also
00100         end in this function.  */
00101       if (__builtin_expect (profile, 0))
00102        {
00103          got[2] = (Elf32_Addr) &_dl_runtime_profile;
00104 
00105          if (_dl_name_match_p (GLRO(dl_profile), l))
00106            /* This is the object we are looking for.  Say that we really
00107               want profiling and the timers are started.  */
00108            GL(dl_profile_map) = l;
00109        }
00110       else
00111        /* This function will get called to fix up the GOT entry indicated by
00112           the offset on the stack, and then jump to the resolved address.  */
00113        got[2] = (Elf32_Addr) &_dl_runtime_resolve;
00114     }
00115 
00116   return lazy;
00117 }
00118 
00119 /* This code is used in dl-runtime.c to call the `fixup' function
00120    and then redirect to the address it returns.  */
00121 #if !defined PROF && !__BOUNDED_POINTERS__
00122 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
00123        .text\n\
00124        .globl _dl_runtime_resolve\n\
00125        .type _dl_runtime_resolve, @function\n\
00126 _dl_runtime_resolve:\n\
00127        add -12,sp           # Preserve registers otherwise clobbered.\n\
00128        mov d1,(20,sp)\n\
00129        mov d0,(16,sp)\n\
00130        mov r1,d0\n\
00131        mov r0,d1\n\
00132        call fixup,[],0             # Call resolver.\n\
00133        mov d0,a0\n\
00134        mov (12,sp),d1              # Copy return address back to mdr,\n\
00135        mov d1,mdr           # in case the callee returns with retf\n\
00136        mov (16,sp),d0              # Get register content back.\n\
00137        mov (20,sp),d1\n\
00138        add 12,sp\n\
00139        jmp (a0)\n\
00140        .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
00141 \n\
00142        .globl _dl_runtime_profile\n\
00143        .type _dl_runtime_profile, @function\n\
00144 _dl_runtime_profile:\n\
00145        add -12,sp           # Preserve registers otherwise clobbered.\n\
00146        mov d1,(20,sp)\n\
00147        mov d0,(16,sp)\n\
00148        mov r1,d0\n\
00149        mov r0,d1\n\
00150        call profile_fixup,[],0            # Call resolver.\n\
00151        mov d0,a0\n\
00152        mov (12,sp),d1              # Copy return address back to mdr,\n\
00153        mov d1,mdr           # in case the callee returns with retf\n\
00154        mov (16,sp),d0              # Get register content back.\n\
00155        mov (20,sp),d1\n\
00156        add 12,sp\n\
00157        jmp (a0)\n\
00158        .size _dl_runtime_profile, .-_dl_runtime_profile\n\
00159        .previous\n\
00160 ");
00161 #else
00162 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
00163        .text\n\
00164        .globl _dl_runtime_resolve\n\
00165        .globl _dl_runtime_profile\n\
00166        .type _dl_runtime_resolve, @function\n\
00167        .type _dl_runtime_profile, @function\n\
00168 _dl_runtime_resolve:\n\
00169 _dl_runtime_profile:\n\
00170        add -12,sp           # Preserve registers otherwise clobbered.\n\
00171        mov d1,(20,sp)\n\
00172        mov d0,(16,sp)\n\
00173        mov r1,d0\n\
00174        mov r0,d1\n\
00175        call profile_fixup,[],0            # Call resolver.\n\
00176        mov d0,a0\n\
00177        mov (12,sp),d1              # Copy return address back to mdr,\n\
00178        mov d1,mdr           # in case the callee returns with retf\n\
00179        mov (16,sp),d0              # Get register content back.\n\
00180        mov (20,sp),d1\n\
00181        add 12,sp\n\
00182        jmp (a0)\n\
00183        .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
00184        .size _dl_runtime_profile, .-_dl_runtime_profile\n\
00185        .previous\n\
00186 ");
00187 #endif
00188 
00189 /* Mask identifying addresses reserved for the user program,
00190    where the dynamic linker should not map anything.  */
00191 #define ELF_MACHINE_USER_ADDRESS_MASK     0xf8000000UL
00192 
00193 /* Initial entry point code for the dynamic linker.
00194    The C function `_dl_start' is the real entry point;
00195    its return value is the user program's entry point.  */
00196 #define RTLD_START asm ("\n\
00197        .text\n\
00198 .globl _start\n\
00199 .globl _dl_start_user\n\
00200 _start:\n\
00201        mov 0,a3      # Mark the top of the stack\n\
00202        mov sp,a1\n\
00203        add -20,sp    # Prepare for function call\n\
00204        mov a1,d0\n\
00205        call _dl_start,[],0\n\
00206 _dl_start_user:\n\
00207        # Save the user entry point address in d2.\n\
00208        mov d0,d2\n\
00209        # Point a2 at the GOT.\n\
00210 0:     mov pc,a2\n\
00211        add _GLOBAL_OFFSET_TABLE_ - (0b-.),a2\n\
00212        # Store the highest stack address\n\
00213        mov (__libc_stack_end@GOT,a2),a0\n\
00214        mov a1,(a0)\n\
00215        # See if we were run as a command with the executable file\n\
00216        # name as an extra leading argument.\n\
00217        mov (_dl_skip_args@GOT,a2),a0\n\
00218        mov (a0),d0\n\
00219        # Pop the original argument count.\n\
00220        mov (20,sp),d3\n\
00221        # Subtract _dl_skip_args from it.\n\
00222        sub d0,d3\n\
00223        # Adjust the stack pointer to skip _dl_skip_args words.\n\
00224        asl2 d0\n\
00225        mov sp,a0\n\
00226        add d0,a0\n\
00227        mov a0,sp\n\
00228        # Push argc back on the stack.\n\
00229        mov d3,(20,sp)\n\
00230        # The special initializer gets called with the stack just\n\
00231        # as the application's entry point will see it; it can\n\
00232        # switch stacks if it moves these contents over.\n\
00233 " RTLD_START_SPECIAL_INIT "\n\
00234        # Load the parameters again.\n\
00235        # (d0, d1, (12,sp), (16,sp)) = (_dl_loaded, argc, argv, envp)\n\
00236        add 24,a0\n\
00237        mov a0,(12,sp)       # a0 is 24+sp\n\
00238        mov d3,d1     # d3 contained argc\n\
00239        inc d3\n\
00240        asl2 d3              # d3 is now (argc+1)*4,\n\
00241        add d3,a0     # the offset between argv and envp\n\
00242        mov a0,(16,sp)\n\
00243        mov (_rtld_local@GOTOFF,a2),d0\n\
00244        # Call the function to run the initializers.\n\
00245        call _dl_init@PLT,[],0\n\
00246        # Pass our finalizer function to the user in d0, as per ELF ABI.\n\
00247        mov (_dl_fini@GOT,a2),d0\n\
00248        add 20,sp\n\
00249        # Jump to the user's entry point.\n\
00250        mov d2,a1\n\
00251        jmp (a1)\n\
00252        .previous\n\
00253 ");
00254 
00255 #ifndef RTLD_START_SPECIAL_INIT
00256 #define RTLD_START_SPECIAL_INIT /* nothing */
00257 #endif
00258 
00259 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
00260    PLT entries should not be allowed to define the value.
00261    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
00262    of the main executable's symbols, as for a COPY reloc.  */
00263 #define elf_machine_type_class(type) \
00264   ((((type) == R_MN10300_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)      \
00265    | (((type) == R_MN10300_COPY) * ELF_RTYPE_CLASS_COPY))
00266 
00267 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00268 #define ELF_MACHINE_JMP_SLOT       R_MN10300_JMP_SLOT
00269 
00270 static inline Elf32_Addr
00271 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00272                      const Elf32_Rela *reloc,
00273                      Elf32_Addr *reloc_addr, Elf32_Addr value)
00274 {
00275   return *reloc_addr = value;
00276 }
00277 
00278 /* Return the final value of a plt relocation.  */
00279 static inline Elf32_Addr
00280 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
00281                      Elf32_Addr value)
00282 {
00283   return value + reloc->r_addend;
00284 }
00285 
00286 #endif /* !dl_machine_h */
00287 
00288 #ifdef RESOLVE
00289 
00290 /* The mn10300 never uses Elf32_Rel relocations.  */
00291 #define ELF_MACHINE_NO_REL 1
00292 
00293 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00294    MAP is the object containing the reloc.  */
00295 
00296 static inline void
00297 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
00298                 const Elf32_Sym *sym, const struct r_found_version *version,
00299                 void *const reloc_addr_arg)
00300 {
00301   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00302   Elf32_Addr value, *reloc_addr;
00303 
00304   /* Make sure we drop any previous alignment assumptions.  */
00305   asm ("" : "=r" (reloc_addr) : "0" (reloc_addr_arg));
00306 
00307 #define COPY_UNALIGNED_WORD(sw, tw, align) \
00308   { \
00309     unsigned long *__sl = (void*)&(sw), *__tl = (void*)&(tw); \
00310     unsigned short *__ss = (void*)&(sw), *__ts = (void*)&(tw); \
00311     unsigned char *__sc = (void*)&(sw), *__tc = (void*)&(tw); \
00312     switch ((align)) \
00313     { \
00314     case 0: \
00315       *__tl = *__sl; \
00316       break; \
00317     case 2: \
00318       *__ts++ = *__ss++; \
00319       *__ts = *__ss; \
00320       break; \
00321     default: \
00322       *__tc++ = *__sc++; \
00323       *__tc++ = *__sc++; \
00324       *__tc++ = *__sc++; \
00325       *__tc = *__sc; \
00326       break; \
00327     } \
00328   }
00329 
00330 #define COPY_UNALIGNED_HALFWORD(sw, tw, align) \
00331   { \
00332     unsigned short *__ss = (void*)&(sw), *__ts = (void*)&(tw); \
00333     unsigned char *__sc = (void*)&(sw), *__tc = (void*)&(tw); \
00334     switch ((align)) \
00335     { \
00336     case 0: \
00337       *__ts = *__ss; \
00338       break; \
00339     default: \
00340       *__tc++ = *__sc++; \
00341       *__tc = *__sc; \
00342       break; \
00343     } \
00344   }
00345 
00346 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
00347   if (__builtin_expect (r_type == R_MN10300_RELATIVE, 0))
00348     {
00349 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
00350       /* This is defined in rtld.c, but nowhere in the static libc.a;
00351         make the reference weak so static programs can still link.
00352         This declaration cannot be done when compiling rtld.c (i.e.
00353         #ifdef RTLD_BOOTSTRAP) because rtld.c contains the common
00354         defn for _dl_rtld_map, which is incompatible with a weak decl
00355         in the same file.  */
00356       weak_extern (_dl_rtld_map);
00357       if (map != &_dl_rtld_map) /* Already done in rtld itself. */
00358 # endif
00359        {
00360          COPY_UNALIGNED_WORD (*reloc_addr, value, (int) reloc_addr & 3);
00361          value += map->l_addr;
00362          COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
00363        }
00364     }
00365 # ifndef RTLD_BOOTSTRAP
00366   else if (__builtin_expect (r_type == R_MN10300_NONE, 0))
00367     return;
00368 # endif
00369   else
00370 #endif
00371     {
00372 #ifndef RTLD_BOOTSTRAP
00373       const Elf32_Sym *const refsym = sym;
00374 #endif
00375 
00376       value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
00377       if (sym)
00378        value += sym->st_value;
00379       value += reloc->r_addend;    /* Assume copy relocs have zero addend.  */
00380 
00381       switch (r_type)
00382        {
00383 #ifndef RTLD_BOOTSTRAP
00384        case R_MN10300_COPY:
00385          if (sym == NULL)
00386            /* This can happen in trace mode if an object could not be
00387               found.  */
00388            break;
00389          if (sym->st_size > refsym->st_size
00390              || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
00391            {
00392              extern char **_dl_argv;
00393              const char *strtab;
00394 
00395              strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00396              _dl_error_printf ("\
00397 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00398                             _dl_argv[0] ?: "<program name unknown>",
00399                             strtab + refsym->st_name);
00400            }
00401          memcpy (reloc_addr, (void *) value, MIN (sym->st_size,
00402                                              refsym->st_size));
00403          break;
00404 #endif
00405        case R_MN10300_GLOB_DAT:
00406        case R_MN10300_JMP_SLOT:
00407          /* These addresses are always aligned.  */
00408          *reloc_addr = value;
00409          break;
00410        case R_MN10300_32:
00411          COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
00412          break;
00413 #ifndef RTLD_BOOTSTRAP
00414        case R_MN10300_16:
00415          COPY_UNALIGNED_HALFWORD (value, *reloc_addr, (int) reloc_addr & 1);
00416          break;
00417        case R_MN10300_8:
00418          *(char *) reloc_addr = value;
00419          break;
00420        case R_MN10300_PCREL32:
00421          value -= (Elf32_Addr) reloc_addr;
00422          COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
00423          break;
00424        case R_MN10300_PCREL16:
00425          value -= (Elf32_Addr) reloc_addr;
00426          COPY_UNALIGNED_HALFWORD (value, *reloc_addr, (int) reloc_addr & 1);
00427          break;
00428        case R_MN10300_PCREL8:
00429          value -= (Elf32_Addr) reloc_addr;
00430          *(char *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
00431          break;
00432 #endif
00433        case R_MN10300_NONE:        /* Alright, Wilbur.  */
00434          break;
00435 #if !defined RTLD_BOOTSTRAP || defined _NDEBUG
00436        default:
00437          _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
00438          break;
00439 #endif
00440        }
00441 
00442     }
00443 }
00444 
00445 static inline void
00446 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
00447                         void *const reloc_addr_arg)
00448 {
00449   Elf32_Addr value, *reloc_addr;
00450 
00451   asm ("" : "=r" (reloc_addr) : "0" (reloc_addr_arg));
00452 
00453   COPY_UNALIGNED_WORD (*reloc_addr, value, (int)reloc_addr & 3);
00454   value += l_addr;
00455   COPY_UNALIGNED_WORD (value, *reloc_addr, (int)reloc_addr & 3);
00456 }
00457 
00458 static inline void
00459 elf_machine_lazy_rel (struct link_map *map,
00460                     Elf32_Addr l_addr, const Elf32_Rela *reloc)
00461 {
00462   unsigned long int const r_type = ELF32_R_TYPE (reloc->r_info);
00463 
00464   /* Check for unexpected PLT reloc type.  */
00465   if (__builtin_expect (r_type, R_MN10300_JMP_SLOT) == R_MN10300_JMP_SLOT)
00466     {
00467       Elf32_Addr* const reloc_addr = (void *)(l_addr + reloc->r_offset);
00468       Elf32_Addr value;
00469 
00470       /* Perform a RELATIVE reloc on the .got entry that transfers
00471         to the .plt.  */
00472       COPY_UNALIGNED_WORD (*reloc_addr, value, (int)reloc_addr & 3);
00473       value += l_addr;
00474       COPY_UNALIGNED_WORD (value, *reloc_addr, (int)reloc_addr & 3);
00475     }
00476   else if (__builtin_expect (r_type, R_MN10300_NONE) != R_MN10300_NONE)
00477     _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
00478 
00479 }
00480 
00481 #endif /* RESOLVE */