Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
00002    Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 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 "m68k"
00024 
00025 #include <sys/param.h>
00026 #include <sysdep.h>
00027 
00028 /* Return nonzero iff ELF header is compatible with the running host.  */
00029 static inline int
00030 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
00031 {
00032   return ehdr->e_machine == EM_68K;
00033 }
00034 
00035 
00036 /* Return the link-time address of _DYNAMIC.
00037    This must be inlined in a function which uses global data.  */
00038 static inline Elf32_Addr
00039 elf_machine_dynamic (void)
00040 {
00041   Elf32_Addr addr;
00042 
00043   asm ("move.l _DYNAMIC@GOT.w(%%a5), %0"
00044        : "=a" (addr));
00045   return addr;
00046 }
00047 
00048 
00049 /* Return the run-time load address of the shared object.  */
00050 static inline Elf32_Addr
00051 elf_machine_load_address (void)
00052 {
00053   Elf32_Addr addr;
00054   asm (PCREL_OP ("lea", "_dl_start", "%0", "%0", "%%pc") "\n\t"
00055        "sub.l _dl_start@GOT.w(%%a5), %0"
00056        : "=a" (addr));
00057   return addr;
00058 }
00059 
00060 
00061 /* Set up the loaded object described by L so its unrelocated PLT
00062    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00063 
00064 static inline int __attribute__ ((always_inline))
00065 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
00066 {
00067   Elf32_Addr *got;
00068   extern void _dl_runtime_resolve (Elf32_Word);
00069   extern void _dl_runtime_profile (Elf32_Word);
00070 
00071   if (l->l_info[DT_JMPREL] && lazy)
00072     {
00073       /* The GOT entries for functions in the PLT have not yet been
00074         filled in.  Their initial contents will arrange when called
00075         to push an offset into the .rela.plt section, push
00076         _GLOBAL_OFFSET_TABLE_[1], and then jump to
00077         _GLOBAL_OFFSET_TABLE_[2].  */
00078       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
00079       got[1] = (Elf32_Addr) l;     /* Identify this shared object.  */
00080 
00081       /* The got[2] entry contains the address of a function which gets
00082         called to get the address of a so far unresolved function and
00083         jump to it.  The profiling extension of the dynamic linker allows
00084         to intercept the calls to collect information.  In this case we
00085         don't store the address in the GOT so that all future calls also
00086         end in this function.  */
00087       if (profile)
00088        {
00089          got[2] = (Elf32_Addr) &_dl_runtime_profile;
00090 
00091          if (GLRO(dl_profile) != NULL
00092              && _dl_name_match_p (GLRO(dl_profile), l))
00093            {
00094              /* This is the object we are looking for.  Say that we really
00095                want profiling and the timers are started.  */
00096              GL(dl_profile_map) = l;
00097            }
00098        }
00099       else
00100        /* This function will get called to fix up the GOT entry indicated by
00101           the offset on the stack, and then jump to the resolved address.  */
00102        got[2] = (Elf32_Addr) &_dl_runtime_resolve;
00103     }
00104 
00105   return lazy;
00106 }
00107 
00108 #define ELF_MACHINE_RUNTIME_FIXUP_ARGS long int save_a0, long int save_a1
00109 
00110 
00111 /* Mask identifying addresses reserved for the user program,
00112    where the dynamic linker should not map anything.  */
00113 #define ELF_MACHINE_USER_ADDRESS_MASK     0x80000000UL
00114 
00115 /* Initial entry point code for the dynamic linker.
00116    The C function `_dl_start' is the real entry point;
00117    its return value is the user program's entry point.  */
00118 
00119 #define RTLD_START asm ("\
00120        .text\n\
00121        .globl _start\n\
00122        .type _start,@function\n\
00123 _start:\n\
00124        move.l %sp, -(%sp)\n\
00125        jbsr _dl_start\n\
00126        addq.l #4, %sp\n\
00127        /* FALLTHRU */\n\
00128 \n\
00129        .globl _dl_start_user\n\
00130        .type _dl_start_user,@function\n\
00131 _dl_start_user:\n\
00132        | Save the user entry point address in %a4.\n\
00133        move.l %d0, %a4\n\
00134        | See if we were run as a command with the executable file\n\
00135        | name as an extra leading argument.\n\
00136        " PCREL_OP ("move.l", "_dl_skip_args", "%d0", "%d0", "%pc") "\n\
00137        | Pop the original argument count\n\
00138        move.l (%sp)+, %d1\n\
00139        | Subtract _dl_skip_args from it.\n\
00140        sub.l %d0, %d1\n\
00141        | Adjust the stack pointer to skip _dl_skip_args words.\n\
00142        lea (%sp, %d0*4), %sp\n\
00143        | Push back the modified argument count.\n\
00144        move.l %d1, -(%sp)\n\
00145        # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
00146        pea 8(%sp, %d1*4)\n\
00147        pea 8(%sp)\n\
00148        move.l %d1, -(%sp)\n\
00149        " PCREL_OP ("move.l", "_rtld_local", "-(%sp)", "%d0", "%pc") "\n\
00150        jbsr _dl_init_internal@PLTPC\n\
00151        addq.l #8, %sp\n\
00152        addq.l #8, %sp\n\
00153        | Pass our finalizer function to the user in %a1.\n\
00154        " PCREL_OP ("lea", "_dl_fini", "%a1", "%a1", "%pc") "\n\
00155        | Initialize %fp with the stack pointer.\n\
00156        move.l %sp, %fp\n\
00157        | Jump to the user's entry point.\n\
00158        jmp (%a4)\n\
00159        .size _dl_start_user, . - _dl_start_user\n\
00160        .previous");
00161 
00162 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
00163    PLT entries should not be allowed to define the value.
00164    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
00165    of the main executable's symbols, as for a COPY reloc.  */
00166 #define elf_machine_type_class(type) \
00167   ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)   \
00168    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
00169 
00170 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00171 #define ELF_MACHINE_JMP_SLOT       R_68K_JMP_SLOT
00172 
00173 /* The m68k never uses Elf32_Rel relocations.  */
00174 #define ELF_MACHINE_NO_REL 1
00175 
00176 static inline Elf32_Addr
00177 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
00178                      const Elf32_Rela *reloc,
00179                      Elf32_Addr *reloc_addr, Elf32_Addr value)
00180 {
00181   return *reloc_addr = value;
00182 }
00183 
00184 /* Return the final value of a plt relocation.  On the m68k the JMP_SLOT
00185    relocation ignores the addend.  */
00186 static inline Elf32_Addr
00187 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
00188                      Elf32_Addr value)
00189 {
00190   return value;
00191 }
00192 
00193 /* Names of the architecture-specific auditing callback functions.  */
00194 #define ARCH_LA_PLTENTER m68k_gnu_pltenter
00195 #define ARCH_LA_PLTEXIT m68k_gnu_pltexit
00196 
00197 #endif /* !dl_machine_h */
00198 
00199 #ifdef RESOLVE_MAP
00200 
00201 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
00202    MAP is the object containing the reloc.  */
00203 
00204 auto inline void __attribute__ ((unused, always_inline))
00205 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
00206                 const Elf32_Sym *sym, const struct r_found_version *version,
00207                 void *const reloc_addr_arg)
00208 {
00209   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00210   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
00211 
00212   if (__builtin_expect (r_type == R_68K_RELATIVE, 0))
00213     *reloc_addr = map->l_addr + reloc->r_addend;
00214   else
00215     {
00216       const Elf32_Sym *const refsym = sym;
00217       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
00218       Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
00219 
00220       switch (r_type)
00221        {
00222        case R_68K_COPY:
00223          if (sym == NULL)
00224            /* This can happen in trace mode if an object could not be
00225               found.  */
00226            break;
00227          if (sym->st_size > refsym->st_size
00228              || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
00229            {
00230              const char *strtab;
00231 
00232              strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00233              _dl_error_printf ("\
00234 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00235                             rtld_progname ?: "<program name unknown>",
00236                             strtab + refsym->st_name);
00237            }
00238          memcpy (reloc_addr_arg, (void *) value,
00239                 MIN (sym->st_size, refsym->st_size));
00240          break;
00241        case R_68K_GLOB_DAT:
00242        case R_68K_JMP_SLOT:
00243          *reloc_addr = value;
00244          break;
00245        case R_68K_8:
00246          *(char *) reloc_addr = value + reloc->r_addend;
00247          break;
00248        case R_68K_16:
00249          *(short *) reloc_addr = value + reloc->r_addend;
00250          break;
00251        case R_68K_32:
00252          *reloc_addr = value + reloc->r_addend;
00253          break;
00254        case R_68K_PC8:
00255          *(char *) reloc_addr
00256            = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
00257          break;
00258        case R_68K_PC16:
00259          *(short *) reloc_addr
00260            = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
00261          break;
00262        case R_68K_PC32:
00263          *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
00264          break;
00265        case R_68K_NONE:            /* Alright, Wilbur.  */
00266          break;
00267        default:
00268          _dl_reloc_bad_type (map, r_type, 0);
00269          break;
00270        }
00271     }
00272 }
00273 
00274 auto inline void __attribute__ ((unused, always_inline))
00275 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
00276                         void *const reloc_addr_arg)
00277 {
00278   Elf32_Addr *const reloc_addr = reloc_addr_arg;
00279   *reloc_addr = l_addr + reloc->r_addend;
00280 }
00281 
00282 auto inline void __attribute__ ((unused, always_inline))
00283 elf_machine_lazy_rel (struct link_map *map,
00284                     Elf32_Addr l_addr, const Elf32_Rela *reloc)
00285 {
00286   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
00287   if (ELF32_R_TYPE (reloc->r_info) == R_68K_JMP_SLOT)
00288     *reloc_addr += l_addr;
00289   else
00290     _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
00291 }
00292 
00293 #endif /* RESOLVE_MAP */