glibc/sysdeps/m68k/dl-machine.h

282 lines
9 KiB
C
Raw Normal View History

/* Machine-dependent ELF dynamic relocation inline functions. m68k version.
Copyright (C) 1996 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#define ELF_MACHINE_NAME "m68k"
#include <assert.h>
#include <string.h>
#include <link.h>
/* Return nonzero iff E_MACHINE is compatible with the running host. */
static inline int
elf_machine_matches_host (Elf32_Half e_machine)
{
switch (e_machine)
{
case EM_68K:
return 1;
default:
return 0;
}
}
/* Return the run-time address of the _GLOBAL_OFFSET_TABLE_.
Must be inlined in a function which uses global data. */
static inline Elf32_Addr *
elf_machine_got (void)
{
register Elf32_Addr *got asm ("%a5");
return got;
}
/* Return the run-time load address of the shared object. */
static inline Elf32_Addr
elf_machine_load_address (void)
{
1996-02-19 21:54:38 +01:00
Elf32_Addr addr;
asm ("here: lea here(%%pc), %0\n"
" sub.l %#here, %0"
: "=a" (addr));
return addr;
}
1996-02-19 21:54:38 +01:00
/* The `subl' insn above will contain an R_68K_RELATIVE relocation
entry intended to insert the run-time address of the label `here'.
This will be the first relocation in the text of the dynamic
linker; we skip it to avoid trying to modify read-only text in this
early stage. */
#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) \
((dynamic_info)[DT_RELA]->d_un.d_ptr += sizeof (Elf32_Rela), \
(dynamic_info)[DT_RELASZ]->d_un.d_val -= sizeof (Elf32_Rela))
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
MAP is the object containing the reloc. */
static inline void
elf_machine_rela (struct link_map *map,
const Elf32_Rela *reloc, const Elf32_Sym *sym,
Elf32_Addr (*resolve) (const Elf32_Sym **ref,
Elf32_Addr reloc_addr,
int noplt))
{
Elf32_Addr *const reloc_addr = (void *) (map->l_addr + reloc->r_offset);
Elf32_Addr loadbase;
switch (ELF32_R_TYPE (reloc->r_info))
{
case R_68K_COPY:
loadbase = (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0);
memcpy (reloc_addr, (void *) (loadbase + sym->st_value), sym->st_size);
break;
case R_68K_GLOB_DAT:
loadbase = (resolve ? (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0) :
/* RESOLVE is null during bootstrap relocation. */
map->l_addr);
*reloc_addr = sym ? (loadbase + sym->st_value) : 0;
break;
case R_68K_JMP_SLOT:
loadbase = (resolve ? (*resolve) (&sym, (Elf32_Addr) reloc_addr, 1) :
/* RESOLVE is null during bootstrap relocation. */
map->l_addr);
*reloc_addr = sym ? (loadbase + sym->st_value) : 0;
break;
case R_68K_8:
loadbase = (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0);
*(char *) reloc_addr = ((sym ? (loadbase + sym->st_value) : 0)
+ reloc->r_addend);
break;
case R_68K_16:
loadbase = (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0);
*(short *) reloc_addr = ((sym ? (loadbase + sym->st_value) : 0)
+ reloc->r_addend);
break;
case R_68K_32:
loadbase = (resolve ? (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0) :
/* RESOLVE is null during bootstrap relocation. */
map->l_addr);
*reloc_addr = ((sym ? (loadbase + sym->st_value) : 0)
+ reloc->r_addend);
break;
case R_68K_RELATIVE:
*reloc_addr = map->l_addr + reloc->r_addend;
break;
case R_68K_PC8:
loadbase = (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0);
*(char *) reloc_addr = ((sym ? (loadbase + sym->st_value) : 0)
+ reloc->r_addend
- (Elf32_Addr) reloc_addr);
break;
case R_68K_PC16:
loadbase = (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0);
*(short *) reloc_addr = ((sym ? (loadbase + sym->st_value) : 0)
+ reloc->r_addend
- (Elf32_Addr) reloc_addr);
break;
case R_68K_PC32:
loadbase = (*resolve) (&sym, (Elf32_Addr) reloc_addr, 0);
*reloc_addr = ((sym ? (loadbase + sym->st_value) : 0)
+ reloc->r_addend
- (Elf32_Addr) reloc_addr);
break;
case R_68K_NONE: /* Alright, Wilbur. */
break;
default:
assert (! "unexpected dynamic reloc type");
break;
}
}
static inline void
elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc)
{
Elf32_Addr *const reloc_addr = (void *) (map->l_addr + reloc->r_offset);
switch (ELF32_R_TYPE (reloc->r_info))
{
case R_68K_NONE:
break;
case R_68K_JMP_SLOT:
*reloc_addr += map->l_addr;
break;
default:
assert (! "unexpected PLT reloc type");
break;
}
}
/* Nonzero iff TYPE describes relocation of a PLT entry, so
PLT entries should not be allowed to define the value. */
#define elf_machine_pltrel_p(type) ((type) == R_68K_JMP_SLOT)
/* The m68k never uses Elf32_Rel relocations. */
#define ELF_MACHINE_NO_REL 1
/* Set up the loaded object described by L so its unrelocated PLT
entries will jump to the on-demand fixup code in dl-runtime.c. */
static inline void
elf_machine_runtime_setup (struct link_map *l, int lazy)
{
Elf32_Addr *got;
extern void _dl_runtime_resolve (Elf32_Word);
if (l->l_info[DT_JMPREL] && lazy)
{
/* The GOT entries for functions in the PLT have not yet been
filled in. Their initial contents will arrange when called
to push an offset into the .rela.plt section, push
_GLOBAL_OFFSET_TABLE_[1], and then jump to
_GLOBAL_OFFSET_TABLE_[2]. */
got = (Elf32_Addr *) (l->l_addr + l->l_info[DT_PLTGOT]->d_un.d_ptr);
got[1] = (Elf32_Addr) l; /* Identify this shared object. */
/* This function will get called to fix up the GOT entry
indicated by the offset on the stack, and then jump to the
resolved address. */
got[2] = (Elf32_Addr) &_dl_runtime_resolve;
}
/* This code is used in dl-runtime.c to call the `fixup' function
and then redirect to the address it returns. */
#define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
| Trampoline for _dl_runtime_resolver
.globl _dl_runtime_resolve
.type _dl_runtime_resolve, @function
_dl_runtime_resolve:
1996-02-19 21:54:38 +01:00
| Save %a0 (struct return address) and %a1.
move.l %a0, -(%sp)
1996-02-19 21:54:38 +01:00
move.l %a1, -(%sp)
| Call the real address resolver.
1996-02-19 21:54:38 +01:00
jbsr fixup
| Restore register %a0 and %a1.
move.l (%sp)+, %a1
move.l (%sp)+, %a0
| Pop parameters
addq.l #8, %sp
| Call real function.
jmp (%d0)
.size _dl_runtime_resolve, . - _dl_runtime_resolve
");
1996-02-19 21:54:38 +01:00
#define ELF_MACHINE_RUNTIME_FIXUP_ARGS long int save_a0, long int save_a1
/* The PLT uses Elf32_Rela relocs. */
#define elf_machine_relplt elf_machine_rela
}
/* Mask identifying addresses reserved for the user program,
where the dynamic linker should not map anything. */
#define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL
/* Initial entry point code for the dynamic linker.
The C function `_dl_start' is the real entry point;
its return value is the user program's entry point. */
#define RTLD_START asm ("\
.text
.globl _start
.globl _dl_start_user
_start:
jbsr _dl_start
_dl_start_user:
| Save the user entry point address in %a4.
move.l %d0, %a4
| Point %a5 at the GOT.
lea _GLOBAL_OFFSET_TABLE_@GOTPC(%pc), %a5
| See if we were run as a command with the executable file
| name as an extra leading argument.
move.l ([_dl_skip_args@GOT, %a5]), %d0
jeq 0f
| Pop the original argument count
move.l (%sp)+, %d1
| Subtract _dl_skip_args from it.
sub.l %d0, %d1
| Adjust the stack pointer to skip _dl_skip_args words.
lea (%sp, %d0*4), %sp
| Push back the modified argument count.
move.l %d1, -(%sp)
* Makerules ($(common-objpfx)libc.so): Depend on $(elfobjdir)/ld.so. * elf/dl-close.c: New file. * elf/link.h: Declare _dl_close. * elf/Makefile (routines): Add dl-close. * elf/dlclose.c (dlclose): Use _dl_close. * elf/Makefile ($(objpfx)librtld.so): Remove libelf from deps. * elf/dl-runtime.c (_dl_global_scope): New variable. (_dl_object_relocation_scope): New function. (fixup): Use it. * elf/rtld.c (dl_main): Use it. * elf/dl-open.c (_dl_open): Use it. If (MODE & RTLD_GLOBAL), set the l_global bit and append the new map to _dl_global_scope. * elf/link.h: Declare _dl_global_scope, _dl_global_scope_alloc, and _dl_object_relocation_scope. * elf/link.h (struct link_map): Add l_loader member. Remove _dl_map_object_from_fd decl. * elf/dl-load.c (_dl_map_object): Pass LOADER to ... (_dl_map_object_from_fd): Take new arg LOADER and set l_loader member. (_dl_map_object): Try DT_RPATH from all loaders up the chain. * elf/dl-object.c (_dl_loaded): Variable removed. (_dl_default_scope): New variable replaces it. * elf/link.h (_dl_loaded): Remove variable decl; instead define as macro for _dl_default_scope[2]. (_dl_default_scope): Declare it. * sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_default_scope[2] instead of _dl_loaded. * sysdeps/m68k/dl-machine.h (RTLD_START): Likewise. * elf/rtld.c (dl_main): Use _dl_default_scope for symbol lookups. * elf/dl-reloc.c (_dl_relocate_object): Remove check for _dl_rtld_map. * elf/rtld.c (dl_main): Pass 0 for LAZY flag when re-relocating self. * elf/link.h (struct link_map.l_type): Remove lt_interpreter. (struct link_map): Add new flag member l_global. * elf/dl-reloc.c (_dl_relocate_object): Check for _dl_rtld_map directly instead of looking for lt_interpreter. * sysdeps/i386/dl-machine.h (elf_machine_rel): Likewise. * elf/rtld.c (_dl_start): Don't bother setting BOOTSTRAP_MAP.l_type. (dl_main): Set _dl_rtld_map.l_type to lt_library. * elf/dl-deps.c (_dl_map_object_deps): Propagate MAP->l_type to dependencies loaded, downgrading lt_executable -> lt_library. * elf/dl-load.c (_dl_map_object_from_fd): Take new arg TYPE and set l_type from that, translating lt_library->lt_executable based on the file's ELF type. (_dl_map_object): Likewise. * elf/link.h: Update prototypes. * elf/dl-open.c: Pass type lt_loaded. * elf/rtld.c: Pass type lt_library. * elf/dl-load.c (_dl_map_object_from_fd): Handle null return from _dl_new_object. (_dl_map_object_from_fd: lose): Unchain and free L if it's not null. Free REALNAME, and just use NAME in error message. * elf/dl-object.c (_dl_new_object): If malloc fails, return null instead of calling _dl_signal_error. * elf/dl-load.c (_dl_map_object_from_fd): Close FD before signalling error for _dl_zerofd setup failure. * elf/dl-object.c (_dl_startup_loaded): Variable removed. * elf/link.h: Remove its decl. * elf/dl-reloc.c (_dl_relocate_object): Take new SCOPE arg and pass it through to _dl_lookup_symbol. * elf/link.h (_dl_relocate_object): Update comment and prototype. * elf/rtld.c (dl_main): Pass scope vector to _dl_relocate_object. * elf/dl-lookup.c (_dl_lookup_symbol): Arg SYMBOL_SCOPE is now a null-terminated vector of pointers, no longer a vector of exactly two. * elf/link.h (_dl_lookup_symbol): Update comment and prototype. * elf/dl-runtime.c (fixup): Set up scope for symbol lookup properly as done in _dl_relocate_object. * elf/dlopen.c: Pass "" to _dl_open when FILE is null.
1996-06-10 22:19:39 +02:00
0: | Push _dl_default_scope[2] as argument in _dl_init_next call below.
move.l ([_dl_default_scope@GOT, %a5]), %d2
0: move.l (%d2, 8), -(%sp)
| Call _dl_init_next to return the address of an initializer
| function to run.
bsr.l _dl_init_next@PLTPC
add.l #4, %sp | Pop argument.
| Check for zero return, when out of initializers.
tst.l %d0
jeq 1f
| Call the shared object initializer function.
| NOTE: We depend only on the registers (%d2, %a4 and %a5)
| and the return address pushed by this call;
| the initializer is called with the stack just
| as it appears on entry, and it is free to move
| the stack around, as long as it winds up jumping to
| the return address on the top of the stack.
move.l %d0, %a0
jsr (%a0)
| Loop to call _dl_init_next for the next initializer.
jra 0b
1: | Pass our finalizer function to the user in %a1.
move.l _dl_fini@GOT(%a5), %a1
| Initialize %fp with the stack pointer.
move.l %sp, %fp
| Jump to the user's entry point.
jmp (%a4)");