switch to netbsd csu
. file- and functionality-compatible with previous situation
(FreeBSD csu) (with a crt1.o -> crt0.o symlink in /usr/lib)
. harmonizes source with netbsd
. harmonizes linker invocation (e.g. clang) with netbsd
. helpful to get some arm code in there for the arm port project
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# $NetBSD: Makefile.inc,v 1.8 2009/09/12 07:22:16 skrll Exp $
|
||||
|
||||
SRCS+= rtld_start.S hppa_reloc.c
|
||||
|
||||
# XXX Should not be in CPPFLAGS!
|
||||
CPPFLAGS+= -fpic
|
||||
|
||||
CPPFLAGS+= -DELFSIZE=32
|
||||
#CPPFLAGS+= -DDEBUG
|
||||
#CPPFLAGS+= -DRTLD_DEBUG
|
||||
#CPPFLAGS+= -DRTLD_DEBUG_RELOC
|
||||
#CPPFLAGS+= -DRTLD_DEBUG_HPPA
|
||||
|
||||
LDFLAGS+= -Wl,-e,'$$rtld_start'
|
||||
@@ -0,0 +1,617 @@
|
||||
/* $NetBSD: hppa_reloc.c,v 1.34 2010/09/24 11:41:46 skrll Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002, 2004 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Matt Fredette and Nick Hudson.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: hppa_reloc.c,v 1.34 2010/09/24 11:41:46 skrll Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "rtld.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef RTLD_DEBUG_HPPA
|
||||
#define hdbg(x) xprintf x
|
||||
#else
|
||||
#define hdbg(x) /* nothing */
|
||||
#endif
|
||||
|
||||
caddr_t _rtld_bind(const Obj_Entry *, const Elf_Addr);
|
||||
void _rtld_bind_start(void);
|
||||
void __rtld_setup_hppa_pltgot(const Obj_Entry *, Elf_Addr *);
|
||||
|
||||
/*
|
||||
* It is possible for the compiler to emit relocations for unaligned data.
|
||||
* We handle this situation with these inlines.
|
||||
*/
|
||||
#define RELOC_ALIGNED_P(x) \
|
||||
(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
|
||||
|
||||
static inline Elf_Addr
|
||||
load_ptr(void *where)
|
||||
{
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
return *(Elf_Addr *)where;
|
||||
else {
|
||||
Elf_Addr res;
|
||||
|
||||
(void)memcpy(&res, where, sizeof(res));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
store_ptr(void *where, Elf_Addr val)
|
||||
{
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
*(Elf_Addr *)where = val;
|
||||
else
|
||||
(void)memcpy(where, &val, sizeof(val));
|
||||
}
|
||||
|
||||
/*
|
||||
* In the runtime architecture (ABI), PLABEL function pointers are
|
||||
* distinguished from normal function pointers by having the next-least-
|
||||
* significant bit set. (This bit is referred to as the L field in HP
|
||||
* documentation). The $$dyncall millicode is aware of this.
|
||||
*/
|
||||
#define RTLD_MAKE_PLABEL(plabel) (((Elf_Addr)(plabel)) | (1 << 1))
|
||||
#define RTLD_IS_PLABEL(addr) (((Elf_Addr)(addr)) & (1 << 1))
|
||||
#define RTLD_GET_PLABEL(addr) ((hppa_plabel *) (((Elf_Addr)addr) & ~3))
|
||||
|
||||
/*
|
||||
* This is the PLABEL structure. The function PC and
|
||||
* shared linkage members must come first, as they are
|
||||
* the actual PLABEL.
|
||||
*/
|
||||
typedef struct _hppa_plabel {
|
||||
Elf_Addr hppa_plabel_pc;
|
||||
Elf_Addr hppa_plabel_sl;
|
||||
SLIST_ENTRY(_hppa_plabel) hppa_plabel_next;
|
||||
} hppa_plabel;
|
||||
|
||||
/*
|
||||
* For now allocated PLABEL structures are tracked on a
|
||||
* singly linked list. This maybe should be revisited.
|
||||
*/
|
||||
static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list
|
||||
= SLIST_HEAD_INITIALIZER(hppa_plabel_list);
|
||||
|
||||
/*
|
||||
* Because I'm hesitant to use NEW while relocating self,
|
||||
* this is a small pool of preallocated PLABELs.
|
||||
*/
|
||||
#define HPPA_PLABEL_PRE (14)
|
||||
static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE];
|
||||
static int hppa_plabel_pre_next = 0;
|
||||
|
||||
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
|
||||
int _rtld_relocate_plt_objects(const Obj_Entry *);
|
||||
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
|
||||
const Elf_Rela *, Elf_Addr *);
|
||||
|
||||
/*
|
||||
* This bootstraps the dynamic linker by relocating its GOT.
|
||||
* On the hppa, unlike on other architectures, static strings
|
||||
* are found through the GOT. Static strings are essential
|
||||
* for RTLD_DEBUG, and I suspect they're used early even when
|
||||
* !defined(RTLD_DEBUG), making relocating the GOT essential.
|
||||
*
|
||||
* It gets worse. Relocating the GOT doesn't mean just walking
|
||||
* it and adding the relocbase to all of the entries. You must
|
||||
* find and use the GOT relocations, since those RELA relocations
|
||||
* have the necessary addends - the GOT comes initialized as
|
||||
* zeroes.
|
||||
*/
|
||||
void
|
||||
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
|
||||
{
|
||||
const Elf_Rela *relafirst, *rela, *relalim;
|
||||
Elf_Addr relasz;
|
||||
void *where;
|
||||
Elf_Addr *pltgot;
|
||||
const Elf_Rela *plabel_relocs[HPPA_PLABEL_PRE];
|
||||
int nplabel_relocs = 0;
|
||||
int i;
|
||||
const Elf_Sym *symtab, *sym;
|
||||
unsigned long symnum;
|
||||
hppa_plabel *plabel;
|
||||
|
||||
/*
|
||||
* Process the DYNAMIC section, looking for the non-PLT relocations.
|
||||
*/
|
||||
relafirst = NULL;
|
||||
relasz = 0;
|
||||
symtab = NULL;
|
||||
pltgot = NULL;
|
||||
for (; dynp->d_tag != DT_NULL; ++dynp) {
|
||||
switch (dynp->d_tag) {
|
||||
|
||||
case DT_RELA:
|
||||
relafirst = (const Elf_Rela *)
|
||||
(relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_RELASZ:
|
||||
relasz = dynp->d_un.d_val;
|
||||
break;
|
||||
|
||||
case DT_SYMTAB:
|
||||
symtab = (const Elf_Sym *)
|
||||
(relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_PLTGOT:
|
||||
pltgot = (Elf_Addr *)
|
||||
(relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
relalim = (const Elf_Rela *)((const char *)relafirst + relasz);
|
||||
|
||||
for (rela = relafirst; rela < relalim; rela++) {
|
||||
symnum = ELF_R_SYM(rela->r_info);
|
||||
where = (void *)(relocbase + rela->r_offset);
|
||||
|
||||
switch (ELF_R_TYPE(rela->r_info)) {
|
||||
case R_TYPE(DIR32):
|
||||
if (symnum == 0)
|
||||
store_ptr(where,
|
||||
relocbase + rela->r_addend);
|
||||
else {
|
||||
sym = symtab + symnum;
|
||||
store_ptr(where,
|
||||
relocbase + rela->r_addend + sym->st_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_TYPE(PLABEL32):
|
||||
/*
|
||||
* PLABEL32 relocation processing is done in two phases
|
||||
*
|
||||
* i) local function relocations (symbol number == 0)
|
||||
* can be resolved immediately.
|
||||
*
|
||||
* ii) external function relocations are deferred until
|
||||
* we finish all other relocations so that global
|
||||
* data isn't accessed until all other non-PLT
|
||||
* relocations have been done.
|
||||
*/
|
||||
if (symnum == 0)
|
||||
*((Elf_Addr *)where) =
|
||||
relocbase + rela->r_addend;
|
||||
else
|
||||
plabel_relocs[nplabel_relocs++] = rela;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(nplabel_relocs < HPPA_PLABEL_PRE);
|
||||
for (i = 0; i < nplabel_relocs; i++) {
|
||||
rela = plabel_relocs[i];
|
||||
where = (void *)(relocbase + rela->r_offset);
|
||||
sym = symtab + ELF_R_SYM(rela->r_info);
|
||||
|
||||
plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
|
||||
|
||||
plabel->hppa_plabel_pc = (Elf_Addr)
|
||||
(relocbase + sym->st_value + rela->r_addend);
|
||||
plabel->hppa_plabel_sl = (Elf_Addr)pltgot;
|
||||
|
||||
SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
|
||||
*((Elf_Addr *)where) = (Elf_Addr)(RTLD_MAKE_PLABEL(plabel));
|
||||
}
|
||||
|
||||
#if defined(RTLD_DEBUG_HPPA)
|
||||
for (rela = relafirst; rela < relalim; rela++) {
|
||||
where = (void *)(relocbase + rela->r_offset);
|
||||
|
||||
switch (ELF_R_TYPE(rela->r_info)) {
|
||||
case R_TYPE(DIR32):
|
||||
hdbg(("DIR32 rela @%p(%p) -> %p(%p)\n",
|
||||
(void *)rela->r_offset,
|
||||
(void *)where,
|
||||
(void *)rela->r_addend,
|
||||
(void *)*((Elf_Addr *)where) ));
|
||||
break;
|
||||
|
||||
case R_TYPE(PLABEL32):
|
||||
symnum = ELF_R_SYM(rela->r_info);
|
||||
if (symnum == 0) {
|
||||
hdbg(("PLABEL rela @%p(%p) -> %p(%p)\n",
|
||||
(void *)rela->r_offset,
|
||||
(void *)where,
|
||||
(void *)rela->r_addend,
|
||||
(void *)*((Elf_Addr *)where) ));
|
||||
} else {
|
||||
sym = symtab + symnum;
|
||||
|
||||
hdbg(("PLABEL32 rela @%p(%p), symnum=%ld(%p) -> %p(%p)\n",
|
||||
(void *)rela->r_offset,
|
||||
(void *)where,
|
||||
symnum,
|
||||
(void *)sym->st_value,
|
||||
(void *)rela->r_addend,
|
||||
(void *)*((Elf_Addr *)where) ));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hdbg(("rela XXX reloc\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* RTLD_DEBUG_HPPA */
|
||||
}
|
||||
|
||||
/*
|
||||
* This allocates a PLABEL. If called with a non-NULL def, the
|
||||
* plabel is for the function associated with that definition
|
||||
* in the defining object defobj, plus the given addend. If
|
||||
* called with a NULL def, the plabel is for the function at
|
||||
* the (unrelocated) address in addend in the object defobj.
|
||||
*/
|
||||
Elf_Addr
|
||||
_rtld_function_descriptor_alloc(const Obj_Entry *defobj, const Elf_Sym *def,
|
||||
Elf_Addr addend)
|
||||
{
|
||||
Elf_Addr func_pc, func_sl;
|
||||
hppa_plabel *plabel;
|
||||
|
||||
if (def != NULL) {
|
||||
|
||||
/*
|
||||
* We assume that symbols of type STT_NOTYPE
|
||||
* are undefined. Return NULL for these.
|
||||
*/
|
||||
if (ELF_ST_TYPE(def->st_info) == STT_NOTYPE)
|
||||
return (Elf_Addr)NULL;
|
||||
|
||||
/* Otherwise assert that this symbol must be a function. */
|
||||
assert(ELF_ST_TYPE(def->st_info) == STT_FUNC);
|
||||
|
||||
func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
|
||||
addend);
|
||||
} else
|
||||
func_pc = (Elf_Addr)(defobj->relocbase + addend);
|
||||
|
||||
/*
|
||||
* Search the existing PLABELs for one matching
|
||||
* this function. If there is one, return it.
|
||||
*/
|
||||
func_sl = (Elf_Addr)(defobj->pltgot);
|
||||
SLIST_FOREACH(plabel, &hppa_plabel_list, hppa_plabel_next)
|
||||
if (plabel->hppa_plabel_pc == func_pc &&
|
||||
plabel->hppa_plabel_sl == func_sl)
|
||||
return RTLD_MAKE_PLABEL(plabel);
|
||||
|
||||
/*
|
||||
* Once we've used up the preallocated set, we start
|
||||
* using NEW to allocate plabels.
|
||||
*/
|
||||
if (hppa_plabel_pre_next < HPPA_PLABEL_PRE)
|
||||
plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
|
||||
else {
|
||||
plabel = NEW(hppa_plabel);
|
||||
if (plabel == NULL)
|
||||
return (Elf_Addr)-1;
|
||||
}
|
||||
|
||||
/* Fill the new entry and insert it on the list. */
|
||||
plabel->hppa_plabel_pc = func_pc;
|
||||
plabel->hppa_plabel_sl = func_sl;
|
||||
SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
|
||||
|
||||
return RTLD_MAKE_PLABEL(plabel);
|
||||
}
|
||||
|
||||
/*
|
||||
* If a pointer is a PLABEL, this unwraps it.
|
||||
*/
|
||||
const void *
|
||||
_rtld_function_descriptor_function(const void *addr)
|
||||
{
|
||||
return (RTLD_IS_PLABEL(addr) ?
|
||||
(const void *) RTLD_GET_PLABEL(addr)->hppa_plabel_pc :
|
||||
addr);
|
||||
}
|
||||
|
||||
/* This sets up an object's GOT. */
|
||||
void
|
||||
_rtld_setup_pltgot(const Obj_Entry *obj)
|
||||
{
|
||||
__rtld_setup_hppa_pltgot(obj, obj->pltgot);
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
{
|
||||
const Elf_Rela *rela;
|
||||
|
||||
for (rela = obj->rela; rela < obj->relalim; rela++) {
|
||||
Elf_Addr *where;
|
||||
const Elf_Sym *def;
|
||||
const Obj_Entry *defobj;
|
||||
Elf_Addr tmp;
|
||||
unsigned long symnum;
|
||||
|
||||
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
|
||||
symnum = ELF_R_SYM(rela->r_info);
|
||||
|
||||
switch (ELF_R_TYPE(rela->r_info)) {
|
||||
case R_TYPE(NONE):
|
||||
break;
|
||||
|
||||
case R_TYPE(DIR32):
|
||||
if (symnum) {
|
||||
/*
|
||||
* This is either a DIR32 against a symbol
|
||||
* (def->st_name != 0), or against a local
|
||||
* section (def->st_name == 0).
|
||||
*/
|
||||
def = obj->symtab + symnum;
|
||||
defobj = obj;
|
||||
if (def->st_name != 0)
|
||||
def = _rtld_find_symdef(symnum, obj,
|
||||
&defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
tmp = (Elf_Addr)(defobj->relocbase +
|
||||
def->st_value + rela->r_addend);
|
||||
|
||||
if (load_ptr(where) != tmp)
|
||||
store_ptr(where, tmp);
|
||||
rdbg(("DIR32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)load_ptr(where),
|
||||
defobj->path));
|
||||
} else {
|
||||
tmp = (Elf_Addr)(obj->relocbase +
|
||||
rela->r_addend);
|
||||
|
||||
if (load_ptr(where) != tmp)
|
||||
store_ptr(where, tmp);
|
||||
rdbg(("DIR32 in %s --> %p", obj->path,
|
||||
(void *)load_ptr(where)));
|
||||
}
|
||||
break;
|
||||
|
||||
case R_TYPE(PLABEL32):
|
||||
if (symnum) {
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj,
|
||||
false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
tmp = _rtld_function_descriptor_alloc(defobj,
|
||||
def, rela->r_addend);
|
||||
if (tmp == (Elf_Addr)-1)
|
||||
return -1;
|
||||
|
||||
if (*where != tmp)
|
||||
*where = tmp;
|
||||
rdbg(("PLABEL32 %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
} else {
|
||||
/*
|
||||
* This is a PLABEL for a static function, and
|
||||
* the dynamic linker has both allocated a PLT
|
||||
* entry for this function and told us where it
|
||||
* is. We can safely use the PLT entry as the
|
||||
* PLABEL because there should be no other
|
||||
* PLABEL reloc referencing this function.
|
||||
* This object should also have an IPLT
|
||||
* relocation to initialize the PLT entry.
|
||||
*
|
||||
* The dynamic linker should also have ensured
|
||||
* that the addend has the
|
||||
* next-least-significant bit set; the
|
||||
* $$dyncall millicode uses this to distinguish
|
||||
* a PLABEL pointer from a plain function
|
||||
* pointer.
|
||||
*/
|
||||
tmp = (Elf_Addr)
|
||||
(obj->relocbase + rela->r_addend);
|
||||
|
||||
if (*where != tmp)
|
||||
*where = tmp;
|
||||
rdbg(("PLABEL32 in %s --> %p", obj->path,
|
||||
(void *)*where));
|
||||
}
|
||||
break;
|
||||
|
||||
case R_TYPE(COPY):
|
||||
/*
|
||||
* These are deferred until all other relocations have
|
||||
* been done. All we do here is make sure that the
|
||||
* COPY relocation is not in a shared library. They
|
||||
* are allowed only in executable files.
|
||||
*/
|
||||
if (obj->isdynamic) {
|
||||
_rtld_error(
|
||||
"%s: Unexpected R_COPY relocation in shared library",
|
||||
obj->path);
|
||||
return -1;
|
||||
}
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"addend = %p, contents = %p, symbol = %s",
|
||||
symnum, (u_long)ELF_R_TYPE(rela->r_info),
|
||||
(void *)rela->r_offset, (void *)rela->r_addend,
|
||||
(void *)load_ptr(where),
|
||||
obj->strtab + obj->symtab[symnum].st_name));
|
||||
_rtld_error("%s: Unsupported relocation type %ld "
|
||||
"in non-PLT relocations",
|
||||
obj->path, (u_long) ELF_R_TYPE(rela->r_info));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
|
||||
{
|
||||
const Elf_Rela *rela;
|
||||
|
||||
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
|
||||
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
|
||||
Elf_Addr func_pc, func_sl;
|
||||
|
||||
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT));
|
||||
|
||||
/*
|
||||
* If this is an IPLT reloc for a static function,
|
||||
* fully resolve the PLT entry now.
|
||||
*/
|
||||
if (ELF_R_SYM(rela->r_info) == 0) {
|
||||
func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
|
||||
func_sl = (Elf_Addr)(obj->pltgot);
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise set up for lazy binding.
|
||||
*/
|
||||
else {
|
||||
/*
|
||||
* This function pointer points to the PLT
|
||||
* stub added by the linker, and instead of
|
||||
* a shared linkage value, we stash this
|
||||
* relocation's offset. The PLT stub has
|
||||
* already been set up to transfer to
|
||||
* _rtld_bind_start.
|
||||
*/
|
||||
func_pc = ((Elf_Addr)(obj->pltgot)) - 16;
|
||||
func_sl = (Elf_Addr)
|
||||
((const char *)rela - (const char *)(obj->pltrela));
|
||||
}
|
||||
rdbg(("lazy bind %s(%p) --> old=(%p,%p) new=(%p,%p)",
|
||||
obj->path,
|
||||
(void *)where,
|
||||
(void *)where[0], (void *)where[1],
|
||||
(void *)func_pc, (void *)func_sl));
|
||||
|
||||
/*
|
||||
* Fill this PLT entry and return.
|
||||
*/
|
||||
where[0] = func_pc;
|
||||
where[1] = func_sl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
|
||||
Elf_Addr *tp)
|
||||
{
|
||||
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
|
||||
const Elf_Sym *def;
|
||||
const Obj_Entry *defobj;
|
||||
Elf_Addr func_pc, func_sl;
|
||||
unsigned long info = rela->r_info;
|
||||
|
||||
assert(ELF_R_TYPE(info) == R_TYPE(IPLT));
|
||||
|
||||
if (ELF_R_SYM(info) == 0) {
|
||||
func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
|
||||
func_sl = (Elf_Addr)(obj->pltgot);
|
||||
} else {
|
||||
def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj,
|
||||
tp != NULL);
|
||||
if (__predict_false(def == NULL))
|
||||
return -1;
|
||||
if (__predict_false(def == &_rtld_sym_zero))
|
||||
return 0;
|
||||
|
||||
func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
|
||||
rela->r_addend);
|
||||
func_sl = (Elf_Addr)(defobj->pltgot);
|
||||
|
||||
rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)",
|
||||
defobj->strtab + def->st_name,
|
||||
(void *)where[0], (void *)where[1],
|
||||
(void *)func_pc, (void *)func_sl));
|
||||
}
|
||||
/*
|
||||
* Fill this PLT entry and return.
|
||||
*/
|
||||
if (where[0] != func_pc)
|
||||
where[0] = func_pc;
|
||||
if (where[1] != func_sl)
|
||||
where[1] = func_sl;
|
||||
|
||||
if (tp)
|
||||
*tp = (Elf_Addr)where;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
caddr_t
|
||||
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
{
|
||||
const Elf_Rela *rela;
|
||||
Elf_Addr new_value = 0; /* XXX gcc */
|
||||
int err;
|
||||
|
||||
rela = (const Elf_Rela *)((const char *)obj->pltrela + reloff);
|
||||
|
||||
assert(ELF_R_SYM(rela->r_info) != 0);
|
||||
|
||||
err = _rtld_relocate_plt_object(obj, rela, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_relocate_plt_objects(const Obj_Entry *obj)
|
||||
{
|
||||
const Elf_Rela *rela = obj->pltrela;
|
||||
|
||||
for (; rela < obj->pltrelalim; rela++) {
|
||||
if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/* $NetBSD: rtld_start.S,v 1.9 2010/09/30 19:32:40 skrll Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Matt Fredette.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <machine/asm.h>
|
||||
#include <machine/frame.h>
|
||||
|
||||
.import _GLOBAL_OFFSET_TABLE_
|
||||
|
||||
ENTRY($rtld_start,HPPA_FRAME_SIZE)
|
||||
|
||||
/* Start stack calling convention. */
|
||||
copy %r3, %r1
|
||||
copy %sp, %r3
|
||||
stw,ma %r1, HPPA_FRAME_SIZE(%sp)
|
||||
|
||||
/*
|
||||
* Save our single argument, the ps_strings pointer. We'll need this
|
||||
* twice later: once to call _rtld, and again to transfer to the
|
||||
* program's entry point.
|
||||
*/
|
||||
stw %arg0, HPPA_FRAME_ARG(0)(%r3)
|
||||
|
||||
/*
|
||||
* We can't move to C until we relocate at least the
|
||||
* Global Offset Table. Even finding the GOT is tricky
|
||||
* without inadvertently causing the linker to make
|
||||
* relocations for this part of the text segment.
|
||||
*/
|
||||
|
||||
bl L$lpc1, %r19
|
||||
depi 0, 31, 2, %r19
|
||||
L$lpc1: addil L'_DYNAMIC - ($PIC_pcrel$0 - 8), %r19
|
||||
ldo R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%r1),%arg0
|
||||
|
||||
/*
|
||||
* Load the absolute address of the beginning of the GOT into %r19, the
|
||||
* shared library linkage table register, leaving it ready-to-use by
|
||||
* the dynamic linker C code.
|
||||
*/
|
||||
addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16), %r19
|
||||
ldo R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%r1),%r19
|
||||
|
||||
/*
|
||||
* The linker sets the first entry in the GOT to the unrelocated
|
||||
* address of _DYNAMIC. Subtract this from the absolute address of
|
||||
* _DYNAMIC to get our relocbase.
|
||||
*/
|
||||
ldw 0(%r19), %arg1
|
||||
sub %arg0, %arg1, %arg1 ; %arg1 = relocbase
|
||||
bl _rtld_relocate_nonplt_self, %rp
|
||||
copy %arg1, %r4 ; save for later
|
||||
|
||||
/*
|
||||
* Recover the ps_strings pointer, and take out the
|
||||
* ps_argvstr member.
|
||||
*/
|
||||
ldw HPPA_FRAME_ARG(0)(%r3), %arg0 ; ps_strings
|
||||
ldw 0(%arg0), %arg0 ; ps_argvstr member first in struct
|
||||
|
||||
/*
|
||||
* ps_argvstr - 4 would get us a pointer to argc, comparable to the
|
||||
* initial stack pointer on architectures where the stack grows down.
|
||||
* Subtracting an additional eight creates the storage for obj and
|
||||
* cleanup that _rtld needs.
|
||||
*/
|
||||
ldo -12(%arg0), %arg0
|
||||
stw %arg0, HPPA_FRAME_ARG(1)(%r3)
|
||||
|
||||
/* Call _rtld, copying relocbase into arg1. */
|
||||
bl _rtld, %rp
|
||||
copy %r4, %arg1 ; %arg1 = relocbase
|
||||
|
||||
/* Prepare the arguments for the entry point. */
|
||||
ldw HPPA_FRAME_ARG(1)(%r3), %r1
|
||||
ldw HPPA_FRAME_ARG(0)(%r3), %arg0 ; ps_strings
|
||||
ldw 0(%r1), %arg1 ; cleanup
|
||||
ldw 4(%r1), %arg2 ; obj
|
||||
|
||||
/* End stack calling convention. */
|
||||
ldo HPPA_FRAME_SIZE(%r3), %sp
|
||||
ldw,mb -HPPA_FRAME_SIZE(%sp), %r3
|
||||
|
||||
/* Go for it. */
|
||||
bv %r0(%ret0)
|
||||
copy %r0, %rp
|
||||
EXIT($rtld_start)
|
||||
|
||||
/*
|
||||
* This does our setup for an object's GOT. %arg0 is the Obj_Entry * for the
|
||||
* object, and %arg1 is its GOT pointer.
|
||||
*/
|
||||
LEAF_ENTRY(__rtld_setup_hppa_pltgot)
|
||||
|
||||
/*
|
||||
* The second entry of the GOT is reserved for the dynamic linker. We
|
||||
* put the Obj_Entry * for the object in there.
|
||||
*/
|
||||
stw %arg0, 4(%arg1)
|
||||
|
||||
/*
|
||||
* Fill the fixup_func and fixup_ltp members of the PLT stub. This
|
||||
* stub is inserted by the linker immediately before the GOT. We use
|
||||
* this stub to enter our binder.
|
||||
*/
|
||||
|
||||
bl L$lpc2, %arg0
|
||||
depi 0, 31, 2, %arg0
|
||||
L$lpc2: addil L'_rtld_bind_start - ($PIC_pcrel$0 - 8), %arg0
|
||||
ldo R'_rtld_bind_start - ($PIC_pcrel$0 - 12)(%r1),%arg0
|
||||
|
||||
stw %arg0, -8(%arg1)
|
||||
bv %r0(%rp)
|
||||
stw %r19, -4(%arg1)
|
||||
EXIT(__rtld_hppa_setup_pltgot)
|
||||
|
||||
/*
|
||||
* In order to support lazy binding, this implementation of _rtld_bind_start is
|
||||
* very closely tied to the shared-library call stub and the PLT stub, both
|
||||
* inserted by the linker.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a magic branch instruction that is used by GCC's
|
||||
* __canonicalize_funcptr_for_compare() function to fixup relocations
|
||||
* in order to do function pointer comparisons.
|
||||
*/
|
||||
|
||||
bl _rtld_bind, %rp
|
||||
|
||||
ENTRY(_rtld_bind_start,HPPA_FRAME_SIZE)
|
||||
|
||||
/* Start stack calling convention. */
|
||||
copy %r3, %r1
|
||||
copy %sp, %r3
|
||||
|
||||
stw,ma %r1, HPPA_FRAME_SIZE(%sp)
|
||||
|
||||
/*
|
||||
* We have to save all calling convention registers that are set by the
|
||||
* caller, because we have to restore them before transferring to the
|
||||
* bound function. Note that this includes %ret0, %ret1, and %t1.
|
||||
*
|
||||
* %ret0 and %ret1 because they can have meaning on entry to a
|
||||
* function.
|
||||
*
|
||||
* %t1 because it's used by libc to pass on errno values to cerror.
|
||||
*/
|
||||
stw %rp, HPPA_FRAME_CRP(%r3)
|
||||
stw %arg0, HPPA_FRAME_ARG(0)(%r3)
|
||||
stw %arg1, HPPA_FRAME_ARG(1)(%r3)
|
||||
stw %arg2, HPPA_FRAME_ARG(2)(%r3)
|
||||
stw %arg3, HPPA_FRAME_ARG(3)(%r3)
|
||||
/* 0(%r3) is filled with the saved %r3 above */
|
||||
stw %ret0, 4(%r3)
|
||||
stw %ret1, 8(%r3)
|
||||
|
||||
/*
|
||||
* The linker PLT stub loads %r20 with (GOT - 8) for the object that
|
||||
* needs binding done. The second entry of the GOT is reserved for the
|
||||
* dynamic linker's use, and we previously stashed the object's
|
||||
* Obj_Entry * there.
|
||||
*/
|
||||
ldw 12(%r20), %arg0
|
||||
|
||||
/*
|
||||
* The linker shared-library call stub loads %r19 from the shared
|
||||
* linkage member of the PLT entry. We previously stashed the reloff
|
||||
* of the relocation there.
|
||||
*/
|
||||
copy %r19, %arg1
|
||||
|
||||
/*
|
||||
* The linker PLT stub loads %r21 with the fixup_ltp word in itself.
|
||||
* We previously stashed our %r19 value there.
|
||||
*/
|
||||
bl _rtld_bind, %rp
|
||||
copy %r21, %r19
|
||||
|
||||
/*
|
||||
* Our hppa version of _rtld_bind returns to us the address of the PLT
|
||||
* entry that it fixed up. Load the function address and shared
|
||||
* linkage for the newly bound function.
|
||||
*/
|
||||
ldw 0(%ret0), %r21
|
||||
ldw 4(%ret0), %r19
|
||||
|
||||
/* Restore registers saved above. */
|
||||
ldw HPPA_FRAME_CRP(%r3), %rp
|
||||
ldw HPPA_FRAME_ARG(0)(%r3), %arg0
|
||||
ldw HPPA_FRAME_ARG(1)(%r3), %arg1
|
||||
ldw HPPA_FRAME_ARG(2)(%r3), %arg2
|
||||
ldw HPPA_FRAME_ARG(3)(%r3), %arg3
|
||||
ldw 4(%r3), %ret0
|
||||
ldw 8(%r3), %ret1
|
||||
|
||||
/* End stack calling convention. */
|
||||
ldo HPPA_FRAME_SIZE(%r3), %sp
|
||||
ldw,mb -HPPA_FRAME_SIZE(%sp), %r3
|
||||
|
||||
/* Transfer to the function. */
|
||||
bv %r0(%r21)
|
||||
nop
|
||||
EXIT(_rtld_bind_start)
|
||||
Reference in New Issue
Block a user