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:
Ben Gras
2012-03-31 00:35:32 +02:00
parent b02992f0c1
commit e83f7ba2c9
146 changed files with 17245 additions and 215 deletions

133
libexec/ld.elf_so/Makefile Normal file
View File

@@ -0,0 +1,133 @@
# $NetBSD: Makefile,v 1.102 2011/01/16 02:36:05 matt Exp $
#
# NOTE: when changing ld.so, ensure that ldd still compiles.
#
WARNS?=4
# This needs to be before bsd.init.mk
.if defined(BSD_MK_COMPAT_FILE)
.include <${BSD_MK_COMPAT_FILE}>
.endif
# We are not building this with PIE
PIE_CFLAGS=
PIE_LDFLAGS=
.include <bsd.init.mk> # for MKPIC definition
.include <bsd.shlib.mk> # for SHLINKINSTALLDIR definition
.if defined(LDELFSO_MACHINE_CPU) && !empty(LDELFSO_MACHINE_CPU) && \
exists(${.CURDIR}/arch/${LDELFSO_MACHINE_CPU})
ARCHSUBDIR= ${LDELFSO_MACHINE_CPU}
.else
ARCHSUBDIR= ${MACHINE_CPU}
.endif
M= ${.CURDIR}/arch/${ARCHSUBDIR}
.if ((${MACHINE_ARCH} == "alpha") || \
(${MACHINE_CPU} == "arm") || \
(${MACHINE_ARCH} == "hppa") || \
(${MACHINE_ARCH} == "i386") || \
(${MACHINE_ARCH} == "m68k") || \
(${MACHINE_CPU} == "mips") || \
(${MACHINE_ARCH} == "powerpc") || \
(${MACHINE_CPU} == "sh3") || \
(${MACHINE_ARCH} == "sparc") || \
(${MACHINE_ARCH} == "sparc64") || \
(${MACHINE_ARCH} == "x86_64") || \
(${MACHINE_ARCH} == "vax")) && \
${MKPIC} != "no"
LDFLAGS+= -shared -symbolic -nostartfiles
LDFLAGS+= -Wl,-static
LDFLAGS+= -Wl,--warn-shared-textrel
CFLAGS+= -fvisibility=hidden
# Adds SRCS, CPPFLAGS, LDFLAGS, etc. Must go first so MD startup source
# is first.
.if exists($M/Makefile.inc)
.include "$M/Makefile.inc"
.endif
# Support compat ld.elf_so.
.if defined(MLIBDIR)
PROG= ld.elf_so-${MLIBDIR}
CPPFLAGS+= -DRTLD_ARCH_SUBDIR=\"${MLIBDIR}\"
.else
PROG= ld.elf_so
.endif
CLIBOBJ!= cd ${NETBSDSRCDIR}/lib/libc && ${PRINTOBJDIR}
SRCS+= rtld.c reloc.c symbol.c xmalloc.c xprintf.c debug.c \
map_object.c load.c search.c headers.c paths.c expand.c
.if ${USE_FORT} == "yes"
.PATH.c: ${NETBSDSRCDIR}/lib/libc/misc
SRCS+= stack_protector.c
.endif
.PATH.c: ${NETBSDSRCDIR}/lib/libc/stdlib
SRCS+= exit.c
errlist_concat.h: ${NETBSDSRCDIR}/lib/libc/gen/errlist.awk ${NETBSDSRCDIR}/sys/sys/errno.h
${TOOL_AWK} -v concat=1 -f ${.ALLSRC} > ${.TARGET}.tmp && \
mv -f ${.TARGET}.tmp ${.TARGET}
xprintf.c: errlist_concat.h
CLEANFILES+= errlist_concat.h
BINDIR= ${SHLINKINSTALLDIR}
CPPFLAGS+= -DLIBDIR=\"${LIBDIR}\" -D_PATH_RTLD=\"${BINDIR}/${PROG}\"
CPPFLAGS+= -I${.CURDIR} -I.
CPPFLAGS+= -DRTLD_LOADER
CPPFLAGS+= -D_RTLD_SOURCE
CPPFLAGS+= -DCOMBRELOC
#CPPFLAGS+= -DDEBUG
#CPPFLAGS+= -DRTLD_DEBUG
#CPPFLAGS+= -DRTLD_DEBUG_RELOC
#DBG= -g
DBG= -O3 -fomit-frame-pointer
.if ${SHLIBDIR} != ${LIBDIR}
CPPFLAGS+= -DRTLD_DEFAULT_LIBRARY_PATH=\"${SHLIBDIR}:${LIBDIR}\"
.endif
# rtld.c and symbol.c use alloca, so disable SSP warnings.
COPTS.rtld.c+= -Wno-stack-protector
COPTS.symbol.c+=-Wno-stack-protector
LDADD+= -L${CLIBOBJ} -L${DESTDIR}${LIBDIR}
.if ${MKPICLIB} != "no"
LDADD+= -lc_pic
.if ${MKPICINSTALL} != "no"
DPADD+= ${LIBC_PIC}
.endif
DPADD+= ${CLIBOBJ}/libc_pic.a
.else
LDADD+= -lc
DPADD+= ${CLIBOBJ}/libc.a
.endif
STRIPFLAG=
.PATH: $M
${PROG}: ${OBJS} ${DPADD}
${_MKMSG_LINK} ${PROG}
${CC} ${LDFLAGS} -o ${PROG} ${OBJS} ${LDADD}
.if ${SHLINKINSTALLDIR} != "/usr/libexec"
SYMLINKS+= ${SHLINKINSTALLDIR}/${PROG} /usr/libexec/${PROG}
.endif
.include <bsd.prog.mk>
.else
MAN= ld.elf_so.1
.include <bsd.man.mk>
.endif

6
libexec/ld.elf_so/README Normal file
View File

@@ -0,0 +1,6 @@
$NetBSD: README,v 1.11 2006/11/24 22:52:16 wiz Exp $
TO DO:
* Support for coexistence of 32-bit and 64-bit ELF on platforms that can
do that.

33
libexec/ld.elf_so/TODO Normal file
View File

@@ -0,0 +1,33 @@
rtld:
* resolve MIPS binding lossage
binutils/gcc:
* alpha: why are there GLOB_DAT relocs in ld.elf_so?
* alpha: bogus textrels in rtti info
* mips: why are there global GOT relocs in ld.elf_so?
* mips: bogus textrels in .rel.dyn
* powerpc: make sure the .got section is always executable
* powerpc: fix ld scripts so that .rodata is still used for PIC
machine-specific:
* #ifdefs:
headers.c:#ifndef __mips__
headers.c:#ifdef __mips__
reloc.c:#if defined(__hppa__)
rtld.c:#if !defined(__hppa__)
rtld.c:#if !defined(__mips__) && !defined(__hppa__)
rtld.c:#if !defined(__arm__) && !defined(__mips__) && !defined(__sh__)
rtld.c:#ifdef __mips__
rtld.h:#ifdef __mips__
symbol.c:#ifndef __mips__
issues to research:
* sh, x86_64 have different absolute and GLOB_DAT relocs; nothing else does
* sh, vax, x86_64 use addend on PLT; nothing else does
rela: alpha hppa m68k powerpc sh sparc sparc64 vax x86_64
rel: arm i386 mips
- mycroft
2003/09/24

View File

@@ -0,0 +1,11 @@
# $NetBSD: Makefile.inc,v 1.12 2005/06/04 16:17:17 lukem Exp $
SRCS+= rtld_start.S alpha_reloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic -mno-fp-regs
CPPFLAGS+= -DELFSIZE=64
#CPPFLAGS+= -DRTLD_DEBUG_ALPHA
LDFLAGS+= -Wl,-e,_rtld_start

View File

@@ -0,0 +1,503 @@
/* $NetBSD: alpha_reloc.c,v 1.38 2010/09/30 09:11:18 skrll Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
* 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.
*/
/*
* Copyright 1996, 1997, 1998, 1999 John D. Polstra.
* All rights reserved.
*
* 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 AUTHOR ``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 AUTHOR 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: alpha_reloc.c,v 1.38 2010/09/30 09:11:18 skrll Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <string.h>
#include "rtld.h"
#include "debug.h"
#ifdef RTLD_DEBUG_ALPHA
#define adbg(x) xprintf x
#else
#define adbg(x) /* nothing */
#endif
void _rtld_bind_start(void);
void _rtld_bind_start_old(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Addr);
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, Elf_Addr *);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
uint32_t word0;
/*
* The PLTGOT on the Alpha looks like this:
*
* PLT HEADER
* .
* . 32 bytes
* .
* PLT ENTRY #0
* .
* . 12 bytes
* .
* PLT ENTRY #1
* .
* . 12 bytes
* .
* etc.
*
* The old-format entries look like (displacements filled in
* by the linker):
*
* ldah $28, 0($31) # 0x279f0000
* lda $28, 0($28) # 0x239c0000
* br $31, plt0 # 0xc3e00000
*
* The new-format entries look like:
*
* br $28, plt0 # 0xc3800000
* # 0x00000000
* # 0x00000000
*
* What we do is fetch the first PLT entry and check to
* see the first word of it matches the first word of the
* old format. If so, we use a binding routine that can
* handle the old format, otherwise we use a binding routine
* that handles the new format.
*
* Note that this is done on a per-object basis, we can mix
* and match shared objects build with both the old and new
* linker.
*/
word0 = *(uint32_t *)(((char *) obj->pltgot) + 32);
if ((word0 & 0xffff0000) == 0x279f0000) {
/* Old PLT entry format. */
adbg(("ALPHA: object %p has old PLT format\n", obj));
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start_old;
obj->pltgot[3] = (Elf_Addr) obj;
} else {
/* New PLT entry format. */
adbg(("ALPHA: object %p has new PLT format\n", obj));
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
obj->pltgot[3] = (Elf_Addr) obj;
}
__asm volatile("imb");
}
/*
* 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)
{
Elf_Addr res;
memcpy(&res, where, sizeof(res));
return (res);
}
static inline void
store_ptr(void *where, Elf_Addr val)
{
memcpy(where, &val, sizeof(val));
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
/* XXX For some reason I see a few GLOB_DAT relocs here. */
*where += (Elf_Addr)relocbase;
}
}
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
const Elf_Rela *rela;
Elf_Addr target = -1;
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(REFQUAD):
case R_TYPE(GLOB_DAT):
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
target = (Elf_Addr)(defobj->relocbase +
def->st_value);
tmp = target + rela->r_addend;
if (__predict_true(RELOC_ALIGNED_P(where))) {
if (*where != tmp)
*where = tmp;
} else {
if (load_ptr(where) != tmp)
store_ptr(where, tmp);
}
rdbg(("REFQUAD/GLOB_DAT %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)tmp, defobj->path));
break;
case R_TYPE(RELATIVE):
if (__predict_true(RELOC_ALIGNED_P(where)))
*where += (Elf_Addr)obj->relocbase;
else
store_ptr(where,
load_ptr(where) + (Elf_Addr)obj->relocbase);
rdbg(("RELATIVE 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;
if (!obj->relocbase)
return 0;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
/* Just relocate the GOT slots pointing into the PLT */
*where += (Elf_Addr)obj->relocbase;
rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
}
return 0;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
Elf_Addr *tp)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
Elf_Addr new_value;
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf_Addr stubaddr;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
rdbg(("bind now/fixup in %s --> old=%p new=%p",
defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
if ((stubaddr = *where) != new_value) {
int64_t delta, idisp;
uint32_t insn[3], *stubptr;
int insncnt;
Elf_Addr pc;
/* Point this GOT entry at the target. */
*where = new_value;
/*
* Alpha shared objects may have multiple GOTs, each
* of which may point to this entry in the PLT. But,
* we only have a reference to the first GOT entry which
* points to this PLT entry. In order to avoid having to
* re-bind this call every time a non-first GOT entry is
* used, we will attempt to patch up the PLT entry to
* reference the target, rather than the binder.
*
* When the PLT stub gets control, PV contains the address
* of the PLT entry. Each PLT entry has room for 3 insns.
* If the displacement of the target from PV fits in a signed
* 32-bit integer, we can simply add it to PV. Otherwise,
* we must load the GOT entry itself into PV.
*
* Note if the shared object uses the old PLT format, then
* we cannot patch up the PLT safely, and so we skip it
* in that case[*].
*
* [*] Actually, if we're not doing lazy-binding, then
* we *can* (and do) patch up this PLT entry; the PLTGOT
* thunk won't yet point to any binder entry point, and
* so this test will fail as it would for the new PLT
* entry format.
*/
if (obj->pltgot[2] == (Elf_Addr) &_rtld_bind_start_old) {
rdbg((" old PLT format"));
goto out;
}
delta = new_value - stubaddr;
rdbg((" stubaddr=%p, where-stubaddr=%ld, delta=%ld",
(void *)stubaddr, (long)where - (long)stubaddr,
(long)delta));
insncnt = 0;
if ((int32_t)delta == delta) {
/*
* We can adjust PV with an LDA, LDAH sequence.
*
* First, build an LDA insn to adjust the low 16
* bits.
*/
insn[insncnt++] = 0x08 << 26 | 27 << 21 | 27 << 16 |
(delta & 0xffff);
rdbg((" LDA $27,%d($27)", (int16_t)delta));
/*
* Adjust the delta to account for the effects of
* the LDA, including sign-extension.
*/
delta -= (int16_t)delta;
if (delta != 0) {
/*
* Build an LDAH instruction to adjust the
* high 16 bits.
*/
insn[insncnt++] = 0x09 << 26 | 27 << 21 |
27 << 16 | ((delta >> 16) & 0xffff);
rdbg((" LDAH $27,%d($27)",
(int16_t)(delta >> 16)));
}
} else {
int64_t dhigh;
/* We must load the GOT entry. */
delta = (Elf_Addr)where - stubaddr;
/*
* If the GOT entry is too far away from the PLT
* entry, then we can't patch up the PLT entry.
* This PLT entry will have to be bound for each
* GOT entry except for the first one. This program
* will still run, albeit very slowly. It is very
* unlikely that this case will ever happen in
* practice.
*/
if ((int32_t)delta != delta) {
rdbg((" PLT stub too far from GOT to relocate"));
goto out;
}
dhigh = delta - (int16_t)delta;
if (dhigh != 0) {
/*
* Build an LDAH instruction to adjust the
* high 16 bits.
*/
insn[insncnt++] = 0x09 << 26 | 27 << 21 |
27 << 16 | ((dhigh >> 16) & 0xffff);
rdbg((" LDAH $27,%d($27)",
(int16_t)(dhigh >> 16)));
}
/* Build an LDQ to load the GOT entry. */
insn[insncnt++] = 0x29 << 26 | 27 << 21 |
27 << 16 | (delta & 0xffff);
rdbg((" LDQ $27,%d($27)",
(int16_t)delta));
}
/*
* Now, build a JMP or BR insn to jump to the target. If
* the displacement fits in a sign-extended 21-bit field,
* we can use the more efficient BR insn. Otherwise, we
* have to jump indirect through PV.
*/
pc = stubaddr + (4 * (insncnt + 1));
idisp = (int64_t)(new_value - pc) >> 2;
if (-0x100000 <= idisp && idisp < 0x100000) {
insn[insncnt++] = 0x30 << 26 | 31 << 21 |
(idisp & 0x1fffff);
rdbg((" BR $31,%p", (void *)new_value));
} else {
insn[insncnt++] = 0x1a << 26 | 31 << 21 |
27 << 16 | (idisp & 0x3fff);
rdbg((" JMP $31,($27),%d",
(int)(idisp & 0x3fff)));
}
/*
* Fill in the tail of the PLT entry first, for reentrancy.
* Until we have overwritten the first insn (an unconditional
* branch), the remaining insns have no effect.
*/
stubptr = (uint32_t *)stubaddr;
while (insncnt > 1) {
insncnt--;
stubptr[insncnt] = insn[insncnt];
}
/*
* Commit the tail of the insn sequence to memory
* before overwriting the first insn.
*/
__asm volatile("wmb" ::: "memory");
stubptr[0] = insn[0];
/*
* I-stream will be sync'd when we either return from
* the binder (lazy bind case) or when the PLTGOT thunk
* is patched up (bind-now case).
*/
}
out:
if (tp)
*tp = new_value;
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Addr reloff)
{
const Elf_Rela *rela =
(const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff);
Elf_Addr result = 0; /* XXX gcc */
int err;
err = _rtld_relocate_plt_object(obj, rela, &result);
if (err)
_rtld_die();
return (caddr_t)result;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rela *rela;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++)
if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
return -1;
return 0;
}

View File

@@ -0,0 +1,194 @@
/* $NetBSD: rtld_start.S,v 1.16 2004/02/18 23:04:49 enami Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Portions copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
/*
* Note: we can call ourselves LEAF even though we use callee-saved
* registers because we're the root of the call graph.
*/
LEAF_NOPROFILE(_rtld_start, 0)
.set noreorder
br pv, 1f
1: LDGP(pv)
/*
* Relocate ourself.
*/
br s2, 2f /* get our PC */
2: ldiq s3, 2b /* get where the linker thought we were */
subq s2, s3, a1 /* relocbase */
lda t5, _DYNAMIC
addq a1, t5, a0 /* &_DYNAMIC */
/* Squirrel away ps_strings. */
mov a3, s0
bsr ra, _rtld_relocate_nonplt_self
LDGP(ra)
/*
* Allocate space on the stack for the cleanup and obj_main
* entries that _rtld() will provide for us.
*/
lda sp, -16(sp)
subq s2, s3, a1 /* relocbase */
mov sp, a0 /* sp */
CALL(_rtld) /* v0 = _rtld(sp, relocbase); */
ldq a1, 0(sp) /* cleanup */
ldq a2, 8(sp) /* obj_main */
lda sp, 16(sp) /* pop stack */
mov sp, a0 /* stack pointer */
mov s0, a3 /* ps_strings */
mov v0, pv /* set up PV for entry point */
jsr ra, (v0), 0 /* (*_start)(sp, cleanup, obj, ps_strings); */
ldgp gp, 0(ra)
CALL(exit)
halt
END(_rtld_start)
#define RTLD_BIND_START_PROLOGUE \
/* at_reg already used by PLT code. */ \
.set noat ; \
\
/* \
* Allocate stack frame and preserve all registers that the \
* caller would have normally saved themselves. \
*/ \
lda sp, -168(sp) ; \
stq ra, 0(sp) ; \
stq v0, 8(sp) ; \
stq t0, 16(sp) ; \
stq t1, 24(sp) ; \
stq t2, 32(sp) ; \
stq t3, 40(sp) ; \
stq t4, 48(sp) ; \
stq t5, 56(sp) ; \
stq t6, 64(sp) ; \
stq t7, 72(sp) ; \
stq a0, 80(sp) ; \
stq a1, 88(sp) ; \
stq a2, 96(sp) ; \
stq a3, 104(sp) ; \
stq a4, 112(sp) ; \
stq a5, 120(sp) ; \
stq t8, 128(sp) ; \
stq t9, 136(sp) ; \
stq t10, 144(sp) ; \
stq t11, 152(sp) ; \
stq gp, 160(sp) ; \
\
/* \
* Load our global pointer. Note, can't use pv, since it is \
* already used by the PLT code. \
*/ \
br t0, 1f ; \
1: LDGP(t0)
#define RTLD_BIND_START_EPILOGUE \
/* Move the destination address into position. */ \
mov v0, pv ; \
\
/* Restore program registers. */ \
ldq ra, 0(sp) ; \
ldq v0, 8(sp) ; \
ldq t0, 16(sp) ; \
ldq t1, 24(sp) ; \
ldq t2, 32(sp) ; \
ldq t3, 40(sp) ; \
ldq t4, 48(sp) ; \
ldq t5, 56(sp) ; \
ldq t6, 64(sp) ; \
ldq t7, 72(sp) ; \
ldq a0, 80(sp) ; \
ldq a1, 88(sp) ; \
ldq a2, 96(sp) ; \
ldq a3, 104(sp) ; \
ldq a4, 112(sp) ; \
ldq a5, 120(sp) ; \
ldq t8, 128(sp) ; \
ldq t9, 136(sp) ; \
ldq t10, 144(sp) ; \
ldq t11, 152(sp) ; \
ldq gp, 160(sp) ; \
/* XXX LDGP? */ \
\
/* \
* We've patched the PLT; sync the I-stream. \
*/ \
imb ; \
\
/* Pop the stack frame and turn control to the destination. */ \
lda sp, 168(sp) ; \
jmp zero, (pv)
/*
* Lazy binding entry point, called via PLT.
*/
NESTED_NOPROFILE(_rtld_bind_start, 0, 168, ra, 0, 0)
RTLD_BIND_START_PROLOGUE
/* Set up the arguments for _rtld_bind. */
subq at_reg, pv, a1 /* calculate offset of reloc entry */
ldq a0, 8(pv) /* object structure */
subq a1, 20, a1 /* = (at - pv - 20) / 12 * 24 */
addq a1, a1, a1
CALL(_rtld_bind)
RTLD_BIND_START_EPILOGUE
END(_rtld_bind_start)
/*
* Lazy binding entry point, called via PLT. This version is for the
* old PLT entry format.
*/
NESTED_NOPROFILE(_rtld_bind_start_old, 0, 168, ra, 0, 0)
RTLD_BIND_START_PROLOGUE
/* Set up the arguments for _rtld_bind. */
ldq a0, 8(pv) /* object structure */
mov at_reg, a1 /* offset of reloc entry */
CALL(_rtld_bind)
RTLD_BIND_START_EPILOGUE
END(_rtld_bind_start_old)

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.11 2005/06/04 16:17:17 lukem Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic
CPPFLAGS+= -DELFSIZE=32
LDFLAGS+= -Wl,-e,_rtld_start

View File

@@ -0,0 +1,276 @@
/* $NetBSD: mdreloc.c,v 1.34 2010/08/06 16:33:17 joerg Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.34 2010/08/06 16:33:17 joerg Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <string.h>
#include "debug.h"
#include "rtld.h"
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
obj->pltgot[1] = (Elf_Addr) obj;
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rel *rel = 0, *rellim;
Elf_Addr relsz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_REL:
rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELSZ:
relsz = dynp->d_un.d_val;
break;
}
}
rellim = (const Elf_Rel *)((const uint8_t *)rel + relsz);
for (; rel < rellim; rel++) {
where = (Elf_Addr *)(relocbase + rel->r_offset);
*where += (Elf_Addr)relocbase;
}
}
/*
* 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)
{
Elf_Addr res;
memcpy(&res, where, sizeof(res));
return (res);
}
static inline void
store_ptr(void *where, Elf_Addr val)
{
memcpy(where, &val, sizeof(val));
}
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
const Elf_Rel *rel;
for (rel = obj->rel; rel < obj->rellim; rel++) {
Elf_Addr *where;
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf_Addr tmp;
unsigned long symnum;
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
symnum = ELF_R_SYM(rel->r_info);
switch (ELF_R_TYPE(rel->r_info)) {
case R_TYPE(NONE):
break;
#if 1 /* XXX should not occur */
case R_TYPE(PC24): { /* word32 S - P + A */
Elf32_Sword addend;
/*
* Extract addend and sign-extend if needed.
*/
addend = *where;
if (addend & 0x00800000)
addend |= 0xff000000;
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
tmp = (Elf_Addr)obj->relocbase + def->st_value
- (Elf_Addr)where + (addend << 2);
if ((tmp & 0xfe000000) != 0xfe000000 &&
(tmp & 0xfe000000) != 0) {
_rtld_error(
"%s: R_ARM_PC24 relocation @ %p to %s failed "
"(displacement %ld (%#lx) out of range)",
obj->path, where,
obj->strtab + obj->symtab[symnum].st_name,
(long) tmp, (long) tmp);
return -1;
}
tmp >>= 2;
*where = (*where & 0xff000000) | (tmp & 0x00ffffff);
rdbg(("PC24 %s in %s --> %p @ %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, where, defobj->path));
break;
}
#endif
case R_TYPE(ABS32): /* word32 B + S + A */
case R_TYPE(GLOB_DAT): /* word32 B + S */
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
if (__predict_true(RELOC_ALIGNED_P(where))) {
tmp = *where + (Elf_Addr)defobj->relocbase +
def->st_value;
/* Set the Thumb bit, if needed. */
if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC)
tmp |= 1;
*where = tmp;
} else {
tmp = load_ptr(where) +
(Elf_Addr)defobj->relocbase +
def->st_value;
/* Set the Thumb bit, if needed. */
if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC)
tmp |= 1;
store_ptr(where, tmp);
}
rdbg(("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)tmp, where, defobj->path));
break;
case R_TYPE(RELATIVE): /* word32 B + A */
if (__predict_true(RELOC_ALIGNED_P(where))) {
tmp = *where + (Elf_Addr)obj->relocbase;
*where = tmp;
} else {
tmp = load_ptr(where) +
(Elf_Addr)obj->relocbase;
store_ptr(where, tmp);
}
rdbg(("RELATIVE in %s --> %p", obj->path,
(void *)tmp));
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, "
"contents = %p, symbol = %s",
symnum, (u_long)ELF_R_TYPE(rel->r_info),
(void *)rel->r_offset, (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(rel->r_info));
return -1;
}
}
return 0;
}
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{
const Elf_Rel *rel;
if (!obj->relocbase)
return 0;
for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT));
/* Just relocate the GOT slots pointing into the PLT */
*where += (Elf_Addr)obj->relocbase;
rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
}
return 0;
}
static int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel,
Elf_Addr *tp)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
Elf_Addr new_value;
const Elf_Sym *def;
const Obj_Entry *defobj;
unsigned long info = rel->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT));
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;
new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
/* Set the Thumb bit, if needed. */
if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC)
new_value |= 1;
rdbg(("bind now/fixup in %s --> old=%p new=%p",
defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
if (*where != new_value)
*where = new_value;
if (tp)
*tp = new_value;
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rel *rel = (const Elf_Rel *)((const uint8_t *)obj->pltrel + reloff);
Elf_Addr new_value = 0; /* XXX gcc */
int err;
err = _rtld_relocate_plt_object(obj, rel, &new_value);
if (err)
_rtld_die();
return (caddr_t)new_value;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rel *rel;
int err = 0;
for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
err = _rtld_relocate_plt_object(obj, rel, NULL);
if (err)
break;
}
return err;
}

View File

@@ -0,0 +1,104 @@
/* $NetBSD: rtld_start.S,v 1.10 2009/11/11 14:15:41 skrll Exp $ */
/*-
* Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas and by Charles M. Hannum.
*
* 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>
RCSID("$NetBSD: rtld_start.S,v 1.10 2009/11/11 14:15:41 skrll Exp $")
.text
.align 0
.globl _rtld_start
.type _rtld_start,%function
_rtld_start:
sub sp, sp, #8 /* make room for obj_main & exit proc */
mov r4, r0 /* save ps_strings */
ldr sl, .L2
ldr r5, .L2+4
ldr r0, .L2+8
.L1:
add sl, pc, sl
ldr r5, [sl, r5]
ldr r0, [sl, r0]
sub r1, sl, r5 /* relocbase */
add r0, r1, r0 /* &_DYNAMIC */
bl _rtld_relocate_nonplt_self
sub r1, sl, r5 /* relocbase */
mov r0, sp /* sp */
bl _rtld /* call the shared loader */
mov r3, r0 /* save entry point */
ldr r2, [sp, #0] /* r2 = cleanup */
ldr r1, [sp, #4] /* r1 = obj_main */
add sp, sp, #8 /* restore stack */
mov r0, r4 /* restore ps_strings */
#ifdef _ARM_ARCH_4T
bx r3 /* jump to the entry point */
#else
mov pc, r3 /* jump to the entry point */
#endif
.L2:
.word _GLOBAL_OFFSET_TABLE_ - (.L1+8)
.word _GLOBAL_OFFSET_TABLE_(GOT)
.word _DYNAMIC(GOT)
.align 0
.globl _rtld_bind_start
.type _rtld_bind_start,%function
/*
* stack[0] = RA
* ip = &GOT[n+3]
* lr = &GOT[2]
*/
_rtld_bind_start:
stmdb sp!,{r0-r4,sl,fp}
sub r1, ip, lr /* r1 = 4 * (n + 1) */
sub r1, r1, #4 /* r1 = 4 * n */
add r1, r1, r1 /* r1 = 8 * n */
ldr r0, [lr, #-4] /* get obj ptr from GOT[1] */
mov r4, ip /* save GOT location */
bl _rtld_bind /* Call the binder */
str r0, [r4] /* save address in GOT */
mov ip, r0 /* save new address */
ldmia sp!,{r0-r4,sl,fp,lr} /* restore the stack */
#ifdef _ARM_ARCH_4T
bx ip /* jump to the new address */
#else
mov pc, ip /* jump to the new address */
#endif

View File

@@ -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'

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.14 2009/12/13 09:31:47 mrg Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic
CPPFLAGS+= -DELFSIZE=32
LDFLAGS+= -Wl,-e,.rtld_start

View File

@@ -0,0 +1,216 @@
/* $NetBSD: mdreloc.c,v 1.32 2010/08/06 16:33:18 joerg Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.32 2010/08/06 16:33:18 joerg Exp $");
#endif /* not lint */
#include <sys/types.h>
#include "debug.h"
#include "rtld.h"
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
obj->pltgot[1] = (Elf_Addr) obj;
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rel *rel = 0, *rellim;
Elf_Addr relsz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_REL:
rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELSZ:
relsz = dynp->d_un.d_val;
break;
}
}
if (rel == 0 || relsz == 0)
return;
rellim = (const Elf_Rel *)((const uint8_t *)rel + relsz);
for (; rel < rellim; rel++) {
where = (Elf_Addr *)(relocbase + rel->r_offset);
*where += (Elf_Addr)relocbase;
}
}
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
const Elf_Rel *rel;
Elf_Addr target = 0;
for (rel = obj->rel; rel < obj->rellim; rel++) {
Elf_Addr *where;
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf_Addr tmp;
unsigned long symnum;
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
symnum = ELF_R_SYM(rel->r_info);
switch (ELF_R_TYPE(rel->r_info)) {
case R_TYPE(NONE):
break;
#if 1 /* XXX should not occur */
case R_TYPE(PC32):
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
target = (Elf_Addr)(defobj->relocbase + def->st_value);
*where += target - (Elf_Addr)where;
rdbg(("PC32 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(GOT32):
#endif
case R_TYPE(32):
case R_TYPE(GLOB_DAT):
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
target = (Elf_Addr)(defobj->relocbase + def->st_value);
tmp = target + *where;
if (*where != tmp)
*where = tmp;
rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(RELATIVE):
*where += (Elf_Addr)obj->relocbase;
rdbg(("RELATIVE 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, "
"contents = %p, symbol = %s",
symnum, (u_long)ELF_R_TYPE(rel->r_info),
(void *)rel->r_offset, (void *)*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(rel->r_info));
return -1;
}
}
return 0;
}
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{
const Elf_Rel *rel;
if (!obj->relocbase)
return 0;
for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JMP_SLOT));
/* Just relocate the GOT slots pointing into the PLT */
*where += (Elf_Addr)obj->relocbase;
rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
}
return 0;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel,
Elf_Addr *tp)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
Elf_Addr target;
const Elf_Sym *def;
const Obj_Entry *defobj;
unsigned long info = rel->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
target = (Elf_Addr)(defobj->relocbase + def->st_value);
rdbg(("bind now/fixup in %s --> old=%p new=%p",
defobj->strtab + def->st_name, (void *)*where,
(void *)target));
if (*where != target)
*where = target;
if (tp)
*tp = target;
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rel *rel = (const Elf_Rel *)((const uint8_t *)obj->pltrel
+ reloff);
Elf_Addr new_value;
int err;
new_value = 0; /* XXX gcc */
err = _rtld_relocate_plt_object(obj, rel, &new_value);
if (err)
_rtld_die();
return (caddr_t)new_value;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rel *rel;
int err = 0;
for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
err = _rtld_relocate_plt_object(obj, rel, NULL);
if (err)
break;
}
return err;
}

View File

@@ -0,0 +1,88 @@
/* $NetBSD: rtld_start.S,v 1.11 2010/12/05 00:56:07 joerg Exp $ */
/*-
* Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas and by Charles M. Hannum.
*
* 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>
.text
.align 4
.globl .rtld_start
.hidden .rtld_start
.type .rtld_start,@function
.rtld_start:
subl $8,%esp # make room of obj_main and exit proc
pushl %ebx # save ps_strings
call 1f
1:
popl %edx
leal _DYNAMIC-1b(%edx),%ecx # &_DYNAMIC
movl %ecx,%ebx
subl _GLOBAL_OFFSET_TABLE_-1b(%edx),%ebx
pushl %ebx # relocbase
pushl %ecx # &_DYNAMIC
call _rtld_relocate_nonplt_self
leal 12(%esp),%eax # &cleanup
pushl %ebx # relocbase
pushl %eax # sp
call _rtld # _rtld(sp, relocbase)
addl $16,%esp # pop args
popl %ebx # %ebx = ps_strings
popl %edx # %edx = cleanup
popl %ecx # %ecx = obj_main
jmp *%eax
.align 4
.globl _rtld_bind_start
.hidden _rtld_bind_start
.type _rtld_bind_start,@function
_rtld_bind_start: # (obj, reloff)
pushf # save registers
pushl %eax
pushl %ecx
pushl %edx
pushl 20(%esp) # Copy of reloff
pushl 20(%esp) # Copy of obj
call _rtld_bind # Call the binder
addl $8,%esp # pop binder args
movl %eax,20(%esp) # Store function to be called in obj
popl %edx
popl %ecx
popl %eax
popf
leal 4(%esp),%esp # Discard reloff, do not change eflags
ret

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.10 2005/06/04 16:17:17 lukem Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic
CPPFLAGS+= -DELFSIZE=32
LDFLAGS+= -Wl,-e,.rtld_start

View File

@@ -0,0 +1,224 @@
/* $NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:18 joerg Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:18 joerg Exp $");
#endif /* not lint */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:18 joerg Exp $");
#endif /* not lint */
#include <sys/types.h>
#include "debug.h"
#include "rtld.h"
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, Elf_Addr *);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
obj->pltgot[1] = (Elf_Addr) obj;
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
*where += (Elf_Addr)relocbase;
}
}
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;
#if 1 /* XXX should not occur */
case R_TYPE(PC32):
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
rela->r_addend) - (Elf_Addr)where;
if (*where != tmp)
*where = tmp;
rdbg(("PC32 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(GOT32):
#endif
case R_TYPE(32):
case R_TYPE(GLOB_DAT):
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 (*where != tmp)
*where = tmp;
rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(RELATIVE):
*where += (Elf_Addr)obj->relocbase;
rdbg(("RELATIVE 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 *)*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;
if (!obj->relocbase)
return 0;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
/* Just relocate the GOT slots pointing into the PLT */
*where += (Elf_Addr)obj->relocbase;
rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
}
return 0;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
Elf_Addr *tp)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
Elf_Addr new_value;
const Elf_Sym *def;
const Obj_Entry *defobj;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
assert(rela->r_addend == 0);
new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
rela->r_addend);
rdbg(("bind now/fixup in %s --> old=%p new=%p",
defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
if (*where != new_value)
*where = new_value;
if (tp)
*tp = new_value - rela->r_addend;
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff);
Elf_Addr result;
int err;
result = 0; /* XXX gcc */
err = _rtld_relocate_plt_object(obj, rela, &result);
if (err)
_rtld_die();
return (caddr_t)result;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rela *rela;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++)
if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
return -1;
return 0;
}

View File

@@ -0,0 +1,79 @@
/* $NetBSD: rtld_start.S,v 1.9 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 1999, 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Klaus Klein and by Charles M. Hannum.
*
* 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>
.text
.align 4
.globl .rtld_start
.type .rtld_start,@function
.rtld_start:
subql #8,%sp | storage for obj and cleanup
lea (%pc,_GLOBAL_OFFSET_TABLE_@GOTPC),%a0
lea (%pc,_DYNAMIC),%a1
movel %a1,%a5
subl (%a0),%a5
movel %a5,-(%sp) | relocbase
movel %a1,-(%sp) | &_DYNAMIC
jbsr _rtld_relocate_nonplt_self@PLTPC
addql #8,%sp | pop arguments
movel %a5,-(%sp) | relocbase
pea 4(%sp) | sp
jbsr _rtld@PLTPC | entry = _rtld(sp, relocbase)
addql #8,%sp | pop arguments
moveal (%sp)+,%a1 | cleanup
moveal (%sp)+,%a0 | obj
moveal %d0,%a3
jmp (%a3) | Go for it!
.size .rtld_start,.-.rtld_start
.align 4
.globl _rtld_bind_start
.type _rtld_bind_start,@function
_rtld_bind_start:
moveml %d0-%d1/%a0-%a1,-(%sp) | preserve caller-saved registers
movel 20(%sp),-(%sp) | push reloff
movel (16+4)(%sp),-(%sp) | push obj
jbsr _rtld_bind@PLTPC | %a0 = _rtld_bind(obj, reloff)
addql #8,%sp | pop args
#ifdef __SVR4_ABI__
movel %a0,(16+4)(%sp) | write fake `return' address over obj
#else
movel %d0,(16+4)(%sp) | write fake `return' address over obj
#endif
moveml (%sp)+,%d0-%d1/%a0-%a1 | restore caller-saved registers
addql #4,%sp | skip reloff
rts | `return' right into function
.size _rtld_bind_start,.-_rtld_bind_start

View File

@@ -0,0 +1,17 @@
# $NetBSD: Makefile.inc,v 1.19 2010/07/11 07:43:12 mrg Exp $
SRCS+= rtld_start.S mips_reloc.c
COPTS+= -G0
ABI64?= ${CFLAGS:M-mabi=64} ${CPPFLAGS:M-mabi=64} ${COPTS:M-mabi=64}
ABIO64?= ${CFLAGS:M-mabi=o64} ${CPPFLAGS:M-mabi=o64} ${COPTS:M-mabi=o64}
.if !empty(ABI64) || !empty(ABIO64)
CPPFLAGS+= -DELFSIZE=64
.else
CPPFLAGS+= -DELFSIZE=32
.endif
CPPFLAGS+= -DRTLD_INHIBIT_COPY_RELOCS
AFLAGS+= -Wa,--fatal-warnings
LDFLAGS+= -Wl,-e,rtld_start

View File

@@ -0,0 +1,454 @@
/* $NetBSD: mips_reloc.c,v 1.60 2010/09/24 15:20:52 matt Exp $ */
/*
* Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
* Portions copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: mips_reloc.c,v 1.60 2010/09/24 15:20:52 matt Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <sys/endian.h>
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "rtld.h"
#ifdef __mips_o32
#define SUPPORT_OLD_BROKEN_LD
#endif
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(Elf_Word, Elf_Addr, Elf_Addr, Elf_Addr);
/*
* It is possible for the compiler to emit relocations for unaligned data.
* We handle this situation with these inlines.
*/
#if ELFSIZE == 64
/*
* ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain
* the symbol index. The top 32-bits contain three relocation types encoded
* in big-endian integer with first relocation in LSB. This means for little
* endian we have to byte swap that interger (r_type).
*/
#define Elf_Sxword Elf64_Sxword
#define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64))
#if BYTE_ORDER == LITTLE_ENDIAN
#undef ELF_R_SYM
#undef ELF_R_TYPE
#define ELF_R_SYM(r_info) ((r_info) & 0xffffffff)
#define ELF_R_TYPE(r_info) bswap32((r_info) >> 32)
#endif
#else
#define ELF_R_NXTTYPE_64_P(r_type) (0)
#define Elf_Sxword Elf32_Sword
#endif
#define GOT1_MASK (~(Elf_Addr)0 >> 1)
static inline Elf_Sxword
load_ptr(void *where, size_t len)
{
Elf_Sxword val;
if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
#if ELFSIZE == 64
if (len == sizeof(Elf_Sxword))
return *(Elf_Sxword *)where;
#endif
return *(Elf_Sword *)where;
}
val = 0;
#if BYTE_ORDER == LITTLE_ENDIAN
(void)memcpy(&val, where, len);
#endif
#if BYTE_ORDER == BIG_ENDIAN
(void)memcpy((uint8_t *)((&val)+1) - len, where, len);
#endif
return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val;
}
static inline void
store_ptr(void *where, Elf_Sxword val, size_t len)
{
if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
#if ELFSIZE == 64
if (len == sizeof(Elf_Sxword)) {
*(Elf_Sxword *)where = val;
return;
}
#endif
*(Elf_Sword *)where = val;
return;
}
#if BYTE_ORDER == LITTLE_ENDIAN
(void)memcpy(where, &val, len);
#endif
#if BYTE_ORDER == BIG_ENDIAN
(void)memcpy(where, (const uint8_t *)((&val)+1) - len, len);
#endif
}
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
/* XXX only if obj->pltgot[1] & 0x80000000 ?? */
obj->pltgot[1] |= (Elf_Addr) obj;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rel *rel = 0, *rellim;
Elf_Addr relsz = 0;
void *where;
const Elf_Sym *symtab = NULL, *sym;
Elf_Addr *got = NULL;
Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
size_t i;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_REL:
rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELSZ:
relsz = dynp->d_un.d_val;
break;
case DT_SYMTAB:
symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_PLTGOT:
got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_MIPS_LOCAL_GOTNO:
local_gotno = dynp->d_un.d_val;
break;
case DT_MIPS_SYMTABNO:
symtabno = dynp->d_un.d_val;
break;
case DT_MIPS_GOTSYM:
gotsym = dynp->d_un.d_val;
break;
}
}
i = (got[1] & 0x80000000) ? 2 : 1;
/* Relocate the local GOT entries */
got += i;
for (; i < local_gotno; i++)
*got++ += relocbase;
sym = symtab + gotsym;
/* Now do the global GOT entries */
for (i = gotsym; i < symtabno; i++) {
*got = sym->st_value + relocbase;
++sym;
++got;
}
rellim = (const Elf_Rel *)((uintptr_t)rel + relsz);
for (; rel < rellim; rel++) {
Elf_Word r_symndx, r_type;
where = (void *)(relocbase + rel->r_offset);
r_symndx = ELF_R_SYM(rel->r_info);
r_type = ELF_R_TYPE(rel->r_info);
switch (r_type & 0xff) {
case R_TYPE(REL32): {
const size_t rlen =
ELF_R_NXTTYPE_64_P(r_type)
? sizeof(Elf_Sxword)
: sizeof(Elf_Sword);
Elf_Sxword old = load_ptr(where, rlen);
Elf_Sxword val = old;
#if ELFSIZE == 64
assert(r_type == R_TYPE(REL32)
|| r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
#endif
assert(r_symndx < gotsym);
sym = symtab + r_symndx;
assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
val += relocbase;
store_ptr(where, val, sizeof(Elf_Sword));
rdbg(("REL32/L(%p) %p -> %p in <self>",
where, (void *)old, (void *)val));
store_ptr(where, val, rlen);
break;
}
case R_TYPE(GPREL32):
case R_TYPE(NONE):
break;
default:
abort();
}
}
}
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
const Elf_Rel *rel;
Elf_Addr *got = obj->pltgot;
const Elf_Sym *sym, *def;
const Obj_Entry *defobj;
Elf_Word i;
#ifdef SUPPORT_OLD_BROKEN_LD
int broken;
#endif
#ifdef SUPPORT_OLD_BROKEN_LD
broken = 0;
sym = obj->symtab;
for (i = 1; i < 12; i++)
if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE))
broken = 1;
dbg(("%s: broken=%d", obj->path, broken));
#endif
i = (got[1] & 0x80000000) ? 2 : 1;
/* Relocate the local GOT entries */
got += i;
for (; i < obj->local_gotno; i++)
*got++ += (Elf_Addr)obj->relocbase;
sym = obj->symtab + obj->gotsym;
/* Now do the global GOT entries */
for (i = obj->gotsym; i < obj->symtabno; i++) {
rdbg((" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
sym->st_name + obj->strtab, (u_long) *got));
#ifdef SUPPORT_OLD_BROKEN_LD
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
broken && sym->st_shndx == SHN_UNDEF) {
/*
* XXX DANGER WILL ROBINSON!
* You might think this is stupid, as it intentionally
* defeats lazy binding -- and you'd be right.
* Unfortunately, for lazy binding to work right, we
* need to a way to force the GOT slots used for
* function pointers to be resolved immediately. This
* is supposed to be done automatically by the linker,
* by not outputting a PLT slot and setting st_value
* to 0 if there are non-PLT references, but older
* versions of GNU ld do not do this.
*/
def = _rtld_find_symdef(i, obj, &defobj, false);
if (def == NULL)
return -1;
*got = def->st_value + (Elf_Addr)defobj->relocbase;
} else
#endif
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
/*
* If there are non-PLT references to the function,
* st_value should be 0, forcing us to resolve the
* address immediately.
*
* XXX DANGER WILL ROBINSON!
* The linker is not outputting PLT slots for calls to
* functions that are defined in the same shared
* library. This is a bug, because it can screw up
* link ordering rules if the symbol is defined in
* more than one module. For now, if there is a
* definition, we fail the test above and force a full
* symbol lookup. This means that all intra-module
* calls are bound immediately. - mycroft, 2003/09/24
*/
*got = sym->st_value + (Elf_Addr)obj->relocbase;
} else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
/* Symbols with index SHN_ABS are not relocated. */
if (sym->st_shndx != SHN_ABS)
*got = sym->st_value +
(Elf_Addr)obj->relocbase;
} else {
def = _rtld_find_symdef(i, obj, &defobj, false);
if (def == NULL)
return -1;
*got = def->st_value + (Elf_Addr)defobj->relocbase;
}
rdbg((" --> now %lx", (u_long) *got));
++sym;
++got;
}
got = obj->pltgot;
for (rel = obj->rel; rel < obj->rellim; rel++) {
Elf_Word r_symndx, r_type;
void *where;
where = obj->relocbase + rel->r_offset;
r_symndx = ELF_R_SYM(rel->r_info);
r_type = ELF_R_TYPE(rel->r_info);
switch (r_type & 0xff) {
case R_TYPE(NONE):
break;
case R_TYPE(REL32): {
/* 32-bit PC-relative reference */
const size_t rlen =
ELF_R_NXTTYPE_64_P(r_type)
? sizeof(Elf_Sxword)
: sizeof(Elf_Sword);
Elf_Sxword old = load_ptr(where, rlen);
Elf_Sxword val = old;
def = obj->symtab + r_symndx;
if (r_symndx >= obj->gotsym) {
val += got[obj->local_gotno + r_symndx - obj->gotsym];
rdbg(("REL32/G(%p) %p --> %p (%s) in %s",
where, (void *)old, (void *)val,
obj->strtab + def->st_name,
obj->path));
} else {
/*
* XXX: ABI DIFFERENCE!
*
* Old NetBSD binutils would generate shared
* libs with section-relative relocations being
* already adjusted for the start address of
* the section.
*
* New binutils, OTOH, generate shared libs
* with the same relocations being based at
* zero, so we need to add in the start address
* of the section.
*
* --rkb, Oct 6, 2001
*/
if (def->st_info ==
ELF_ST_INFO(STB_LOCAL, STT_SECTION)
#ifdef SUPPORT_OLD_BROKEN_LD
&& !broken
#endif
)
val += (Elf_Addr)def->st_value;
val += (Elf_Addr)obj->relocbase;
rdbg(("REL32/L(%p) %p -> %p (%s) in %s",
where, (void *)old, (void *)val,
obj->strtab + def->st_name, obj->path));
}
store_ptr(where, val, rlen);
break;
}
default:
rdbg(("sym = %lu, type = %lu, offset = %p, "
"contents = %p, symbol = %s",
(u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info),
(void *)rel->r_offset,
(void *)load_ptr(where, sizeof(Elf_Sword)),
obj->strtab + obj->symtab[r_symndx].st_name));
_rtld_error("%s: Unsupported relocation type %ld "
"in non-PLT relocations",
obj->path, (u_long) ELF_R_TYPE(rel->r_info));
return -1;
}
}
return 0;
}
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{
/* PLT fixups were done above in the GOT relocation. */
return 0;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, Elf_Word sym, Elf_Addr *tp)
{
Elf_Addr *got = obj->pltgot;
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf_Addr new_value;
def = _rtld_find_plt_symdef(sym, obj, &defobj, tp != NULL);
if (__predict_false(def == NULL))
return -1;
if (__predict_false(def == &_rtld_sym_zero))
return 0;
new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
rdbg(("bind now/fixup in %s --> new=%p",
defobj->strtab + def->st_name, (void *)new_value));
got[obj->local_gotno + sym - obj->gotsym] = new_value;
if (tp)
*tp = new_value;
return 0;
}
caddr_t
_rtld_bind(Elf_Word a0, Elf_Addr a1, Elf_Addr a2, Elf_Addr a3)
{
Elf_Addr *got = (Elf_Addr *)(a2 - 0x7ff0);
const Obj_Entry *obj = (Obj_Entry *)(got[1] & GOT1_MASK);
Elf_Addr new_value = 0; /* XXX gcc */
int err;
err = _rtld_relocate_plt_object(obj, a0, &new_value);
if (err)
_rtld_die();
return (caddr_t)new_value;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Sym *sym = obj->symtab + obj->gotsym;
Elf_Word i;
for (i = obj->gotsym; i < obj->symtabno; i++, sym++) {
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
if (_rtld_relocate_plt_object(obj, i, NULL) < 0)
return -1;
}
return 0;
}

View File

@@ -0,0 +1,140 @@
/* $NetBSD: rtld_start.S,v 1.10 2009/12/14 00:41:19 matt Exp $ */
/*
* Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
* Portions copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <mips/asm.h>
.globl _C_LABEL(_rtld_relocate_nonplt_self)
.globl _C_LABEL(_rtld)
#define PTR_SIZE (1<<PTR_SCALESHIFT)
LEAF(rtld_start)
.frame sp, 4*PTR_SIZE, ra
.mask 0x10090000,-PTR_SIZE
.set noreorder
SETUP_GP
PTR_SUBU sp, 4*PTR_SIZE # adjust stack pointer
SETUP_GP64(s4, rtld_start)
SAVE_GP(0)
# -> 1*PTR_SIZE(sp) for atexit
# -> 2*PTR_SIZE(sp) for obj_main
move s0, a0 # save stack pointer from a0
move s3, a3 # save ps_strings pointer
PTR_LA a1, 1f
bal 1f
PTR_LA t0, _C_LABEL(_rtld_relocate_nonplt_self)
1: PTR_SUBU a1, ra, a1 # relocbase
move s2, a1 # save for _rtld
PTR_LA a0, _DYNAMIC
PTR_ADDU t9, a1, t0
jalr t9 # _rtld_relocate_nonplt_self(dynp, relocabase)
PTR_ADDU a0, a1, a0 # &_DYNAMIC
move a1, s2 # relocbase
PTR_ADDU a0, sp, 2*PTR_SIZE # sp
jal _C_LABEL(_rtld) # v0 = _rtld(sp, relocbase)
nop
PTR_L a1, 2*PTR_SIZE(sp) # our atexit function
PTR_L a2, 3*PTR_SIZE(sp) # obj_main entry
PTR_ADDU sp, 4*PTR_SIZE # readjust stack
move a0, s0 # stack pointer
move t9, v0
jr t9 # _start(sp, cleanup, obj);
move a3, s3 # restore ps_strings
END(rtld_start)
#define XCALLFRAME_SIZ (12*SZREG)
#define XCALLFRAME_RA (10*SZREG)
#define XCALLFRAME_GP (9*SZREG)
#define XCALLFRAME_S0 (8*SZREG)
#define XCALLFRAME_A3 (7*SZREG)
#define XCALLFRAME_A2 (6*SZREG)
#define XCALLFRAME_A1 (5*SZREG)
#define XCALLFRAME_A0 (4*SZREG)
#if defined(__mips_n32) || defined(__mips_n64)
#define XCALLFRAME_A7 (3*SZREG)
#define XCALLFRAME_A6 (2*SZREG)
#define XCALLFRAME_A5 (1*SZREG)
#define XCALLFRAME_A4 (0*SZREG)
#endif
.globl _rtld_bind_start
.ent _rtld_bind_start
_rtld_bind_start:
.frame sp, XCALLFRAME_SIZ, $15
move v1, gp # save old GP
#if defined(__mips_o32) || defined(__mips_o64)
PTR_ADDU t9, 8 # modify T9 to point at .cpload
#endif
SETUP_GP
PTR_SUBU sp, XCALLFRAME_SIZ # save arguments and sp value in stack
SETUP_GP64(XCALLFRAME_GP, _rtld_bind_start)
SAVE_GP(XCALLFRAME_GP)
#if defined(__mips_n32) || defined(__mips_n64)
REG_S a4, XCALLFRAME_A4(sp)
REG_S a5, XCALLFRAME_A5(sp)
REG_S a6, XCALLFRAME_A6(sp)
REG_S a7, XCALLFRAME_A7(sp)
#endif
REG_S a0, XCALLFRAME_A0(sp)
REG_S a1, XCALLFRAME_A1(sp)
REG_S a2, XCALLFRAME_A2(sp)
REG_S a3, XCALLFRAME_A3(sp)
REG_S $15, XCALLFRAME_RA(sp) # ra is in t7/t3
REG_S s0, XCALLFRAME_S0(sp)
move s0, sp
move a0, t8 # symbol index
move a1, $15 # old RA
move a2, v1 # old GP
move a3, ra # current RA
jal _C_LABEL(_rtld_bind)
nop
move sp, s0
REG_L ra, XCALLFRAME_RA(sp)
REG_L s0, XCALLFRAME_S0(sp)
REG_L a0, XCALLFRAME_A0(sp)
REG_L a1, XCALLFRAME_A1(sp)
REG_L a2, XCALLFRAME_A2(sp)
REG_L a3, XCALLFRAME_A3(sp)
#if defined(__mips_n32) || defined(__mips_n64)
REG_L a4, XCALLFRAME_A4(sp)
REG_L a5, XCALLFRAME_A5(sp)
REG_L a6, XCALLFRAME_A6(sp)
REG_L a7, XCALLFRAME_A7(sp)
#endif
RESTORE_GP64
PTR_ADDU sp, XCALLFRAME_SIZ
move t9, v0
jr t9
nop
END(_rtld_bind_start)

View File

@@ -0,0 +1,11 @@
# $NetBSD: Makefile.inc,v 1.11 2009/10/22 21:56:13 skrll Exp $
SRCS+= rtld_start.S ppc_reloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic -msoft-float
CPPFLAGS+= -DELFSIZE=32
LDFLAGS+= -Wl,-e,_rtld_start
LDFLAGS+= -Wl,--script,${.CURDIR}/arch/powerpc/ld.so.script

View File

@@ -0,0 +1,271 @@
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc",
"elf32-powerpc")
OUTPUT_ARCH(powerpc)
ENTRY(_start)
/* Do we need any of these for elf?
__DYNAMIC = 0; */
PROVIDE (__stack = 0); PROVIDE (___stack = 0);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0 + SIZEOF_HEADERS;
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text :
{
*(.rel.text)
*(.rel.text.*)
*(.rel.gnu.linkonce.t.*)
}
.rela.text :
{
*(.rela.text)
*(.rela.text.*)
*(.rela.gnu.linkonce.t.*)
}
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata :
{
*(.rel.rodata)
*(.rel.rodata.*)
*(.rel.gnu.linkonce.r.*)
}
.rela.rodata :
{
*(.rela.rodata)
*(.rela.rodata.*)
*(.rela.gnu.linkonce.r.*)
}
.rel.data :
{
*(.rel.data)
*(.rel.data.*)
*(.rel.gnu.linkonce.d.*)
}
.rela.data :
{
*(.rela.data)
*(.rela.data.*)
*(.rela.gnu.linkonce.d.*)
}
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.sdata :
{
*(.rel.sdata)
*(.rel.sdata.*)
*(.rel.gnu.linkonce.s.*)
}
.rela.sdata :
{
*(.rela.sdata)
*(.rela.sdata.*)
*(.rela.gnu.linkonce.s.*)
}
.rel.sbss :
{
*(.rel.sbss)
*(.rel.sbss.*)
*(.rel.gnu.linkonce.sb.*)
}
.rela.sbss :
{
*(.rela.sbss)
*(.rela.sbss.*)
*(.rel.gnu.linkonce.sb.*)
}
.rel.sdata2 :
{
*(.rel.sdata2)
*(.rel.sdata2.*)
*(.rel.gnu.linkonce.s2.*)
}
.rela.sdata2 :
{
*(.rela.sdata2)
*(.rela.sdata2.*)
*(.rela.gnu.linkonce.s2.*)
}
.rel.sbss2 :
{
*(.rel.sbss2)
*(.rel.sbss2.*)
*(.rel.gnu.linkonce.sb2.*)
}
.rela.sbss2 :
{
*(.rela.sbss2)
*(.rela.sbss2.*)
*(.rela.gnu.linkonce.sb2.*)
}
.rel.bss :
{
*(.rel.bss)
*(.rel.bss.*)
*(.rel.gnu.linkonce.b.*)
}
.rela.bss :
{
*(.rela.bss)
*(.rela.bss.*)
*(.rela.gnu.linkonce.b.*)
}
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init :
{
KEEP (*(.init))
} =0
.text :
{
*(.text)
*(.text.*)
*(.stub)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t.*)
} =0
.fini :
{
KEEP (*(.fini))
} =0
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(8);
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.eh_frame : { KEEP (*(.eh_frame)) }
.gcc_except_table : { *(.gcc_except_table) }
.fixup : { *(.fixup) }
.got1 : { *(.got1) }
.got2 : { *(.got2) }
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
/* We don't want to include the .ctor section from
from the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.got : { *(.got.plt) *(.got) }
PROVIDE (_GOT_END_ = .);
.sdata2 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) }
.sbss2 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) }
.dynamic : { *(.dynamic) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
}
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss :
{
PROVIDE (__sbss_start = .);
PROVIDE (___sbss_start = .);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
PROVIDE (__sbss_end = .);
PROVIDE (___sbss_end = .);
}
.plt : { *(.plt) }
.bss :
{
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections. */
. = ALIGN(8);
}
. = ALIGN(8);
_end = .;
__end = .;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}

View File

@@ -0,0 +1,370 @@
/* $NetBSD: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $ */
/*-
* Copyright (C) 1998 Tsubai Masanari
* Portions copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $");
#endif /* not lint */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <machine/cpu.h>
#include "debug.h"
#include "rtld.h"
void _rtld_powerpc_pltcall(Elf_Word);
void _rtld_powerpc_pltresolve(Elf_Word, Elf_Word);
#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
#define l(x) ((u_int32_t)(x) & 0xffff)
void _rtld_bind_bssplt_start(void);
void _rtld_bind_secureplt_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
static int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, int, Elf_Addr *);
/*
* The PPC PLT format consists of three sections:
* (1) The "pltcall" and "pltresolve" glue code. This is always 18 words.
* (2) The code part of the PLT entries. There are 2 words per entry for
* up to 8192 entries, then 4 words per entry for any additional entries.
* (3) The data part of the PLT entries, comprising a jump table.
* This section is half the size of the second section (ie. 1 or 2 words
* per entry).
*/
/*
* Setup the plt glue routines (for bss-plt).
*/
#define PLTCALL_SIZE 20
#define PLTRESOLVE_SIZE 24
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
/*
* Secure-PLT is much more sane.
*/
if (obj->gotptr != NULL) {
obj->gotptr[1] = (Elf_Addr) _rtld_bind_secureplt_start;
obj->gotptr[2] = (Elf_Addr) obj;
} else {
Elf_Word *pltcall, *pltresolve;
Elf_Word *jmptab;
int N = obj->pltrelalim - obj->pltrela;
/* Entries beyond 8192 take twice as much space. */
if (N > 8192)
N += N-8192;
pltcall = obj->pltgot;
jmptab = pltcall + 18 + N * 2;
memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
pltcall[1] |= ha(jmptab);
pltcall[2] |= l(jmptab);
pltresolve = obj->pltgot + 8;
memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
pltresolve[0] |= ha(_rtld_bind_bssplt_start);
pltresolve[1] |= l(_rtld_bind_bssplt_start);
pltresolve[3] |= ha(obj);
pltresolve[4] |= l(obj);
/*
* Invalidate the icache for only the code part of the PLT
* (and not the jump table at the end).
*/
__syncicache(pltcall, (char *)jmptab - (char *)pltcall);
}
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
*where = (Elf_Addr)(relocbase + rela->r_addend);
}
}
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)) {
#if 1 /* XXX Should not be necessary. */
case R_TYPE(JMP_SLOT):
#endif
case R_TYPE(NONE):
break;
case R_TYPE(32): /* word32 S + A */
case R_TYPE(GLOB_DAT): /* word32 S + A */
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 (*where != tmp)
*where = tmp;
rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(RELATIVE): /* word32 B + A */
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
rdbg(("RELATIVE 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 *)*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)
{
Elf_Addr * const pltresolve = obj->pltgot + 8;
const Elf_Rela *rela;
int reloff;
for (rela = obj->pltrela, reloff = 0;
rela < obj->pltrelalim;
rela++, reloff++) {
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
if (obj->gotptr != NULL) {
/*
* For now, simply treat then as relative.
*/
*where += (Elf_Addr)obj->relocbase;
} else {
int distance;
if (reloff < 32768) {
/* li r11,reloff */
*where++ = 0x39600000 | reloff;
} else {
/* lis r11,ha(reloff) */
/* addi r11,l(reloff) */
*where++ = 0x3d600000 | ha(reloff);
*where++ = 0x396b0000 | l(reloff);
}
/* b pltresolve */
distance = (Elf_Addr)pltresolve - (Elf_Addr)where;
*where++ = 0x48000000 | (distance & 0x03fffffc);
/*
* Icache invalidation is not done for each entry here
* because we sync the entire code part of the PLT once
* in _rtld_setup_pltgot() after all the entries have been
* initialized.
*/
/* __syncicache(where - 3, 12); */
}
}
return 0;
}
static int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff, Elf_Addr *tp)
{
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
Elf_Addr value;
const Elf_Sym *def;
const Obj_Entry *defobj;
int distance;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
value = (Elf_Addr)(defobj->relocbase + def->st_value);
distance = value - (Elf_Addr)where;
rdbg(("bind now/fixup in %s --> new=%p",
defobj->strtab + def->st_name, (void *)value));
if (obj->gotptr != NULL) {
/*
* For Secure-PLT we simply replace the entry in GOT with the address
* of the routine.
*/
assert(where >= (Elf_Word *)obj->pltgot);
assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela));
*where = value;
} else if (abs(distance) < 32*1024*1024) { /* inside 32MB? */
/* b value # branch directly */
*where = 0x48000000 | (distance & 0x03fffffc);
__syncicache(where, 4);
} else {
Elf_Addr *pltcall, *jmptab;
int N = obj->pltrelalim - obj->pltrela;
/* Entries beyond 8192 take twice as much space. */
if (N > 8192)
N += N-8192;
pltcall = obj->pltgot;
jmptab = pltcall + 18 + N * 2;
jmptab[reloff] = value;
if (reloff < 32768) {
/* li r11,reloff */
*where++ = 0x39600000 | reloff;
} else {
#ifdef notyet
/* lis r11,ha(value) */
/* addi r11,l(value) */
/* mtctr r11 */
/* bctr */
*where++ = 0x3d600000 | ha(value);
*where++ = 0x396b0000 | l(value);
*where++ = 0x7d6903a6;
*where++ = 0x4e800420;
#else
/* lis r11,ha(reloff) */
/* addi r11,l(reloff) */
*where++ = 0x3d600000 | ha(reloff);
*where++ = 0x396b0000 | l(reloff);
#endif
}
/* b pltcall */
distance = (Elf_Addr)pltcall - (Elf_Addr)where;
*where++ = 0x48000000 | (distance & 0x03fffffc);
__syncicache(where - 3, 12);
}
if (tp)
*tp = value;
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rela *rela = (const void *)((const char *)obj->pltrela + reloff);
Elf_Addr new_value;
int err;
new_value = 0; /* XXX gcc */
err = _rtld_relocate_plt_object(obj, rela, reloff, &new_value);
if (err)
_rtld_die();
return (caddr_t)new_value;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rela *rela;
int reloff;
for (rela = obj->pltrela, reloff = 0; rela < obj->pltrelalim; rela++, reloff++) {
if (_rtld_relocate_plt_object(obj, rela, reloff, NULL) < 0)
return -1;
}
return 0;
}

View File

@@ -0,0 +1,133 @@
/* $NetBSD: rtld_start.S,v 1.14 2011/01/16 01:22:29 matt Exp $ */
/*-
* Copyright (C) 1998 Tsubai Masanari
* Portions copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
.globl _rtld_start
.globl _rtld
.text
_rtld_start:
stwu %r1,-48(%r1)
stw %r3,12(%r1) # argc
stw %r4,16(%r1) # argv
stw %r5,20(%r1) # envp
/* stw %r6,24(%r1) # obj (always 0) */
/* stw %r7,28(%r1) # cleanup (always 0) */
stw %r8,32(%r1) # ps_strings
bcl 20,31,1f
1: mflr %r30
mr %r3,%r30 # save for _DYNAMIC
addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha
addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l
addis %r3,%r3,_DYNAMIC-1b@ha # get _DYNAMIC actual address
addi %r3,%r3,_DYNAMIC-1b@l
lwz %r28,0(%r30) # get base-relative &_DYNAMIC
sub %r28,%r3,%r28 # r28 = relocbase
mr %r4,%r28 # r4 = relocbase
bl _rtld_relocate_nonplt_self
lwz %r3,16(%r1)
addi %r3,%r3,-12 # sp = &argv[-3] /* XXX */
mr %r4,%r28 # r4 = relocbase
bl _rtld # _start = _rtld(sp, relocbase)
mtlr %r3
lwz %r3,12(%r1) # argc
lwz %r4,16(%r1) # argv
lwz %r5,20(%r1) # envp
lwz %r6,-8(%r4) # obj = sp[1] (== argv[-2])
lwz %r7,-12(%r4) # cleanup = sp[0] (== argv[-3])
lwz %r8,32(%r1) # ps_strings
addi %r1,%r1,48
blrl # _start(argc, argv, envp, obj, cleanup, ps_strings)
li %r0,1 # _exit()
sc
END(_rtld_start)
.globl _rtld_bind
/*
* secure-plt expects %r11 to be the offset to the rela entry.
* bss-plt expects %r11 to be index of the rela entry.
* So for bss-plt, we multiply the index by 12 to get the offset.
*/
ENTRY_NOPROFILE(_rtld_bind_bssplt_start)
slwi %r11,%r11,2
add %r0,%r11,%r11
add %r11,%r11,%r0
ENTRY_NOPROFILE(_rtld_bind_secureplt_start)
stwu %r1,-160(%r1)
stw %r0,20(%r1)
mflr %r0
stw %r0,16(%r1) # save lr
mfcr %r0
stw %r0,12(%r1) # save cr
stmw %r3,24(%r1) # save r3-r31
mr %r3,%r12 # obj
mr %r4,%r11 # reloff
bl _rtld_bind # _rtld_bind(obj, reloff)
mtctr %r3
lmw %r3,24(%r1) # load r3-r31
lwz %r0,12(%r1) # restore cr
mtcr %r0
lwz %r0,16(%r1) # restore lr
mtlr %r0
lwz %r0,20(%r1)
addi %r1,%r1,160
bctr
END(_rtld_bind_start)
.globl _rtld_powerpc_pltcall
.globl _rtld_powerpc_pltresolve
_rtld_powerpc_pltcall:
slwi %r11,%r11,2
addis %r11,%r11,0 # addis 11,11,jmptab@ha
lwz %r11,0(%r11) # lwz 11,jmptab@l(11)
mtctr %r11
bctr
_rtld_powerpc_pltresolve:
lis %r12,0 # lis 12,_rtld_bind_bssplt_start@ha
addi %r12,%r12,0 # addi 12,12,_rtld_bind_bssplt_start@l
mtctr %r12
lis %r12,0 # lis 12,obj@ha
addi %r12,%r12,0 # addi 12,12,obj@l
bctr

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.7 2005/06/04 16:17:17 lukem Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic
CPPFLAGS+= -DELFSIZE=32
LDFLAGS+= -Wl,-e,.rtld_start

View File

@@ -0,0 +1,249 @@
/* $NetBSD: mdreloc.c,v 1.28 2010/08/06 16:33:18 joerg Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.28 2010/08/06 16:33:18 joerg Exp $");
#endif /* not lint */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.28 2010/08/06 16:33:18 joerg Exp $");
#endif /* not lint */
#include <sys/types.h>
#include "debug.h"
#include "rtld.h"
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, Elf_Addr *);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
obj->pltgot[1] = (Elf_Addr) obj;
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
*where = (Elf_Addr)(relocbase + rela->r_addend);
}
}
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;
#if 1 /* XXX should not occur */
case R_TYPE(GOT32):
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 (*where != tmp)
*where = tmp;
rdbg(("GOT32 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(REL32):
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
rela->r_addend) - (Elf_Addr)where;
if (*where != tmp)
*where = tmp;
rdbg(("PC32 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
#endif
case R_TYPE(DIR32):
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 (*where != tmp)
*where = tmp;
rdbg(("32 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(GLOB_DAT):
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 (*where != tmp)
*where = tmp;
rdbg(("GLOB_DAT %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(RELATIVE):
if (rela->r_addend)
*where = (Elf_Addr)obj->relocbase + rela->r_addend;
else
*where += (Elf_Addr)obj->relocbase;
rdbg(("RELATIVE 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 *)*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;
if (!obj->relocbase)
return 0;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
/* Just relocate the GOT slots pointing into the PLT */
*where += (Elf_Addr)obj->relocbase;
rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
}
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff);
Elf_Addr new_value;
int err;
new_value = 0; /* XXX gcc */
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;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
Elf_Addr new_value;
const Elf_Sym *def;
const Obj_Entry *defobj;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
rdbg(("bind now/fixup in %s --> old=%p new=%p",
defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
if (*where != new_value)
*where = new_value;
if (tp)
*tp = new_value;
return 0;
}

View File

@@ -0,0 +1,117 @@
/* $NetBSD: rtld_start.S,v 1.7 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Marcus Comstedt.
*
* 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>
.text
.align 2
.globl .rtld_start
.type .rtld_start,@function
.rtld_start:
mova 2f,r0
mov.l @r0,r2
add r0,r2 /* GOT */
mov.l @(4,r0),r4 /* _DYNAMIC@GOTOFF */
add r2,r4 /* _DYNAMIC */
mov.l @(12,r0),r1 /* _rtld_relocate_nonplt_self offset */
mov.l @(8,r0),r0 /* _DYNAMIC@GOT */
mov r4,r5
mov.l @(r0,r2),r0 /* where linker thinks _DYNAMIC is */
sub r0,r5 /* compute relocation base */
bsrf r1 /* _rtld_relocate_nonplt_self(dynp, relocbase) */
mov.l r5,@-r15 /* save relocbase */
4:
mov.l @r15+,r5 /* restore relocbase */
add #-8,r15 /* room for values returned by _rtld */
mov r15,r4
mov.l 1f,r0
bsrf r0 /* _rtld(sp, relocbase) */
mov.l r9,@-r15 /* save ps_strings */
3:
mov.l @r15+,r9 /* restore ps_strings */
mov.l @r15+,r7 /* from _rtld: exit procedure */
mov.l @r15+,r8 /* from _rtld: main object */
mov.l @r15,r4 /* restore argc */
mov r15,r5 /* restore argv */
add #4,r5
mov r4,r6 /* restore envp */
shll2 r6
add r15,r6
jmp @r0 /* entry point returned by _rtld */
add #8,r6
.align 2
1: .long _rtld-3b
2: .long _GLOBAL_OFFSET_TABLE_
.long _DYNAMIC@GOTOFF
.long _DYNAMIC@GOT
.long _rtld_relocate_nonplt_self-4b
.size .rtld_start,.-.rtld_start
.align 2
.globl _rtld_bind_start
.type _rtld_bind_start,@function
_rtld_bind_start: /* r0 = obj, r1 = reloff */
mov.l r2,@-r15 /* save registers */
mov.l r3,@-r15
mov.l r4,@-r15
mov.l r5,@-r15
mov.l r6,@-r15
mov.l r7,@-r15
sts.l mach,@-r15
sts.l macl,@-r15
sts.l pr,@-r15
mov r0,r4 /* copy of obj */
mov.l 2f,r0
bsrf r0 /* call the binder */
mov r1,r5 /* copy of reloff */
4:
lds.l @r15+,pr /* restore registers */
lds.l @r15+,macl
lds.l @r15+,mach
mov.l @r15+,r7
mov.l @r15+,r6
mov.l @r15+,r5
mov.l @r15+,r4
mov.l @r15+,r3
jmp @r0
mov.l @r15+,r2
.align 2
2: .long _rtld_bind-4b
.size _rtld_bind_start,.-_rtld_bind_start
.end

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.14 2009/12/13 09:31:47 mrg Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic
CPPFLAGS+= -DELFSIZE=32
LDFLAGS+= -Wl,-e,_rtld_start

View File

@@ -0,0 +1,394 @@
/* $NetBSD: mdreloc.c,v 1.44 2010/08/06 16:33:18 joerg Exp $ */
/*-
* Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Paul Kranenburg and by Charles M. Hannum.
*
* 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: mdreloc.c,v 1.44 2010/08/06 16:33:18 joerg Exp $");
#endif /* not lint */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "rtldenv.h"
#include "debug.h"
#include "rtld.h"
/*
* The following table holds for each relocation type:
* - the width in bits of the memory location the relocation
* applies to (not currently used)
* - the number of bits the relocation value must be shifted to the
* right (i.e. discard least significant bits) to fit into
* the appropriate field in the instruction word.
* - flags indicating whether
* * the relocation involves a symbol
* * the relocation is relative to the current position
* * the relocation is for a GOT entry
* * the relocation is relative to the load address
*
*/
#define _RF_S 0x80000000 /* Resolve symbol */
#define _RF_A 0x40000000 /* Use addend */
#define _RF_P 0x20000000 /* Location relative */
#define _RF_G 0x10000000 /* GOT offset */
#define _RF_B 0x08000000 /* Load address relative */
#define _RF_U 0x04000000 /* Unaligned */
#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
#define _RF_RS(s) ( (s) & 0xff) /* right shift */
static const int reloc_target_flags[] = {
0, /* NONE */
_RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */
_RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32 */
_RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */
_RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */
_RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */
_RF_SZ(32) | _RF_RS(0), /* COPY */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */
_RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */
_RF_A| _RF_B| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */
_RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */
};
#ifdef RTLD_DEBUG_RELOC
static const char *reloc_names[] = {
"NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8",
"DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22",
"22", "13", "LO10", "GOT10", "GOT13",
"GOT22", "PC10", "PC22", "WPLT30", "COPY",
"GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32"
};
#endif
#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0)
#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0)
#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
static const int reloc_target_bitmask[] = {
#define _BM(x) (~(-(1ULL << (x))))
0, /* NONE */
_BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */
_BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */
_BM(30), _BM(22), /* WDISP30, WDISP22 */
_BM(22), _BM(22), /* HI22, _22 */
_BM(13), _BM(10), /* RELOC_13, _LO10 */
_BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */
_BM(10), _BM(22), /* _PC10, _PC22 */
_BM(30), 0, /* _WPLT30, _COPY */
-1, -1, -1, /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
_BM(32) /* _UA32 */
#undef _BM
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, Elf_Addr *);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
/*
* PLTGOT is the PLT on the sparc.
* The first entry holds the call the dynamic linker.
* We construct a `call' sequence that transfers
* to `_rtld_bind_start()'.
* The second entry holds the object identification.
* Note: each PLT entry is three words long.
*/
#define SAVE 0x9de3bfa0 /* i.e. `save %sp,-96,%sp' */
#define CALL 0x40000000
#define NOP 0x01000000
obj->pltgot[0] = SAVE;
obj->pltgot[1] = CALL |
((Elf_Addr) &_rtld_bind_start - (Elf_Addr) &obj->pltgot[1]) >> 2;
obj->pltgot[2] = NOP;
obj->pltgot[3] = (Elf_Addr) obj;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
*where += (Elf_Addr)(relocbase + rela->r_addend);
}
}
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
const Elf_Rela *rela;
for (rela = obj->rela; rela < obj->relalim; rela++) {
Elf_Addr *where;
Elf_Word type, value, mask;
const Elf_Sym *def = NULL;
const Obj_Entry *defobj = NULL;
unsigned long symnum;
where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
symnum = ELF_R_SYM(rela->r_info);
type = ELF_R_TYPE(rela->r_info);
if (type == R_TYPE(NONE))
continue;
/* We do JMP_SLOTs in _rtld_bind() below */
if (type == R_TYPE(JMP_SLOT))
continue;
/* COPY relocs are also handled elsewhere */
if (type == R_TYPE(COPY))
continue;
/*
* We use the fact that relocation types are an `enum'
* Note: R_SPARC_6 is currently numerically largest.
*/
if (type > R_TYPE(6))
return (-1);
value = rela->r_addend;
/*
* Handle relative relocs here, as an optimization.
*/
if (type == R_TYPE(RELATIVE)) {
*where += (Elf_Addr)(obj->relocbase + value);
rdbg(("RELATIVE in %s --> %p", obj->path,
(void *)*where));
continue;
}
if (RELOC_RESOLVE_SYMBOL(type)) {
/* Find the symbol */
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return (-1);
/* Add in the symbol's absolute address */
value += (Elf_Word)(defobj->relocbase + def->st_value);
}
if (RELOC_PC_RELATIVE(type)) {
value -= (Elf_Word)where;
}
if (RELOC_BASE_RELATIVE(type)) {
/*
* Note that even though sparcs use `Elf_rela'
* exclusively we still need the implicit memory addend
* in relocations referring to GOT entries.
* Undoubtedly, someone f*cked this up in the distant
* past, and now we're stuck with it in the name of
* compatibility for all eternity..
*
* In any case, the implicit and explicit should be
* mutually exclusive. We provide a check for that
* here.
*/
#define DIAGNOSTIC
#ifdef DIAGNOSTIC
if (value != 0 && *where != 0) {
xprintf("BASE_REL(%s): where=%p, *where 0x%x, "
"addend=0x%x, base %p\n",
obj->path, where, *where,
rela->r_addend, obj->relocbase);
}
#endif
value += (Elf_Word)(obj->relocbase + *where);
}
mask = RELOC_VALUE_BITMASK(type);
value >>= RELOC_VALUE_RIGHTSHIFT(type);
value &= mask;
if (RELOC_UNALIGNED(type)) {
/* Handle unaligned relocations. */
Elf_Addr tmp = 0;
char *ptr = (char *)where;
int i, size = RELOC_TARGET_SIZE(type)/8;
/* Read it in one byte at a time. */
for (i=0; i<size; i++)
tmp = (tmp << 8) | ptr[i];
tmp &= ~mask;
tmp |= value;
/* Write it back out. */
for (i=0; i<size; i++)
ptr[i] = ((tmp >> (8*i)) & 0xff);
#ifdef RTLD_DEBUG_RELOC
value = (Elf_Word)tmp;
#endif
} else {
*where &= ~mask;
*where |= value;
#ifdef RTLD_DEBUG_RELOC
value = (Elf_Word)*where;
#endif
}
#ifdef RTLD_DEBUG_RELOC
if (RELOC_RESOLVE_SYMBOL(type)) {
rdbg(("%s %s in %s --> %p in %s", reloc_names[type],
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)value, defobj->path));
} else {
rdbg(("%s in %s --> %p", reloc_names[type],
obj->path, (void *)value));
}
#endif
}
return (0);
}
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{
return (0);
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff);
Elf_Addr value;
int err;
value = 0; /* XXX gcc */
err = _rtld_relocate_plt_object(obj, rela, &value);
if (err)
_rtld_die();
return (caddr_t)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;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp)
{
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf_Word *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
Elf_Addr value;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
value = (Elf_Addr)(defobj->relocbase + def->st_value);
rdbg(("bind now/fixup in %s --> new=%p",
defobj->strtab + def->st_name, (void *)value));
/*
* At the PLT entry pointed at by `where', we now construct
* a direct transfer to the now fully resolved function
* address. The resulting code in the jump slot is:
*
* sethi %hi(roffset), %g1
* sethi %hi(addr), %g1
* jmp %g1+%lo(addr)
*
* We write the third instruction first, since that leaves the
* previous `b,a' at the second word in place. Hence the whole
* PLT slot can be atomically change to the new sequence by
* writing the `sethi' instruction at word 2.
*/
#define SETHI 0x03000000
#define JMP 0x81c06000
#define NOP 0x01000000
where[2] = JMP | (value & 0x000003ff);
where[1] = SETHI | ((value >> 10) & 0x003fffff);
__asm volatile("iflush %0+8" : : "r" (where));
__asm volatile("iflush %0+4" : : "r" (where));
if (tp)
*tp = value;
return 0;
}

View File

@@ -0,0 +1,81 @@
/* $NetBSD: rtld_start.S,v 1.16 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 1999, 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas, Paul Kranenburg, and by Charles M. Hannum.
*
* 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>
.section ".text"
.align 4
.global _rtld_start
.type _rtld_start,@function
_rtld_start:
mov 0, %fp /* Erect a fence post for ourselves */
mov %g1, %l1 /* save ps_strings */
sub %sp, 32+8, %sp /* room for return args and save area */
sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %l7
call 0f
add %l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
call _DYNAMIC+8
0: add %l7, %o7, %l7 /* real &_GLOBAL_OFFSET_TABLE_ */
ld [%o7+8], %o0 /* load stub call instruction */
ld [%l7], %l0 /* base-relative &_DYNAMIC */
sll %o0, 2, %o0 /* extract PC offset */
add %o0, %o7, %o0 /* real &_DYNAMIC */
sub %o0, %l0, %l0 /* relocbase */
call _rtld_relocate_nonplt_self
mov %l0, %o1 /* relocbase */
mov %l0, %o1 /* relocbase */
call _rtld
add %sp, 96, %o0 /* &argc - 8 */
ld [%sp + 96], %g3 /* arg: cleanup */
ld [%sp + 96 + 4], %g2 /* arg: obj */
add %sp, 32+8, %sp /* restore stack pointer */
jmp %o0
mov %l1, %g1 /* restore ps_strings */
.section ".text"
.align 4
.global _rtld_bind_start
.type _rtld_bind_start,@function
_rtld_bind_start: # (obj, reloff)
ld [%o7 + 8], %o0 /* obj id is in second PLT slot */
srl %g1, 10, %o1 /* offset is in high 22 bits */
call _rtld_bind /* Call _rtld_bind(obj, offset) */
sub %o1, 12*4, %o1 /* first 4 `pltrel' entries missing! */
jmp %o0 /* return value == function address */
restore

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.8 2005/06/04 16:17:17 lukem Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic
CPPFLAGS+= -DELFSIZE=64
LDFLAGS+= -Wl,-e,_rtld_start

View File

@@ -0,0 +1,732 @@
/* $NetBSD: mdreloc.c,v 1.50 2010/09/24 12:00:10 skrll Exp $ */
/*-
* Copyright (c) 2000 Eduardo Horvath.
* Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Paul Kranenburg and by Charles M. Hannum.
*
* 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: mdreloc.c,v 1.50 2010/09/24 12:00:10 skrll Exp $");
#endif /* not lint */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "rtldenv.h"
#include "debug.h"
#include "rtld.h"
/*
* The following table holds for each relocation type:
* - the width in bits of the memory location the relocation
* applies to (not currently used)
* - the number of bits the relocation value must be shifted to the
* right (i.e. discard least significant bits) to fit into
* the appropriate field in the instruction word.
* - flags indicating whether
* * the relocation involves a symbol
* * the relocation is relative to the current position
* * the relocation is for a GOT entry
* * the relocation is relative to the load address
*
*/
#define _RF_S 0x80000000 /* Resolve symbol */
#define _RF_A 0x40000000 /* Use addend */
#define _RF_P 0x20000000 /* Location relative */
#define _RF_G 0x10000000 /* GOT offset */
#define _RF_B 0x08000000 /* Load address relative */
#define _RF_U 0x04000000 /* Unaligned */
#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
#define _RF_RS(s) ( (s) & 0xff) /* right shift */
static const int reloc_target_flags[] = {
0, /* NONE */
_RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */
_RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32 */
_RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */
_RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */
_RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */
_RF_SZ(32) | _RF_RS(0), /* COPY */
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */
_RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */
_RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* RELATIVE */
_RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */
_RF_A| _RF_SZ(32) | _RF_RS(0), /* PLT32 */
_RF_A| _RF_SZ(32) | _RF_RS(10), /* HIPLT22 */
_RF_A| _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT32 */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PCPLT22 */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT10 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 10 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 11 */
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* 64 */
_RF_S|_RF_A|/*extra*/ _RF_SZ(32) | _RF_RS(0), /* OLO10 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(42), /* HH22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(32), /* HM10 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LM22 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(42), /* PC_HH22 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(32), /* PC_HM10 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC_LM22 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP16 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP19 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_JMP */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 7 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 5 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 6 */
_RF_S|_RF_A|_RF_P| _RF_SZ(64) | _RF_RS(0), /* DISP64 */
_RF_A| _RF_SZ(64) | _RF_RS(0), /* PLT64 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HIX22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LOX10 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(22), /* H44 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(12), /* M44 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* L44 */
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */
_RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */
_RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */
};
#ifdef RTLD_DEBUG_RELOC
static const char *reloc_names[] = {
"NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8",
"DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22",
"22", "13", "LO10", "GOT10", "GOT13",
"GOT22", "PC10", "PC22", "WPLT30", "COPY",
"GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32", "PLT32",
"HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", "PCPLT32",
"10", "11", "64", "OLO10", "HH22",
"HM10", "LM22", "PC_HH22", "PC_HM10", "PC_LM22",
"WDISP16", "WDISP19", "GLOB_JMP", "7", "5", "6",
"DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44",
"L44", "REGISTER", "UA64", "UA16"
};
#endif
#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0)
#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0)
#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
static const long reloc_target_bitmask[] = {
#define _BM(x) (~(-(1ULL << (x))))
0, /* NONE */
_BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */
_BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */
_BM(30), _BM(22), /* WDISP30, WDISP22 */
_BM(22), _BM(22), /* HI22, _22 */
_BM(13), _BM(10), /* RELOC_13, _LO10 */
_BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */
_BM(10), _BM(22), /* _PC10, _PC22 */
_BM(30), 0, /* _WPLT30, _COPY */
_BM(32), _BM(32), _BM(32), /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
_BM(32), _BM(32), /* _UA32, PLT32 */
_BM(22), _BM(10), /* _HIPLT22, LOPLT10 */
_BM(32), _BM(22), _BM(10), /* _PCPLT32, _PCPLT22, _PCPLT10 */
_BM(10), _BM(11), -1, /* _10, _11, _64 */
_BM(10), _BM(22), /* _OLO10, _HH22 */
_BM(10), _BM(22), /* _HM10, _LM22 */
_BM(22), _BM(10), _BM(22), /* _PC_HH22, _PC_HM10, _PC_LM22 */
_BM(16), _BM(19), /* _WDISP16, _WDISP19 */
-1, /* GLOB_JMP */
_BM(7), _BM(5), _BM(6) /* _7, _5, _6 */
-1, -1, /* DISP64, PLT64 */
_BM(22), _BM(13), /* HIX22, LOX10 */
_BM(22), _BM(10), _BM(13), /* H44, M44, L44 */
-1, -1, _BM(16), /* REGISTER, UA64, UA16 */
#undef _BM
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
/*
* Instruction templates:
*/
#define BAA 0x10400000 /* ba,a %xcc, 0 */
#define SETHI 0x03000000 /* sethi %hi(0), %g1 */
#define JMP 0x81c06000 /* jmpl %g1+%lo(0), %g0 */
#define NOP 0x01000000 /* sethi %hi(0), %g0 */
#define OR 0x82806000 /* or %g1, 0, %g1 */
#define XOR 0x82c06000 /* xor %g1, 0, %g1 */
#define MOV71 0x8283a000 /* or %o7, 0, %g1 */
#define MOV17 0x9c806000 /* or %g1, 0, %o7 */
#define CALL 0x40000000 /* call 0 */
#define SLLX 0x8b407000 /* sllx %g1, 0, %g1 */
#define SETHIG5 0x0b000000 /* sethi %hi(0), %g5 */
#define ORG5 0x82804005 /* or %g1, %g5, %g1 */
/* %hi(v)/%lo(v) with variable shift */
#define HIVAL(v, s) (((v) >> (s)) & 0x003fffff)
#define LOVAL(v, s) (((v) >> (s)) & 0x000003ff)
void _rtld_bind_start_0(long, long);
void _rtld_bind_start_1(long, long);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
/*
* Install rtld function call into this PLT slot.
*/
#define SAVE 0x9de3bf50 /* i.e. `save %sp,-176,%sp' */
#define SETHI_l0 0x21000000
#define SETHI_l1 0x23000000
#define OR_l0_l0 0xa0142000
#define SLLX_l0_32_l0 0xa12c3020
#define OR_l0_l1_l0 0xa0140011
#define JMPL_l0_o0 0x91c42000
#define MOV_g1_o1 0x92100001
void _rtld_install_plt(Elf_Word *, Elf_Addr);
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, Elf_Addr *);
void
_rtld_install_plt(Elf_Word *pltgot, Elf_Addr proc)
{
pltgot[0] = SAVE;
pltgot[1] = SETHI_l0 | HIVAL(proc, 42);
pltgot[2] = SETHI_l1 | HIVAL(proc, 10);
pltgot[3] = OR_l0_l0 | LOVAL(proc, 32);
pltgot[4] = SLLX_l0_32_l0;
pltgot[5] = OR_l0_l1_l0;
pltgot[6] = JMPL_l0_o0 | LOVAL(proc, 0);
pltgot[7] = MOV_g1_o1;
}
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
/*
* On sparc64 we got troubles.
*
* Instructions are 4 bytes long.
* Elf[64]_Addr is 8 bytes long, so are our pltglot[]
* array entries.
* Each PLT entry jumps to PLT0 to enter the dynamic
* linker.
* Loading an arbitrary 64-bit pointer takes 6
* instructions and 2 registers.
*
* Somehow we need to issue a save to get a new stack
* frame, load the address of the dynamic linker, and
* jump there, in 8 instructions or less.
*
* Oh, we need to fill out both PLT0 and PLT1.
*/
{
Elf_Word *entry = (Elf_Word *)obj->pltgot;
/* Install in entries 0 and 1 */
_rtld_install_plt(&entry[0], (Elf_Addr) &_rtld_bind_start_0);
_rtld_install_plt(&entry[8], (Elf_Addr) &_rtld_bind_start_1);
/*
* Install the object reference in first slot
* of entry 2.
*/
obj->pltgot[8] = (Elf_Addr) obj;
}
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
*where = (Elf_Addr)(relocbase + rela->r_addend);
}
}
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
const Elf_Rela *rela;
const Elf_Sym *def = NULL;
const Obj_Entry *defobj = NULL;
for (rela = obj->rela; rela < obj->relalim; rela++) {
Elf_Addr *where;
Elf_Word type;
Elf_Addr value = 0, mask;
unsigned long symnum;
where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
symnum = ELF_R_SYM(rela->r_info);
type = ELF_R_TYPE(rela->r_info);
if (type == R_TYPE(NONE))
continue;
/* We do JMP_SLOTs in _rtld_bind() below */
if (type == R_TYPE(JMP_SLOT))
continue;
/* COPY relocs are also handled elsewhere */
if (type == R_TYPE(COPY))
continue;
/*
* We use the fact that relocation types are an `enum'
* Note: R_SPARC_UA16 is currently numerically largest.
*/
if (type > R_TYPE(UA16))
return (-1);
value = rela->r_addend;
/*
* Handle relative relocs here, as an optimization.
*/
if (type == R_TYPE(RELATIVE)) {
*where = (Elf_Addr)(obj->relocbase + value);
rdbg(("RELATIVE in %s --> %p", obj->path,
(void *)*where));
continue;
}
if (RELOC_RESOLVE_SYMBOL(type)) {
/* Find the symbol */
def = _rtld_find_symdef(symnum, obj, &defobj,
false);
if (def == NULL)
return -1;
/* Add in the symbol's absolute address */
value += (Elf_Addr)(defobj->relocbase + def->st_value);
}
if (RELOC_PC_RELATIVE(type)) {
value -= (Elf_Addr)where;
}
if (RELOC_BASE_RELATIVE(type)) {
/*
* Note that even though sparcs use `Elf_rela'
* exclusively we still need the implicit memory addend
* in relocations referring to GOT entries.
* Undoubtedly, someone f*cked this up in the distant
* past, and now we're stuck with it in the name of
* compatibility for all eternity..
*
* In any case, the implicit and explicit should be
* mutually exclusive. We provide a check for that
* here.
*/
#ifdef DIAGNOSTIC
if (value != 0 && *where != 0) {
xprintf("BASE_REL(%s): where=%p, *where 0x%lx, "
"addend=0x%lx, base %p\n",
obj->path, where, *where,
rela->r_addend, obj->relocbase);
}
#endif
/* XXXX -- apparently we ignore the preexisting value */
value += (Elf_Addr)(obj->relocbase);
}
mask = RELOC_VALUE_BITMASK(type);
value >>= RELOC_VALUE_RIGHTSHIFT(type);
value &= mask;
if (RELOC_UNALIGNED(type)) {
/* Handle unaligned relocations. */
Elf_Addr tmp = 0;
char *ptr = (char *)where;
int i, size = RELOC_TARGET_SIZE(type)/8;
/* Read it in one byte at a time. */
for (i=0; i<size; i++)
tmp = (tmp << 8) | ptr[i];
tmp &= ~mask;
tmp |= value;
/* Write it back out. */
for (i=0; i<size; i++)
ptr[i] = ((tmp >> (8*i)) & 0xff);
#ifdef RTLD_DEBUG_RELOC
value = (Elf_Addr)tmp;
#endif
} else if (RELOC_TARGET_SIZE(type) > 32) {
*where &= ~mask;
*where |= value;
#ifdef RTLD_DEBUG_RELOC
value = (Elf_Addr)*where;
#endif
} else {
Elf32_Addr *where32 = (Elf32_Addr *)where;
*where32 &= ~mask;
*where32 |= value;
#ifdef RTLD_DEBUG_RELOC
value = (Elf_Addr)*where32;
#endif
}
#ifdef RTLD_DEBUG_RELOC
if (RELOC_RESOLVE_SYMBOL(type)) {
rdbg(("%s %s in %s --> %p in %s", reloc_names[type],
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)value, defobj->path));
} else {
rdbg(("%s in %s --> %p", reloc_names[type],
obj->path, (void *)value));
}
#endif
}
return (0);
}
int
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
{
return (0);
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rela *rela = obj->pltrela + reloff;
Elf_Addr result;
int err;
result = 0; /* XXX gcc */
if (ELF_R_TYPE(obj->pltrela->r_info) == R_TYPE(JMP_SLOT)) {
/*
* XXXX
*
* The first four PLT entries are reserved. There is some
* disagreement whether they should have associated relocation
* entries. Both the SPARC 32-bit and 64-bit ELF
* specifications say that they should have relocation entries,
* but the 32-bit SPARC binutils do not generate them, and now
* the 64-bit SPARC binutils have stopped generating them too.
*
* So, to provide binary compatibility, we will check the first
* entry, if it is reserved it should not be of the type
* JMP_SLOT. If it is JMP_SLOT, then the 4 reserved entries
* were not generated and our index is 4 entries too far.
*/
rela -= 4;
}
err = _rtld_relocate_plt_object(obj, rela, &result);
if (err)
_rtld_die();
return (caddr_t)result;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rela *rela;
rela = obj->pltrela;
/*
* Check for first four reserved entries - and skip them.
* See above for details.
*/
if (ELF_R_TYPE(obj->pltrela->r_info) != R_TYPE(JMP_SLOT))
rela += 4;
for (; rela < obj->pltrelalim; rela++)
if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
return -1;
return 0;
}
/*
* New inline function that is called by _rtld_relocate_plt_object and
* _rtld_bind
*/
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 value, offset;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
value = (Elf_Addr)(defobj->relocbase + def->st_value);
rdbg(("bind now/fixup in %s --> new=%p",
defobj->strtab + def->st_name, (void *)value));
/*
* At the PLT entry pointed at by `where', we now construct a direct
* transfer to the now fully resolved function address.
*
* A PLT entry is supposed to start by looking like this:
*
* sethi %hi(. - .PLT0), %g1
* ba,a %xcc, .PLT1
* nop
* nop
* nop
* nop
* nop
* nop
*
* When we replace these entries we start from the last instruction
* and do it in reverse order so the last thing we do is replace the
* branch. That allows us to change this atomically.
*
* We now need to find out how far we need to jump. We have a choice
* of several different relocation techniques which are increasingly
* expensive.
*/
offset = ((Elf_Addr)where) - value;
if (rela->r_addend) {
Elf_Addr *ptr = (Elf_Addr *)where;
/*
* This entry is >= 32768. The relocations points to a
* PC-relative pointer to the bind_0 stub at the top of the
* PLT section. Update it to point to the target function.
*/
ptr[0] += value - (Elf_Addr)obj->pltgot;
} else if (offset <= (1L<<20) && (Elf_SOff)offset >= -(1L<<20)) {
/*
* We're within 1MB -- we can use a direct branch insn.
*
* We can generate this pattern:
*
* sethi %hi(. - .PLT0), %g1
* ba,a %xcc, addr
* nop
* nop
* nop
* nop
* nop
* nop
*
*/
where[1] = BAA | ((offset >> 2) & 0x3fffff);
__asm volatile("iflush %0+4" : : "r" (where));
} else if (value < (1L<<32)) {
/*
* We're within 32-bits of address zero.
*
* The resulting code in the jump slot is:
*
* sethi %hi(. - .PLT0), %g1
* sethi %hi(addr), %g1
* jmp %g1+%lo(addr)
* nop
* nop
* nop
* nop
* nop
*
*/
where[2] = JMP | LOVAL(value, 0);
where[1] = SETHI | HIVAL(value, 10);
__asm volatile("iflush %0+8" : : "r" (where));
__asm volatile("iflush %0+4" : : "r" (where));
} else if ((Elf_SOff)value <= 0 && (Elf_SOff)value > -(1L<<32)) {
/*
* We're within 32-bits of address -1.
*
* The resulting code in the jump slot is:
*
* sethi %hi(. - .PLT0), %g1
* sethi %hix(addr), %g1
* xor %g1, %lox(addr), %g1
* jmp %g1
* nop
* nop
* nop
* nop
*
*/
where[3] = JMP;
where[2] = XOR | ((~value) & 0x00001fff);
where[1] = SETHI | HIVAL(~value, 10);
__asm volatile("iflush %0+12" : : "r" (where));
__asm volatile("iflush %0+8" : : "r" (where));
__asm volatile("iflush %0+4" : : "r" (where));
} else if (offset <= (1L<<32) && (Elf_SOff)offset >= -((1L<<32) - 4)) {
/*
* We're within 32-bits -- we can use a direct call insn
*
* The resulting code in the jump slot is:
*
* sethi %hi(. - .PLT0), %g1
* mov %o7, %g1
* call (.+offset)
* mov %g1, %o7
* nop
* nop
* nop
* nop
*
*/
where[3] = MOV17;
where[2] = CALL | ((offset >> 4) & 0x3fffffff);
where[1] = MOV71;
__asm volatile("iflush %0+12" : : "r" (where));
__asm volatile("iflush %0+8" : : "r" (where));
__asm volatile("iflush %0+4" : : "r" (where));
} else if (offset < (1L<<44)) {
/*
* We're within 44 bits. We can generate this pattern:
*
* The resulting code in the jump slot is:
*
* sethi %hi(. - .PLT0), %g1
* sethi %h44(addr), %g1
* or %g1, %m44(addr), %g1
* sllx %g1, 12, %g1
* jmp %g1+%l44(addr)
* nop
* nop
* nop
*
*/
where[4] = JMP | LOVAL(offset, 0);
where[3] = SLLX | 12;
where[2] = OR | (((offset) >> 12) & 0x00001fff);
where[1] = SETHI | HIVAL(offset, 22);
__asm volatile("iflush %0+16" : : "r" (where));
__asm volatile("iflush %0+12" : : "r" (where));
__asm volatile("iflush %0+8" : : "r" (where));
__asm volatile("iflush %0+4" : : "r" (where));
} else if ((Elf_SOff)offset < 0 && (Elf_SOff)offset > -(1L<<44)) {
/*
* We're within 44 bits. We can generate this pattern:
*
* The resulting code in the jump slot is:
*
* sethi %hi(. - .PLT0), %g1
* sethi %h44(-addr), %g1
* xor %g1, %m44(-addr), %g1
* sllx %g1, 12, %g1
* jmp %g1+%l44(addr)
* nop
* nop
* nop
*
*/
where[4] = JMP | LOVAL(offset, 0);
where[3] = SLLX | 12;
where[2] = XOR | (((~offset) >> 12) & 0x00001fff);
where[1] = SETHI | HIVAL(~offset, 22);
__asm volatile("iflush %0+16" : : "r" (where));
__asm volatile("iflush %0+12" : : "r" (where));
__asm volatile("iflush %0+8" : : "r" (where));
__asm volatile("iflush %0+4" : : "r" (where));
} else {
/*
* We need to load all 64-bits
*
* The resulting code in the jump slot is:
*
* sethi %hi(. - .PLT0), %g1
* sethi %hh(addr), %g1
* sethi %lm(addr), %g5
* or %g1, %hm(addr), %g1
* sllx %g1, 32, %g1
* or %g1, %g5, %g1
* jmp %g1+%lo(addr)
* nop
*
*/
where[6] = JMP | LOVAL(value, 0);
where[5] = ORG5;
where[4] = SLLX | 32;
where[3] = OR | LOVAL(value, 32);
where[2] = SETHIG5 | HIVAL(value, 10);
where[1] = SETHI | HIVAL(value, 42);
__asm volatile("iflush %0+24" : : "r" (where));
__asm volatile("iflush %0+20" : : "r" (where));
__asm volatile("iflush %0+16" : : "r" (where));
__asm volatile("iflush %0+12" : : "r" (where));
__asm volatile("iflush %0+8" : : "r" (where));
__asm volatile("iflush %0+4" : : "r" (where));
}
if (tp)
*tp = value;
return 0;
}

View File

@@ -0,0 +1,172 @@
/* $NetBSD: rtld_start.S,v 1.17 2008/04/28 20:23:04 martin Exp $ */
/*-
* Copyright (c) 2000 Eduardo Horvath.
* Copyright (c) 1999, 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas, Paul Kranenburg and by Charles M. Hannum.
*
* 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>
#define _LOCORE
#include <machine/frame.h>
/*
* ELF:
* On startup the stack should contain 16 extended word register save area,
* followed by the arg count, etc.
*
* _rtld() expects the stack pointer to point to two longwords for argument
* return followed by argc, etc. We need to create a pointer to
* &argc + 16 and pass that in. The return args will be in those locations.
*
* NB: We are violating the ELF spec by passing a pointer to the ps strings in
* %g1 instead of a termination routine.
*/
.register %g2,#scratch
.register %g3,#scratch
/* Offset of ARGC from bottom of stack */
#define ARGC 176
.section ".text"
.align 4
.global _rtld_start
.type _rtld_start,@function
_rtld_start:
mov 0, %fp /* Erect a fence post for ourselves */
mov %g1, %l1 /* save ps_strings */
sub %sp, 48+16, %sp /* Make room for return args */
sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %l7
call 0f
add %l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
call _DYNAMIC+8
0: add %l7, %o7, %l7 /* real &_GLOBAL_OFFSET_TABLE_ */
ld [%o7+8], %o0 /* load stub call instruction */
ldx [%l7], %l0 /* base-relative &_DYNAMIC */
sll %o0, 2, %o0 /* extract PC offset */
sra %o0, 0, %o0 /* sign-extend */
add %o0, %o7, %o0 /* real &_DYNAMIC */
sub %o0, %l0, %l0 /* relocbase */
call _rtld_relocate_nonplt_self
mov %l0, %o1 /* relocbase */
mov %l0, %o1 /* relocbase */
call _rtld
add %sp, BIAS + ARGC, %o0 /* &argc - 16 */
ldx [%sp + BIAS + ARGC], %g3 /* arg: cleanup */
ldx [%sp + BIAS + ARGC + 8], %g2 /* arg: obj */
add %sp, 48+16, %sp /* restore stack pointer */
jmp %o0
mov %l1, %g1 /* restore ps_strings */
/*
* We have two separate entry points to the runtime linker.
* I'm implementing this following the SPARC v9 ABI spec.
*
* _rtld_bind_start_0(y, x) is called from .PLT0, and is used for
* PLT entries above 32768.
*
* _rtld_bind_start_1(y, x) is called from .PLT1, and is used for
* PLT entries below 32768.
*
* The first two entries of PLT2 contain the xword object pointer.
*
* These routines are called with two longword arguments,
* x and y. To calculate the address of the entry,
* _rtld_bind_start_1(y, x) does:
*
* n = x >> 15;
*
* and _rtld_bind_start_0(y, x) does:
*
* i = x - y + 8 - 32768*32;
* n = 32768 + (i/5120)*160 + (i%5120)/24;
*
* Neither routine needs to issue a save since it's already been
* done in the PLT entry.
*/
.section ".text"
.align 4
.global _rtld_bind_start_0
.type _rtld_bind_start_0,@function
_rtld_bind_start_0: # (y, x)
/* %o0 = obj->pltgot[6] */
/* %o1 = plt[4] */
/* %o1 - %o0 + 8 == offset of plt[] from obj->pltgot[] */
/* -32768*32 to get offset from beginning of upper PLT section */
sethi %hi(32768*32-8), %l1
sub %o1, %o0, %l0 /* i = x - y */
or %l1, %lo(32768*32-8), %l1
sub %l0, %l1, %l0 /* i = x - y + 8 - 32768*32 */
ldx [%o0 + (10*4)], %o0 /* Load object pointer from PLT2 */
sethi %hi(5120), %l1
sdivx %l0, %l1, %l1 /* Calculate i/5120 */
sllx %l1, 2, %l2
add %l2, %l1, %l2
sllx %l2, 10, %l2
sub %l0, %l2, %l2 /* And i%5120 */
/* Let the division churn for a bit. */
sdivx %l2, 24, %l4 /* (i%5120)/24 */
/* 160 is (32 * 5) or (32 * (4 + 1)) */
sllx %l1, 2, %l3 /* 4 * (i/5120) */
add %l1, %l3, %l3 /* 5 * (i/5120) */
sllx %l3, 5, %l3 /* 32 * 5 * (i/5120) */
sethi %hi(32768), %l6
add %l3, %l4, %l5 /* %l5 = (i/5120)*160 + (i%5120)/24; */
call _rtld_bind /* Call _rtld_bind(obj, offset) */
add %l5, %l6, %o1 /* %o1 = 32768 + ... */
jmp %o0 /* return value == function address */
restore /* Dump our stack frame */
.section ".text"
.align 4
.global _rtld_bind_start_1
.type _rtld_bind_start_1,@function
_rtld_bind_start_1: # (y, x)
ldx [%o0 + (2*4)], %o0 /* Load object pointer from PLT2 */
call _rtld_bind /* Call _rtld_bind(obj, offset) */
srax %o1, 15, %o1 /* %o1 is the index to our PLT slot */
jmp %o0 /* return value == function address */
restore /* Dump our stack frame */

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.11 2009/09/19 14:54:17 skrll Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fpic
CPPFLAGS+= -DELFSIZE=32
LDFLAGS+= -Wl,-Bsymbolic -Wl,-e,_rtld_start

View File

@@ -0,0 +1,207 @@
/* $NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:19 joerg Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:19 joerg Exp $");
#endif /* not lint */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mdreloc.c,v 1.27 2010/08/06 16:33:19 joerg Exp $");
#endif /* not lint */
#include <sys/types.h>
#include "debug.h"
#include "rtld.h"
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, Elf_Addr *);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
obj->pltgot[1] = (Elf_Addr) obj;
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
*where = (Elf_Addr)(relocbase + rela->r_addend);
}
}
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(32): /* word32 S + A */
case R_TYPE(GLOB_DAT): /* word32 S + A */
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 (*where != tmp)
*where = tmp;
rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where, defobj->path));
break;
case R_TYPE(RELATIVE): /* word32 B + A */
tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
if (*where != tmp)
*where = tmp;
rdbg(("RELATIVE 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 *)*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;
if (!obj->relocbase)
return 0;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
/* Just relocate the GOT slots pointing into the PLT */
*where += (Elf_Addr)obj->relocbase;
rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
}
return 0;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
Elf_Addr new_value;
const Elf_Sym *def;
const Obj_Entry *defobj;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
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;
new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
rela->r_addend);
rdbg(("bind now/fixup in %s --> old=%p new=%p",
defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
if (*where != new_value)
*where = new_value;
if (tp)
*tp = new_value - rela->r_addend;
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff);
Elf_Addr result;
int err;
result = 0; /* XXX gcc */
err = _rtld_relocate_plt_object(obj, rela, &result);
if (err)
_rtld_die();
return (caddr_t)result;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rela *rela;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++)
if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
return -1;
return 0;
}

View File

@@ -0,0 +1,78 @@
/* $NetBSD: rtld_start.S,v 1.16 2003/03/02 22:03:40 mycroft Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Portions copyright 2002, 2003 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
/* R9 contains the address of PS_STRINGS and since its caller saved,
* we can just use it. R6 has a backup copy of the stack pointer which
* we can use as well.
*/
ENTRY(_rtld_start, 0)
/* Allocate space on the stack for the cleanup and obj_main
* entries that _rtld() will provide for us.
*/
clrl %fp
subl2 $8,%sp
movab _DYNAMIC,%r0
subl3 _GLOBAL_OFFSET_TABLE_,%r0,%r10
pushl %r10 /* relocbase */
pushl %r0 /* &_DYNAMIC */
calls $2,_rtld_relocate_nonplt_self
pushl %r10 /* relocbase */
pushal 4(%sp) /* sp */
calls $2,_rtld /* entry = _rtld(sp, relocbase) */
movq (%sp)+,%r7 /* grab cleanup and obj_main into %r7/%r8 */
jmp 2(%r0) /* jump to entry point + 2 */
/*
* Lazy binding entry point, called via PLT.
*
* Note: Some functions rely on there not being an additional call frame;
* hence the `optimization' to avoid the callg opportunistically.
*/
ALTENTRY(_rtld_bind_start)
pushr $0x3f /* save R0-R5 */
movq 24(%sp),%r0 /* get addresses of plt.got & reloc index */
pushl (%r1) /* push relocation index */
pushl %r0 /* push address of obj entry */
calls $2,_rtld_bind
movl %r0,28(%sp) /* save return address onto stack */
bicw3 6(%fp),(%r0),%r0/* does the entry mask save any additional regs */
popr $0x3f /* restore R0-R5 (cond flags not modified) */
bneq 4f /* yes? do it the hard way */
addl2 $4,%sp /* no? skip past plt.got on stack */
addl2 $2,(%sp) /* skip past the mask */
rsb /* and jump to it */
4: addl2 $4,%sp
callg (%ap),*(%sp)+ /* return value from _rtld_bind() == actual */
ret

View File

@@ -0,0 +1,10 @@
# $NetBSD: Makefile.inc,v 1.7 2005/06/04 16:17:17 lukem Exp $
SRCS+= rtld_start.S mdreloc.c
# XXX Should not be in CPPFLAGS!
CPPFLAGS+= -fPIC
CPPFLAGS+= -DELFSIZE=64
LDFLAGS+= -Wl,-e,.rtld_start

View File

@@ -0,0 +1,311 @@
/* $NetBSD: mdreloc.c,v 1.38 2010/08/06 16:33:19 joerg Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Frank van der Linden for Wasabi Systems, Inc.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
* 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.
*/
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: mdreloc.c,v 1.38 2010/08/06 16:33:19 joerg Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <elf.h>
#include "debug.h"
#include "rtld.h"
void _rtld_bind_start(void);
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
static inline int _rtld_relocate_plt_object(const Obj_Entry *,
const Elf_Rela *, Elf_Addr *);
void
_rtld_setup_pltgot(const Obj_Entry *obj)
{
obj->pltgot[1] = (Elf_Addr) obj;
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
}
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rela *rela = 0, *relalim;
Elf_Addr relasz = 0;
Elf_Addr *where;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_RELA:
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
}
}
/*
* Assume only 64-bit relocations here, which should always
* be true for the dynamic linker.
*/
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
for (; rela < relalim; rela++) {
where = (Elf_Addr *)(relocbase + rela->r_offset);
*where = (Elf_Addr)(relocbase + rela->r_addend);
}
}
int
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
{
const Elf_Rela *rela;
const Elf_Sym *def = NULL;
const Obj_Entry *defobj =NULL;
for (rela = obj->rela; rela < obj->relalim; rela++) {
Elf64_Addr *where64;
Elf32_Addr *where32;
Elf64_Addr tmp64;
Elf32_Addr tmp32;
unsigned long symnum;
where64 = (Elf64_Addr *)(obj->relocbase + rela->r_offset);
where32 = (Elf32_Addr *)where64;
symnum = ELF_R_SYM(rela->r_info);
switch (ELF_R_TYPE(rela->r_info)) {
case R_TYPE(NONE):
break;
case R_TYPE(32): /* word32 S + A, truncate */
case R_TYPE(32S): /* word32 S + A, signed truncate */
case R_TYPE(GOT32): /* word32 G + A (XXX can we see these?) */
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
tmp32 = (Elf32_Addr)(u_long)(defobj->relocbase +
def->st_value + rela->r_addend);
if (*where32 != tmp32)
*where32 = tmp32;
rdbg(("32/32S %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)(unsigned long)*where32,
defobj->path));
break;
case R_TYPE(64): /* word64 S + A */
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
tmp64 = (Elf64_Addr)(defobj->relocbase + def->st_value +
rela->r_addend);
if (*where64 != tmp64)
*where64 = tmp64;
rdbg(("64 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where64, defobj->path));
break;
case R_TYPE(PC32): /* word32 S + A - P */
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
tmp32 = (Elf32_Addr)(u_long)(defobj->relocbase +
def->st_value + rela->r_addend -
(Elf64_Addr)where64);
if (*where32 != tmp32)
*where32 = tmp32;
rdbg(("PC32 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)(unsigned long)*where32,
defobj->path));
break;
case R_TYPE(GLOB_DAT): /* word64 S */
def = _rtld_find_symdef(symnum, obj, &defobj, false);
if (def == NULL)
return -1;
tmp64 = (Elf64_Addr)(defobj->relocbase + def->st_value);
if (*where64 != tmp64)
*where64 = tmp64;
rdbg(("64 %s in %s --> %p in %s",
obj->strtab + obj->symtab[symnum].st_name,
obj->path, (void *)*where64, defobj->path));
break;
case R_TYPE(RELATIVE): /* word64 B + A */
tmp64 = (Elf64_Addr)(obj->relocbase + rela->r_addend);
if (*where64 != tmp64)
*where64 = tmp64;
rdbg(("RELATIVE in %s --> %p", obj->path,
(void *)*where64));
break;
case R_TYPE(COPY):
rdbg(("COPY"));
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 *)*where64,
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;
if (!obj->relocbase)
return 0;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT));
/* Just relocate the GOT slots pointing into the PLT */
*where += (Elf_Addr)obj->relocbase;
rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
}
return 0;
}
static inline int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp)
{
Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
Elf_Addr new_value;
const Elf_Sym *def;
const Obj_Entry *defobj;
unsigned long info = rela->r_info;
assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT));
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;
new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
rela->r_addend);
rdbg(("bind now/fixup in %s --> old=%p new=%p",
defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
if (*where != new_value)
*where = new_value;
if (tp)
*tp = new_value - rela->r_addend;
return 0;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rela *rela = obj->pltrela + reloff;
Elf_Addr new_value;
int error;
new_value = 0; /* XXX GCC4 */
error = _rtld_relocate_plt_object(obj, rela, &new_value);
if (error)
_rtld_die();
return (caddr_t)new_value;
}
int
_rtld_relocate_plt_objects(const Obj_Entry *obj)
{
const Elf_Rela *rela;
for (rela = obj->pltrela; rela < obj->pltrelalim; rela++)
if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
return -1;
return 0;
}

View File

@@ -0,0 +1,105 @@
/* $NetBSD: rtld_start.S,v 1.8 2010/12/05 00:56:07 joerg Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Frank van der Linden for Wasabi Systems, Inc.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
* 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>
.text
.align 16
.globl .rtld_start
.hidden .rtld_start
.type .rtld_start,@function
.rtld_start:
subq $16,%rsp # make room of obj_main and exit proc
movq %rsp,%r12 # stack pointer arg to _rtld
pushq %rbx # save ps_strings
leaq _GLOBAL_OFFSET_TABLE_(%rip),%rax
leaq _DYNAMIC(%rip),%rdi # &_DYNAMIC
movq %rdi,%rbx
subq (%rax),%rbx # relocbase
movq %rbx,%rsi
call _rtld_relocate_nonplt_self
movq %r12,%rdi
movq %rbx,%rsi
call _rtld # _rtld(sp, relocbase)
popq %rbx # %rbx = ps_strings
popq %rdx # %rdx = cleanup
popq %rcx # %rcx = obj_main
jmp *%rax
.align 4
.globl _rtld_bind_start
.hidden _rtld_bind_start
.type _rtld_bind_start,@function
_rtld_bind_start: # (obj, reloff)
# This function is called with a misaligned stack from the PLT
# due to the additional argument pushed.
# At this point %rsp % 16 == 8.
pushfq # save caller-saved registers
pushq %rax
pushq %rcx
pushq %rdx
pushq %rsi
pushq %rdi
pushq %r8
pushq %r9
pushq %r10
pushq %r11
movq 80(%rsp),%rdi
movq 88(%rsp),%rsi
call _rtld_bind # call the binder
movq %rax,88(%rsp) # store function in obj
popq %r11
popq %r10
popq %r9
popq %r8
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %rax
popfq
leaq 8(%rsp),%rsp
ret

64
libexec/ld.elf_so/debug.c Normal file
View File

@@ -0,0 +1,64 @@
/* $NetBSD: debug.c,v 1.6 2004/10/22 05:39:56 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Support for printing debugging messages.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: debug.c,v 1.6 2004/10/22 05:39:56 skrll Exp $");
#endif /* not lint */
#include <stdarg.h>
#include "debug.h"
#include "rtldenv.h"
#ifdef DEBUG
int debug = 0;
void
debug_printf(const char *format, ...)
{
if (debug) {
va_list ap;
va_start(ap, format);
xvprintf(format, ap);
va_end(ap);
xprintf("\n");
}
}
#endif

58
libexec/ld.elf_so/debug.h Normal file
View File

@@ -0,0 +1,58 @@
/* $NetBSD: debug.h,v 1.5 2002/09/12 22:56:28 mycroft Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Support for printing debugging messages.
*/
#ifndef DEBUG_H
#define DEBUG_H
#ifdef DEBUG
extern void debug_printf __P((const char *, ...))
__attribute__((__format__(__printf__, 1, 2)));
extern int debug;
# define dbg(a) debug_printf a
#else
# define dbg(a) ((void) 0)
#endif
#ifdef RTLD_DEBUG_RELOC
# define rdbg(a) debug_printf a
#else
# define rdbg(a) ((void) 0)
#endif
#endif

172
libexec/ld.elf_so/expand.c Normal file
View File

@@ -0,0 +1,172 @@
/* $NetBSD: expand.c,v 1.5 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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: expand.c,v 1.5 2008/04/28 20:23:03 martin Exp $");
#endif /* not lint */
#include <ctype.h>
#include <string.h>
#include <sys/sysctl.h>
#ifdef DEBUG_EXPAND
#include <stdio.h>
#include <err.h>
#define xwarn warn
#define xerr err
size_t _rtld_expand_path(char *, size_t, const char *, const char *,
const char *);
#else
#include <sys/stat.h>
#include "rtld.h"
#endif
static const struct {
const char *name;
size_t namelen;
} bltn[] = {
#define ADD(a) { #a, sizeof(#a) - 1 },
ADD(HWCAP) /* SSE, MMX, etc */
ADD(ISALIST) /* XXX */
ADD(ORIGIN) /* dirname argv[0] */
ADD(OSNAME) /* uname -s */
ADD(OSREL) /* uname -r */
ADD(PLATFORM) /* uname -p */
};
static int mib[3][2] = {
{ CTL_KERN, KERN_OSTYPE },
{ CTL_KERN, KERN_OSRELEASE },
{ CTL_HW, HW_MACHINE_ARCH },
};
static size_t
expand(char *buf, const char *execname, int what, size_t bl)
{
const char *p, *ep;
char *bp = buf;
size_t len;
char name[32];
switch (what) {
case 0: /* HWCAP XXX: Not yet */
case 1: /* ISALIST XXX: Not yet */
return 0;
case 2: /* ORIGIN */
if (execname == NULL)
xerr(1, "execname not specified in AUX vector");
if ((ep = strrchr(p = execname, '/')) == NULL)
xerr(1, "bad execname `%s' in AUX vector", execname);
break;
case 3: /* OSNAME */
case 4: /* OSREL */
case 5: /* PLATFORM */
len = sizeof(name);
if (sysctl(mib[what - 3], 2, name, &len, NULL, 0) == -1) {
xwarn("sysctl");
return 0;
}
ep = (p = name) + len - 1;
break;
default:
return 0;
}
while (p != ep && bl)
*bp++ = *p++, bl--;
return bp - buf;
}
size_t
_rtld_expand_path(char *buf, size_t bufsize, const char *execname,
const char *bp, const char *ep)
{
size_t i, ds = bufsize;
char *dp = buf;
const char *p;
int br;
for (p = bp; p < ep;) {
if (*p == '$') {
br = *++p == '{';
if (br)
p++;
for (i = 0; i < sizeof(bltn) / sizeof(bltn[0]); i++) {
size_t s = bltn[i].namelen;
const char *es = p + s;
if ((br && *es != '}') ||
(!br && (es != ep &&
isalpha((unsigned char)*es))))
continue;
if (strncmp(bltn[i].name, p, s) == 0) {
size_t ls = expand(dp, execname, i, ds);
if (ls >= ds)
return bufsize;
ds -= ls;
dp += ls;
p = es + br;
goto done;
}
}
p -= br + 1;
}
*dp++ = *p++;
ds--;
done:;
}
*dp = '\0';
return dp - buf;
}
#ifdef DEBUG_EXPAND
int
main(int argc, char *argv[])
{
char buf[1024];
size_t i;
for (i = 1; i < argc; i++) {
char *p = argv[i], *ep = argv[i] + strlen(p);
size_t n = _rtld_expand_path(buf, sizeof(buf), argv[0], p, ep);
printf("%s\n", buf);
}
return 0;
}
#endif

369
libexec/ld.elf_so/headers.c Normal file
View File

@@ -0,0 +1,369 @@
/* $NetBSD: headers.c,v 1.39 2011/01/16 01:22:29 matt Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: headers.c,v 1.39 2011/01/16 01:22:29 matt Exp $");
#endif /* not lint */
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/bitops.h>
#include <dirent.h>
#include "debug.h"
#include "rtld.h"
/*
* Process a shared object's DYNAMIC section, and save the important
* information in its Obj_Entry structure.
*/
void
_rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
{
Elf_Dyn *dynp;
Needed_Entry **needed_tail = &obj->needed;
const Elf_Dyn *dyn_rpath = NULL;
bool use_pltrel = false;
bool use_pltrela = false;
Elf_Addr relsz = 0, relasz = 0;
Elf_Addr pltrel = 0, pltrelsz = 0;
Elf_Addr init = 0, fini = 0;
for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
switch (dynp->d_tag) {
case DT_REL:
obj->rel = (const Elf_Rel *)
(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_RELSZ:
relsz = dynp->d_un.d_val;
break;
case DT_RELENT:
assert(dynp->d_un.d_val == sizeof(Elf_Rel));
break;
case DT_JMPREL:
pltrel = dynp->d_un.d_ptr;
break;
case DT_PLTRELSZ:
pltrelsz = dynp->d_un.d_val;
break;
case DT_RELA:
obj->rela = (const Elf_Rela *)
(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
relasz = dynp->d_un.d_val;
break;
case DT_RELAENT:
assert(dynp->d_un.d_val == sizeof(Elf_Rela));
break;
case DT_PLTREL:
use_pltrel = dynp->d_un.d_val == DT_REL;
use_pltrela = dynp->d_un.d_val == DT_RELA;
assert(use_pltrel || use_pltrela);
break;
case DT_SYMTAB:
obj->symtab = (const Elf_Sym *)
(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_SYMENT:
assert(dynp->d_un.d_val == sizeof(Elf_Sym));
break;
case DT_STRTAB:
obj->strtab = (const char *)
(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_STRSZ:
obj->strsize = dynp->d_un.d_val;
break;
case DT_HASH:
{
const Elf_Symindx *hashtab = (const Elf_Symindx *)
(obj->relocbase + dynp->d_un.d_ptr);
if (hashtab[0] > UINT32_MAX)
obj->nbuckets = UINT32_MAX;
else
obj->nbuckets = hashtab[0];
obj->nchains = hashtab[1];
obj->buckets = hashtab + 2;
obj->chains = obj->buckets + obj->nbuckets;
/*
* Should really be in _rtld_relocate_objects,
* but _rtld_symlook_obj might be used before.
*/
if (obj->nbuckets) {
fast_divide32_prepare(obj->nbuckets,
&obj->nbuckets_m,
&obj->nbuckets_s1,
&obj->nbuckets_s2);
}
}
break;
case DT_NEEDED:
{
Needed_Entry *nep = NEW(Needed_Entry);
nep->name = dynp->d_un.d_val;
nep->obj = NULL;
nep->next = NULL;
*needed_tail = nep;
needed_tail = &nep->next;
}
break;
case DT_PLTGOT:
obj->pltgot = (Elf_Addr *)
(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_TEXTREL:
obj->textrel = true;
break;
case DT_SYMBOLIC:
obj->symbolic = true;
break;
case DT_RPATH:
/*
* We have to wait until later to process this, because
* we might not have gotten the address of the string
* table yet.
*/
dyn_rpath = dynp;
break;
case DT_SONAME:
/* Not used by the dynamic linker. */
break;
case DT_INIT:
init = dynp->d_un.d_ptr;
break;
case DT_FINI:
fini = dynp->d_un.d_ptr;
break;
/*
* Don't process DT_DEBUG on MIPS as the dynamic section
* is mapped read-only. DT_MIPS_RLD_MAP is used instead.
* XXX: n32/n64 may use DT_DEBUG, not sure yet.
*/
#ifndef __mips__
case DT_DEBUG:
#ifdef RTLD_LOADER
dynp->d_un.d_ptr = (Elf_Addr)&_rtld_debug;
#endif
break;
#endif
#ifdef __mips__
case DT_MIPS_LOCAL_GOTNO:
obj->local_gotno = dynp->d_un.d_val;
break;
case DT_MIPS_SYMTABNO:
obj->symtabno = dynp->d_un.d_val;
break;
case DT_MIPS_GOTSYM:
obj->gotsym = dynp->d_un.d_val;
break;
case DT_MIPS_RLD_MAP:
#ifdef RTLD_LOADER
*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr)
&_rtld_debug;
#endif
break;
#endif
#ifdef __powerpc__
case DT_PPC_GOT:
obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
break;
#endif
case DT_FLAGS_1:
obj->z_now =
((dynp->d_un.d_val & DF_1_BIND_NOW) != 0);
obj->z_nodelete =
((dynp->d_un.d_val & DF_1_NODELETE) != 0);
obj->z_initfirst =
((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
obj->z_noopen =
((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
break;
}
}
obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
if (use_pltrel) {
obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + pltrelsz);
obj->pltrelalim = 0;
/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
Trim rel(a)lim to save time later. */
if (obj->rellim && obj->pltrel &&
obj->rellim > obj->pltrel &&
obj->rellim <= obj->pltrellim)
obj->rellim = obj->pltrel;
} else if (use_pltrela) {
obj->pltrela = (const Elf_Rela *)(obj->relocbase + pltrel);
obj->pltrellim = 0;
obj->pltrelalim = (const Elf_Rela *)(obj->relocbase + pltrel + pltrelsz);
/* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
Trim rel(a)lim to save time later. */
if (obj->relalim && obj->pltrela &&
obj->relalim > obj->pltrela &&
obj->relalim <= obj->pltrelalim)
obj->relalim = obj->pltrela;
}
#if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
if (init != 0)
obj->init = (void (*)(void))
_rtld_function_descriptor_alloc(obj, NULL, init);
if (fini != 0)
obj->fini = (void (*)(void))
_rtld_function_descriptor_alloc(obj, NULL, fini);
#else
if (init != 0)
obj->init = (void (*)(void))
(obj->relocbase + init);
if (fini != 0)
obj->fini = (void (*)(void))
(obj->relocbase + fini);
#endif
if (dyn_rpath != NULL) {
_rtld_add_paths(execname, &obj->rpaths, obj->strtab +
dyn_rpath->d_un.d_val);
}
}
/*
* Process a shared object's program header. This is used only for the
* main program, when the kernel has already loaded the main program
* into memory before calling the dynamic linker. It creates and
* returns an Obj_Entry structure.
*/
Obj_Entry *
_rtld_digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
{
Obj_Entry *obj;
const Elf_Phdr *phlimit = phdr + phnum;
const Elf_Phdr *ph;
int nsegs = 0;
Elf_Addr vaddr;
obj = _rtld_obj_new();
for (ph = phdr; ph < phlimit; ++ph) {
if (ph->p_type != PT_PHDR)
continue;
obj->phdr = (void *)(uintptr_t)phdr->p_vaddr;
obj->phsize = phdr->p_memsz;
obj->relocbase = (caddr_t)((uintptr_t)phdr - (uintptr_t)ph->p_vaddr);
dbg(("headers: phdr %p phsize %zu relocbase %lx", obj->phdr,
obj->phsize, (long)obj->relocbase));
break;
}
assert(obj->phdr == phdr);
for (ph = phdr; ph < phlimit; ++ph) {
vaddr = (Elf_Addr)(uintptr_t)(obj->relocbase + ph->p_vaddr);
switch (ph->p_type) {
case PT_INTERP:
obj->interp = (const char *)(uintptr_t)vaddr;
break;
case PT_LOAD:
assert(nsegs < 2);
if (nsegs == 0) { /* First load segment */
obj->vaddrbase = round_down(vaddr);
obj->mapbase = (caddr_t)(uintptr_t)obj->vaddrbase;
obj->textsize = round_up(vaddr + ph->p_memsz) -
obj->vaddrbase;
} else { /* Last load segment */
obj->mapsize = round_up(vaddr + ph->p_memsz) -
obj->vaddrbase;
}
++nsegs;
break;
case PT_DYNAMIC:
obj->dynamic = (Elf_Dyn *)(uintptr_t)vaddr;
break;
}
}
assert(nsegs == 2);
obj->entry = entry;
return obj;
}

View File

@@ -0,0 +1,224 @@
.\" $NetBSD: ld.elf_so.1,v 1.15 2010/12/17 08:50:26 wiz Exp $
.\"
.\" Copyright (c) 2001 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by 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.
.\"
.Dd December 17, 2010
.Dt LD.ELF_SO 1
.Os
.Sh NAME
.Nm ld.elf_so
.Nd run-time link-editor (linker)
.Sh DESCRIPTION
.Nm
is a self-contained, position independent program
image providing run-time support for loading and
link-editing shared objects into a process' address space.
It uses information stored in data structures within the binary (see
.Xr elf 5 )
and environment variables to determine which shared objects are needed.
These shared objects are loaded at a convenient virtual address using the
.Xr mmap 2
system call.
After all shared objects have been successfully loaded,
.Nm
proceeds to resolve external references from both
the main program and all objects loaded.
Once all required references are resolved control is
passed to the program via its entry point.
.Ss Startup
On the execution of a dynamically linked binary the kernel will load
the program and its run-time linker as specified in the PT_INTERP
section in the program header.
At this point, instead of passing control directly to the program,
the kernel passes control to the specified linker.
An auxiliary vector of information is passed that includes
the address of the program header, the size of each entry in the header,
and the number of entries.
The entry point of the program and the base address of where
.Nm
is loaded is also supplied.
.Ss Finding objects
Each
.Xr elf 5
object file may contain information in its dynamic (PT_DYNAMIC) section
about which shared objects it requires (often referred to as dependencies).
These dependencies are specified in the optional DT_NEEDED entry within
the dynamic section.
Each DT_NEEDED entry refers to a filename string of
the shared object that is to be searched for.
.Pp
The linker will search for libraries in three lists of paths:
.Bl -enum
.It
A user defined list of paths as specified in LD_LIBRARY_PATH and
.Xr ld.so.conf 5 .
.Pp
The use of ld.so.conf should be avoided as the setting of a global search
path can present a security risk.
.It
A list of paths specified within a shared object using a DT_RPATH entry in
the dynamic section.
This is defined at shared object link time.
.It
The list of default paths which is set to
.Pa /usr/lib .
.El
.Pp
.Nm
will expand the following variables if present in the paths:
.Bl -tag -width $PLATFORM
.It $HWCAP
Processor hardware capabilities, for example FPU, MMX, SSE.
Currently unimplemented.
.It $ISALIST
List of instructions sets this processor can execute.
Currently unimplemented.
.It $ORIGIN
The directory of the main object.
Implemented in
.Nm
but the kernel support is currently disabled.
.It $OSNAME
The value of the
.Dv kern.ostype
.Xr sysctl 3 .
.It $OSREL
The value of the
.Dv kern.osrelease
.Xr sysctl 3 .
.It $PLATFORM
The value of the
.Dv hw.machine_arch
.Xr sysctl 3 .
.El
.Pp
Both
.Dv ${VARIABLE}
and
.Dv $VARIABLE
are recognized.
.Pp
The filename string can be considered free form, however, it will almost
always take the form lib\*[Lt]name\*[Gt].so.\*[Lt]number\*[Gt],
where name specifies the
.Sq library
name and number is conceptually the library's major version number.
.Pp
This name and another of the form lib\*[Lt]name\*[Gt].so are normally
symbolic links to the real shared object which has a filename of the form
lib\*[Lt]name\*[Gt].so.\*[Lt]major\*[Gt].\*[Lt]minor\*[Gt][.\*[Lt]teeny\*[Gt]].
This naming convention allows a versioning scheme similar to
.Xr a.out 5 .
.Ss Relocation
.Nm
will perform all necessary relocations immediately except for relocations
relating to the Procedure Linkage Table (PLT).
The PLT is used as a indirection method for procedure
calls to globally defined functions.
It allows, through the use of intermediate code, the delayed binding of
a call to a globally defined function to be performed at procedure call time.
This
.Sq lazy
method is the default (see LD_BIND_NOW).
.Ss Initialization
A mechanism is provided for initialization and termination routines
to be called, on a per-object basis before execution of the program proper
begins or after the program has completed.
This gives a shared object an opportunity to perform
any extra set-up or completion work.
.Pp
The DT_INIT and DT_FINI entries in the dynamic section specify the addresses
of the initialization and termination functions, respectively, for
the shared object.
.Nm
arranges for each initialization function to be called before control is passed
to the program and for the termination functions to be called by using
.Xr atexit 3 .
.Pp
This mechanism is exploited by the system-supplied constructor
initialization and destructor code located in
.Pa /usr/lib/crtbeginS.o
and
.Pa /usr/lib/crtendS.o .
These files are automatically included by
.Xr cc 1
and
.Xr c++ 1
in the list of object-code files passed to
.Xr ld 1
when building a shared C or C++ object.
.Sh ENVIRONMENT
If the following environment variables exist they will be used by
.Nm .
.Bl -tag -width "LD_LIBRARY_PATH"
.It Ev LD_LIBRARY_PATH
A colon separated list of directories, overriding the default search path
for shared libraries.
.It Ev LD_PRELOAD
A colon or space separated list of shared object filenames to be loaded
.Em after
the main program but
.Em before
its shared object dependencies.
Space is allowed as a separator for backwards compatibility only.
Support may be removed in a future release and should not be relied upon.
.It Ev LD_BIND_NOW
If defined immediate binding of Procedure Link Table (PLT) entries is
performed instead of the default lazy method.
.It Ev LD_DEBUG
If defined a variety of debug information will be written to the standard
error of an dynamically linked executed when it is run.
This variable is only recognized if
.Nm
was compiled with debugging support
.Sy ( -DDEBUG ) .
.El
.Sh FILES
.Bl -tag -width /etc/ld.so.conf -compact
.It Pa /etc/ld.so.conf
library location hints supplied by the system administrator.
.El
.Sh SEE ALSO
.Xr ld 1 ,
.Xr ld.aout_so 1 ,
.Xr dlfcn 3 ,
.Xr elf 5
.Sh HISTORY
The ELF shared library model employed first appeared in Sys V R4.
.Pp
The path expansion variables first appeared in Solaris 10, and
in
.Nx 5.0 .
.Sh SECURITY CONSIDERATIONS
The environment variables
.Ev LD_LIBRARY_PATH
and
.Ev LD_PRELOAD
are not honored when executing in a set-user-ID or set-group-ID environment.
This action is taken to prevent malicious substitution of shared object
dependencies or interposition of symbols.

350
libexec/ld.elf_so/load.c Normal file
View File

@@ -0,0 +1,350 @@
/* $NetBSD: load.c,v 1.42 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: load.c,v 1.42 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <dirent.h>
#include "debug.h"
#include "rtld.h"
static bool _rtld_load_by_name(const char *, Obj_Entry *, Needed_Entry **,
int);
#ifdef RTLD_LOADER
Objlist _rtld_list_main = /* Objects loaded at program startup */
SIMPLEQ_HEAD_INITIALIZER(_rtld_list_main);
Objlist _rtld_list_global = /* Objects dlopened with RTLD_GLOBAL */
SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global);
void
_rtld_objlist_push_head(Objlist *list, Obj_Entry *obj)
{
Objlist_Entry *elm;
elm = NEW(Objlist_Entry);
elm->obj = obj;
SIMPLEQ_INSERT_HEAD(list, elm, link);
}
void
_rtld_objlist_push_tail(Objlist *list, Obj_Entry *obj)
{
Objlist_Entry *elm;
elm = NEW(Objlist_Entry);
elm->obj = obj;
SIMPLEQ_INSERT_TAIL(list, elm, link);
}
Objlist_Entry *
_rtld_objlist_find(Objlist *list, const Obj_Entry *obj)
{
Objlist_Entry *elm;
SIMPLEQ_FOREACH(elm, list, link) {
if (elm->obj == obj)
return elm;
}
return NULL;
}
#endif
/*
* Load a shared object into memory, if it is not already loaded.
*
* Returns a pointer to the Obj_Entry for the object. Returns NULL
* on failure.
*/
Obj_Entry *
_rtld_load_object(const char *filepath, int flags)
{
Obj_Entry *obj;
int fd = -1;
struct stat sb;
size_t pathlen = strlen(filepath);
for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
if (pathlen == obj->pathlen && !strcmp(obj->path, filepath))
break;
/*
* If we didn't find a match by pathname, open the file and check
* again by device and inode. This avoids false mismatches caused
* by multiple links or ".." in pathnames.
*
* To avoid a race, we open the file and use fstat() rather than
* using stat().
*/
if (obj == NULL) {
if ((fd = open(filepath, O_RDONLY)) == -1) {
_rtld_error("Cannot open \"%s\"", filepath);
return NULL;
}
if (fstat(fd, &sb) == -1) {
_rtld_error("Cannot fstat \"%s\"", filepath);
close(fd);
return NULL;
}
for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) {
if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) {
close(fd);
break;
}
}
}
if (obj == NULL) { /* First use of this object, so we must map it in */
obj = _rtld_map_object(filepath, fd, &sb);
(void)close(fd);
if (obj == NULL)
return NULL;
_rtld_digest_dynamic(filepath, obj);
if (flags & _RTLD_DLOPEN) {
if (obj->z_noopen || (flags & _RTLD_NOLOAD)) {
dbg(("refusing to load non-loadable \"%s\"",
obj->path));
_rtld_error("Cannot dlopen non-loadable %s",
obj->path);
munmap(obj->mapbase, obj->mapsize);
_rtld_obj_free(obj);
return OBJ_ERR;
}
}
*_rtld_objtail = obj;
_rtld_objtail = &obj->next;
_rtld_objcount++;
_rtld_objloads++;
#ifdef RTLD_LOADER
_rtld_linkmap_add(obj); /* for GDB */
#endif
dbg((" %p .. %p: %s", obj->mapbase,
obj->mapbase + obj->mapsize - 1, obj->path));
if (obj->textrel)
dbg((" WARNING: %s has impure text", obj->path));
}
++obj->refcount;
#ifdef RTLD_LOADER
if (flags & _RTLD_MAIN && !obj->mainref) {
obj->mainref = 1;
dbg(("adding %p (%s) to _rtld_list_main", obj, obj->path));
_rtld_objlist_push_tail(&_rtld_list_main, obj);
}
if (flags & _RTLD_GLOBAL && !obj->globalref) {
obj->globalref = 1;
dbg(("adding %p (%s) to _rtld_list_global", obj, obj->path));
_rtld_objlist_push_tail(&_rtld_list_global, obj);
}
#endif
return obj;
}
static bool
_rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed,
int flags)
{
Library_Xform *x = _rtld_xforms;
Obj_Entry *o = NULL;
size_t j;
ssize_t i;
bool got = false;
union {
int i;
u_quad_t q;
char s[16];
} val;
dbg(("load by name %s %p", name, x));
for (; x; x = x->next) {
if (strcmp(x->name, name) != 0)
continue;
j = sizeof(val);
if ((i = _rtld_sysctl(x->ctlname, &val, &j)) == -1) {
xwarnx(_PATH_LD_HINTS ": invalid/unknown sysctl for %s (%d)",
name, errno);
break;
}
switch (i) {
case CTLTYPE_QUAD:
xsnprintf(val.s, sizeof(val.s), "%" PRIu64, val.q);
break;
case CTLTYPE_INT:
xsnprintf(val.s, sizeof(val.s), "%d", val.i);
break;
case CTLTYPE_STRING:
break;
default:
xwarnx("unsupported sysctl type %d", (int)i);
break;
}
dbg(("sysctl returns %s", val.s));
for (i = 0; i < RTLD_MAX_ENTRY && x->entry[i].value != NULL;
i++) {
dbg(("entry %ld", (unsigned long)i));
if (strcmp(x->entry[i].value, val.s) == 0)
break;
}
if (i == RTLD_MAX_ENTRY) {
xwarnx("sysctl value %s not found for lib%s",
val.s, name);
break;
}
for (j = 0; j < RTLD_MAX_LIBRARY &&
x->entry[i].library[j] != NULL; j++) {
o = _rtld_load_library(x->entry[i].library[j], obj,
flags);
if (o == NULL) {
xwarnx("could not load %s for %s",
x->entry[i].library[j], name);
continue;
}
got = true;
if (j == 0)
(*needed)->obj = o;
else {
/* make a new one and put it in the chain */
Needed_Entry *ne = xmalloc(sizeof(*ne));
ne->name = (*needed)->name;
ne->obj = o;
ne->next = (*needed)->next;
(*needed)->next = ne;
*needed = ne;
}
}
}
if (got)
return true;
return ((*needed)->obj = _rtld_load_library(name, obj, flags)) != NULL;
}
/*
* Given a shared object, traverse its list of needed objects, and load
* each of them. Returns 0 on success. Generates an error message and
* returns -1 on failure.
*/
int
_rtld_load_needed_objects(Obj_Entry *first, int flags)
{
Obj_Entry *obj;
int status = 0;
for (obj = first; obj != NULL; obj = obj->next) {
Needed_Entry *needed;
for (needed = obj->needed; needed != NULL;
needed = needed->next) {
const char *name = obj->strtab + needed->name;
#ifdef RTLD_LOADER
Obj_Entry *nobj;
#endif
if (!_rtld_load_by_name(name, obj, &needed,
flags & ~_RTLD_NOLOAD))
status = -1; /* FIXME - cleanup */
#ifdef RTLD_LOADER
if (status == -1)
return status;
if (flags & _RTLD_MAIN)
continue;
nobj = needed->obj;
if (nobj->z_nodelete && !obj->ref_nodel) {
dbg(("obj %s nodelete", nobj->path));
_rtld_ref_dag(nobj);
nobj->ref_nodel = true;
}
#endif
}
}
return status;
}
#ifdef RTLD_LOADER
int
_rtld_preload(const char *preload_path)
{
const char *path;
char *cp, *buf;
int status = 0;
if (preload_path != NULL && *preload_path != '\0') {
cp = buf = xstrdup(preload_path);
while ((path = strsep(&cp, " :")) != NULL && status == 0) {
if (!_rtld_load_object(path, _RTLD_MAIN))
status = -1;
else
dbg((" preloaded \"%s\"", path));
}
xfree(buf);
}
return status;
}
#endif

View File

@@ -0,0 +1,422 @@
/* $NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $");
#endif /* not lint */
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "debug.h"
#include "rtld.h"
static int protflags(int); /* Elf flags -> mmap protection */
#define EA_UNDEF (~(Elf_Addr)0)
/*
* Map a shared object into memory. The argument is a file descriptor,
* which must be open on the object and positioned at its beginning.
*
* The return value is a pointer to a newly-allocated Obj_Entry structure
* for the shared object. Returns NULL on failure.
*/
Obj_Entry *
_rtld_map_object(const char *path, int fd, const struct stat *sb)
{
Obj_Entry *obj;
Elf_Ehdr *ehdr;
Elf_Phdr *phdr;
size_t phsize;
Elf_Phdr *phlimit;
Elf_Phdr *segs[2];
int nsegs;
caddr_t mapbase = MAP_FAILED;
size_t mapsize = 0;
int mapflags;
Elf_Off base_offset;
#ifdef MAP_ALIGNED
Elf_Addr base_alignment;
#endif
Elf_Addr base_vaddr;
Elf_Addr base_vlimit;
Elf_Addr text_vlimit;
int text_flags;
caddr_t base_addr;
Elf_Off data_offset;
Elf_Addr data_vaddr;
Elf_Addr data_vlimit;
int data_flags;
caddr_t data_addr;
Elf_Addr phdr_vaddr;
size_t phdr_memsz;
caddr_t gap_addr;
size_t gap_size;
int i;
#ifdef RTLD_LOADER
Elf_Addr clear_vaddr;
caddr_t clear_addr;
size_t nclear;
#endif
if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
_rtld_error("%s: unrecognized file format1", path);
return NULL;
}
obj = _rtld_obj_new();
obj->path = xstrdup(path);
obj->pathlen = strlen(path);
if (sb != NULL) {
obj->dev = sb->st_dev;
obj->ino = sb->st_ino;
}
ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd,
(off_t)0);
obj->ehdr = ehdr;
if (ehdr == MAP_FAILED) {
_rtld_error("%s: read error: %s", path, xstrerror(errno));
goto bad;
}
/* Make sure the file is valid */
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
ehdr->e_ident[EI_CLASS] != ELFCLASS) {
_rtld_error("%s: unrecognized file format2 [%x != %x]", path,
ehdr->e_ident[EI_CLASS], ELFCLASS);
goto bad;
}
/* Elf_e_ident includes class */
if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
ehdr->e_version != EV_CURRENT ||
ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
_rtld_error("%s: unsupported file version", path);
goto bad;
}
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
_rtld_error("%s: unsupported file type", path);
goto bad;
}
switch (ehdr->e_machine) {
ELFDEFNNAME(MACHDEP_ID_CASES)
default:
_rtld_error("%s: unsupported machine", path);
goto bad;
}
/*
* We rely on the program header being in the first page. This is
* not strictly required by the ABI specification, but it seems to
* always true in practice. And, it simplifies things considerably.
*/
assert(ehdr->e_phentsize == sizeof(Elf_Phdr));
assert(ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf_Phdr) <=
_rtld_pagesz);
/*
* Scan the program header entries, and save key information.
*
* We rely on there being exactly two load segments, text and data,
* in that order.
*/
phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
phsize = ehdr->e_phnum * sizeof(phdr[0]);
obj->phdr = NULL;
phdr_vaddr = EA_UNDEF;
phdr_memsz = 0;
phlimit = phdr + ehdr->e_phnum;
nsegs = 0;
while (phdr < phlimit) {
switch (phdr->p_type) {
case PT_INTERP:
obj->interp = (void *)(uintptr_t)phdr->p_vaddr;
dbg(("%s: PT_INTERP %p", obj->path, obj->interp));
break;
case PT_LOAD:
if (nsegs < 2)
segs[nsegs] = phdr;
++nsegs;
dbg(("%s: PT_LOAD %p", obj->path, phdr));
break;
case PT_PHDR:
phdr_vaddr = phdr->p_vaddr;
phdr_memsz = phdr->p_memsz;
dbg(("%s: PT_PHDR %p phsize %zu", obj->path,
(void *)(uintptr_t)phdr_vaddr, phdr_memsz));
break;
case PT_DYNAMIC:
obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
dbg(("%s: PT_DYNAMIC %p", obj->path, obj->dynamic));
break;
}
++phdr;
}
phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
obj->entry = (void *)(uintptr_t)ehdr->e_entry;
if (!obj->dynamic) {
_rtld_error("%s: not dynamically linked", path);
goto bad;
}
if (nsegs != 2) {
_rtld_error("%s: wrong number of segments (%d != 2)", path,
nsegs);
goto bad;
}
/*
* Map the entire address space of the object as a file
* region to stake out our contiguous region and establish a
* base for relocation. We use a file mapping so that
* the kernel will give us whatever alignment is appropriate
* for the platform we're running on.
*
* We map it using the text protection, map the data segment
* into the right place, then map an anon segment for the bss
* and unmap the gaps left by padding to alignment.
*/
#ifdef MAP_ALIGNED
base_alignment = segs[0]->p_align;
#endif
base_offset = round_down(segs[0]->p_offset);
base_vaddr = round_down(segs[0]->p_vaddr);
base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
text_flags = protflags(segs[0]->p_flags);
data_offset = round_down(segs[1]->p_offset);
data_vaddr = round_down(segs[1]->p_vaddr);
data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz);
data_flags = protflags(segs[1]->p_flags);
#ifdef RTLD_LOADER
clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
#endif
obj->textsize = text_vlimit - base_vaddr;
obj->vaddrbase = base_vaddr;
obj->isdynamic = ehdr->e_type == ET_DYN;
obj->phdr_loaded = false;
for (i = 0; i < nsegs; i++) {
if (phdr_vaddr != EA_UNDEF &&
segs[i]->p_vaddr <= phdr_vaddr &&
segs[i]->p_memsz >= phdr_memsz) {
obj->phdr_loaded = true;
break;
}
if (segs[i]->p_offset <= ehdr->e_phoff &&
segs[i]->p_memsz >= phsize) {
phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff;
phdr_memsz = phsize;
obj->phdr_loaded = true;
break;
}
}
if (obj->phdr_loaded) {
obj->phdr = (void *)(uintptr_t)phdr_vaddr;
obj->phsize = phdr_memsz;
} else {
Elf_Phdr *buf;
buf = xmalloc(phsize);
if (buf == NULL) {
_rtld_error("%s: cannot allocate program header", path);
goto bad;
}
memcpy(buf, phdr, phsize);
obj->phdr = buf;
obj->phsize = phsize;
}
dbg(("%s: phdr %p phsize %zu (%s)", obj->path, obj->phdr, obj->phsize,
obj->phdr_loaded ? "loaded" : "allocated"));
/* Unmap header if it overlaps the first load section. */
if (base_offset < _rtld_pagesz) {
munmap(ehdr, _rtld_pagesz);
obj->ehdr = MAP_FAILED;
}
/*
* Calculate log2 of the base section alignment.
*/
mapflags = 0;
#ifdef MAP_ALIGNED
if (base_alignment > _rtld_pagesz) {
unsigned int log2 = 0;
for (; base_alignment > 1; base_alignment >>= 1)
log2++;
mapflags = MAP_ALIGNED(log2);
}
#endif
#ifdef RTLD_LOADER
base_addr = obj->isdynamic ? NULL : (caddr_t)base_vaddr;
#else
base_addr = NULL;
#endif
mapsize = base_vlimit - base_vaddr;
mapbase = mmap(base_addr, mapsize, text_flags,
mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset);
if (mapbase == MAP_FAILED) {
_rtld_error("mmap of entire address space failed: %s",
xstrerror(errno));
goto bad;
}
/* Overlay the data segment onto the proper region. */
data_addr = mapbase + (data_vaddr - base_vaddr);
if (mmap(data_addr, data_vlimit - data_vaddr, data_flags,
MAP_FILE | MAP_PRIVATE | MAP_FIXED, fd, data_offset) ==
MAP_FAILED) {
_rtld_error("mmap of data failed: %s", xstrerror(errno));
goto bad;
}
/* Overlay the bss segment onto the proper region. */
if (mmap(mapbase + data_vlimit - base_vaddr, base_vlimit - data_vlimit,
data_flags, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) ==
MAP_FAILED) {
_rtld_error("mmap of bss failed: %s", xstrerror(errno));
goto bad;
}
/* Unmap the gap between the text and data. */
gap_addr = mapbase + round_up(text_vlimit - base_vaddr);
gap_size = data_addr - gap_addr;
if (gap_size != 0 && mprotect(gap_addr, gap_size, PROT_NONE) == -1) {
_rtld_error("mprotect of text -> data gap failed: %s",
xstrerror(errno));
goto bad;
}
#ifdef RTLD_LOADER
/* Clear any BSS in the last page of the data segment. */
clear_addr = mapbase + (clear_vaddr - base_vaddr);
if ((nclear = data_vlimit - clear_vaddr) > 0)
memset(clear_addr, 0, nclear);
/* Non-file portion of BSS mapped above. */
#endif
obj->mapbase = mapbase;
obj->mapsize = mapsize;
obj->relocbase = mapbase - base_vaddr;
if (obj->dynamic)
obj->dynamic = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->dynamic);
if (obj->entry)
obj->entry = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->entry);
if (obj->interp)
obj->interp = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->interp);
if (obj->phdr_loaded)
obj->phdr = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->phdr);
return obj;
bad:
if (obj->ehdr != MAP_FAILED)
munmap(obj->ehdr, _rtld_pagesz);
if (mapbase != MAP_FAILED)
munmap(mapbase, mapsize);
_rtld_obj_free(obj);
return NULL;
}
void
_rtld_obj_free(Obj_Entry *obj)
{
Objlist_Entry *elm;
xfree(obj->path);
while (obj->needed != NULL) {
Needed_Entry *needed = obj->needed;
obj->needed = needed->next;
xfree(needed);
}
while ((elm = SIMPLEQ_FIRST(&obj->dldags)) != NULL) {
SIMPLEQ_REMOVE_HEAD(&obj->dldags, link);
xfree(elm);
}
while ((elm = SIMPLEQ_FIRST(&obj->dagmembers)) != NULL) {
SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, link);
xfree(elm);
}
if (!obj->phdr_loaded)
xfree((void *)(uintptr_t)obj->phdr);
xfree(obj);
#ifdef COMBRELOC
_rtld_combreloc_reset(obj);
#endif
}
Obj_Entry *
_rtld_obj_new(void)
{
Obj_Entry *obj;
obj = CNEW(Obj_Entry);
SIMPLEQ_INIT(&obj->dldags);
SIMPLEQ_INIT(&obj->dagmembers);
return obj;
}
/*
* Given a set of ELF protection flags, return the corresponding protection
* flags for MMAP.
*/
static int
protflags(int elfflags)
{
int prot = 0;
if (elfflags & PF_R)
prot |= PROT_READ;
#ifdef RTLD_LOADER
if (elfflags & PF_W)
prot |= PROT_WRITE;
#endif
if (elfflags & PF_X)
prot |= PROT_EXEC;
return prot;
}

478
libexec/ld.elf_so/paths.c Normal file
View File

@@ -0,0 +1,478 @@
/* $NetBSD: paths.c,v 1.40 2009/05/19 20:44:52 christos Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: paths.c,v 1.40 2009/05/19 20:44:52 christos Exp $");
#endif /* not lint */
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/gmon.h>
#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/mbuf.h>
#include <sys/resource.h>
#include <machine/cpu.h>
#include "debug.h"
#include "rtld.h"
static Search_Path *_rtld_find_path(Search_Path *, const char *, size_t);
static Search_Path **_rtld_append_path(Search_Path **, Search_Path **,
const char *, const char *, const char *);
static void _rtld_process_mapping(Library_Xform **, const char *,
const char *);
static char *exstrdup(const char *, const char *);
static const char *getstr(const char **, const char *, const char *);
static const char *getcstr(const char **, const char *, const char *);
static const char *getword(const char **, const char *, const char *);
static int matchstr(const char *, const char *, const char *);
static const char WS[] = " \t\n";
/*
* Like xstrdup(), but takes end of string as a argument.
*/
static char *
exstrdup(const char *bp, const char *ep)
{
char *cp;
size_t len = ep - bp;
cp = xmalloc(len + 1);
memcpy(cp, bp, len);
cp[len] = '\0';
return (cp);
}
/*
* Like strsep(), but takes end of string and doesn't put any NUL. To
* detect empty string, compare `*p' and return value.
*/
static const char *
getstr(const char **p, const char *ep, const char *delim)
{
const char *cp = *p, *q, *r;
if (ep < cp)
/* End of string */
return (NULL);
for (q = cp; q < ep; q++)
for (r = delim; *r != 0; r++)
if (*r == *q)
goto done;
done:
*p = q;
return (cp);
}
/*
* Like getstr() above, but delim[] is complemented.
*/
static const char *
getcstr(const char **p, const char *ep, const char *delim)
{
const char *cp = *p, *q, *r;
if (ep < cp)
/* End of string */
return (NULL);
for (q = cp; q < ep; q++)
for (r = delim; *r != *q; r++)
if (*r == 0)
goto done;
done:
*p = q;
return (cp);
}
static const char *
getword(const char **p, const char *ep, const char *delim)
{
(void)getcstr(p, ep, delim);
/*
* Now, we're looking non-delim, or end of string.
*/
return (getstr(p, ep, delim));
}
/*
* Match `bp' against NUL terminated string pointed by `p'.
*/
static int
matchstr(const char *p, const char *bp, const char *ep)
{
int c;
while (bp < ep)
if ((c = *p++) == 0 || c != *bp++)
return (0);
return (*p == 0);
}
static Search_Path *
_rtld_find_path(Search_Path *path, const char *pathstr, size_t pathlen)
{
for (; path != NULL; path = path->sp_next) {
if (pathlen == path->sp_pathlen &&
memcmp(path->sp_path, pathstr, pathlen) == 0)
return path;
}
return NULL;
}
static Search_Path **
_rtld_append_path(Search_Path **head_p, Search_Path **path_p,
const char *execname, const char *bp, const char *ep)
{
Search_Path *path;
char epath[MAXPATHLEN];
size_t len;
len = _rtld_expand_path(epath, sizeof(epath), execname, bp, ep);
if (len == 0)
return path_p;
if (_rtld_find_path(*head_p, bp, ep - bp) != NULL)
return path_p;
path = NEW(Search_Path);
path->sp_pathlen = len;
path->sp_path = exstrdup(epath, epath + len);
path->sp_next = (*path_p);
(*path_p) = path;
path_p = &path->sp_next;
dbg((" added path \"%s\"", path->sp_path));
return path_p;
}
void
_rtld_add_paths(const char *execname, Search_Path **path_p, const char *pathstr)
{
Search_Path **head_p = path_p;
if (pathstr == NULL)
return;
if (pathstr[0] == ':') {
/*
* Leading colon means append to current path
*/
while ((*path_p) != NULL)
path_p = &(*path_p)->sp_next;
pathstr++;
}
for (;;) {
const char *bp = pathstr;
const char *ep = strchr(bp, ':');
if (ep == NULL)
ep = &pathstr[strlen(pathstr)];
path_p = _rtld_append_path(head_p, path_p, execname, bp, ep);
if (ep[0] == '\0')
break;
pathstr = ep + 1;
}
}
/*
* Process library mappings of the form:
* <library_name> <machdep_variable> <value,...:library_name,...> ...
*/
static void
_rtld_process_mapping(Library_Xform **lib_p, const char *bp, const char *ep)
{
Library_Xform *hwptr = NULL;
const char *ptr, *key, *ekey, *lib, *elib, *l;
int i, j;
dbg((" processing mapping \"%.*s\"", (int)(ep - bp), bp));
if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp)
return;
dbg((" library \"%.*s\"", (int)(bp - ptr), ptr));
hwptr = xmalloc(sizeof(*hwptr));
memset(hwptr, 0, sizeof(*hwptr));
hwptr->name = exstrdup(ptr, bp);
bp++;
if ((ptr = getword(&bp, ep, WS)) == NULL || ptr == bp) {
xwarnx("missing sysctl variable name");
goto cleanup;
}
dbg((" sysctl \"%.*s\"", (int)(bp - ptr), ptr));
hwptr->ctlname = exstrdup(ptr, bp);
for (i = 0; bp++, (ptr = getword(&bp, ep, WS)) != NULL;) {
dbg((" ptr = %.*s", (int)(bp - ptr), ptr));
if (ptr == bp)
continue;
if (i == RTLD_MAX_ENTRY) {
no_more:
xwarnx("maximum library entries exceeded `%s'",
hwptr->name);
goto cleanup;
}
if ((key = getstr(&ptr, bp, ":")) == NULL) {
xwarnx("missing sysctl variable value for `%s'",
hwptr->name);
goto cleanup;
}
ekey = ptr++;
if ((lib = getstr(&ptr, bp, ":")) == NULL) {
xwarnx("missing sysctl library list for `%s'",
hwptr->name);
goto cleanup;
}
elib = ptr; /* No need to advance */
for (j = 0; (l = getstr(&lib, elib, ",")) != NULL;
j++, lib++) {
if (j == RTLD_MAX_LIBRARY) {
xwarnx("maximum library entries exceeded `%s'",
hwptr->name);
goto cleanup;
}
dbg((" library \"%.*s\"", (int)(lib - l), l));
hwptr->entry[i].library[j] = exstrdup(l, lib);
}
if (j == 0) {
xwarnx("No library map entries for `%s/%.*s'",
hwptr->name, (int)(bp - ptr), ptr);
goto cleanup;
}
j = i;
for (; (l = getstr(&key, ekey, ",")) != NULL; i++, key++) {
/*
* Allow empty key (it is valid as string
* value). Thus, we loop at least once and
* `i' is incremented.
*/
dbg((" key \"%.*s\"", (int)(key - l), l));
if (i == RTLD_MAX_ENTRY)
goto no_more;
if (i != j)
(void)memcpy(hwptr->entry[i].library,
hwptr->entry[j].library,
sizeof(hwptr->entry[j].library));
hwptr->entry[i].value = exstrdup(l, key);
}
}
if (i == 0) {
xwarnx("No library entries for `%s'", hwptr->name);
goto cleanup;
}
hwptr->next = *lib_p;
*lib_p = hwptr;
return;
cleanup:
if (hwptr->name)
xfree(hwptr->name);
xfree(hwptr);
}
void
_rtld_process_hints(const char *execname, Search_Path **path_p,
Library_Xform **lib_p, const char *fname)
{
int fd;
char *buf, small[128];
const char *b, *ep, *ptr;
struct stat st;
ssize_t sz;
Search_Path **head_p = path_p;
if ((fd = open(fname, O_RDONLY)) == -1) {
/* Don't complain */
return;
}
/* Try to avoid mmap/stat on the file. */
buf = small;
buf[0] = '\0';
sz = read(fd, buf, sizeof(small));
if (sz == -1) {
xwarn("read: %s", fname);
(void)close(fd);
return;
}
if (sz >= (ssize_t)sizeof(small)) {
if (fstat(fd, &st) == -1) {
/* Complain */
xwarn("fstat: %s", fname);
(void)close(fd);
return;
}
sz = (ssize_t) st.st_size;
buf = mmap(0, sz, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
if (buf == MAP_FAILED) {
xwarn("mmap: %s", fname);
(void)close(fd);
return;
}
}
(void)close(fd);
while ((*path_p) != NULL)
path_p = &(*path_p)->sp_next;
for (b = buf, ep = buf + sz; b < ep; b++) {
(void)getcstr(&b, ep, WS);
if (b == ep)
break;
ptr = getstr(&b, ep, "\n#");
if (*ptr == '/') {
/*
* Since '/' != '\n' and != '#', we know ptr <
* b. And we will stop when b[-1] == '/'.
*/
while (b[-1] == ' ' || b[-1] == '\t')
b--;
path_p = _rtld_append_path(head_p, path_p, execname,
ptr, b);
} else
_rtld_process_mapping(lib_p, ptr, b);
/*
* b points one of ' ', \t, \n, # or equal to ep. So,
* make sure we are at newline or end of string.
*/
(void)getstr(&b, ep, "\n");
}
if (buf != small)
(void)munmap(buf, sz);
}
/* Basic name -> sysctl MIB translation */
int
_rtld_sysctl(const char *name, void *oldp, size_t *oldlen)
{
const char *node, *ep;
struct sysctlnode query, *result, *newresult;
int mib[CTL_MAXNAME], r;
size_t res_size, n, i;
u_int miblen = 0;
/* Start with 16 entries, will grow it up as needed. */
res_size = 16 * sizeof(struct sysctlnode);
result = xmalloc(res_size);
if (result == NULL)
return (-1);
ep = name + strlen(name);
do {
i = ~0ul;
while (*name == '/' || *name == '.')
name++;
if (name >= ep)
break;
mib[miblen] = CTL_QUERY;
memset(&query, 0, sizeof(query));
query.sysctl_flags = SYSCTL_VERSION;
n = res_size;
if (sysctl(mib, miblen + 1, result, &n, &query,
sizeof(query)) == -1) {
if (errno != ENOMEM)
goto bad;
/* Grow up result */
res_size = n;
newresult = xrealloc(result, res_size);
if (newresult == NULL)
goto bad;
result = newresult;
if (sysctl(mib, miblen + 1, result, &n, &query,
sizeof(query)) == -1)
goto bad;
}
n /= sizeof(struct sysctlnode);
node = getstr(&name, ep, "./");
for (i = 0; i < n; i++)
if (matchstr(result[i].sysctl_name, node, name)) {
mib[miblen] = result[i].sysctl_num;
miblen++;
break;
}
} while (name < ep && miblen <= CTL_MAXNAME);
if (name < ep || i == ~0ul)
goto bad;
r = SYSCTL_TYPE(result[i].sysctl_flags);
xfree(result);
if (sysctl(mib, miblen, oldp, oldlen, NULL, 0) == -1)
return (-1);
return r;
bad:
xfree(result);
return (-1);
}

224
libexec/ld.elf_so/reloc.c Normal file
View File

@@ -0,0 +1,224 @@
/* $NetBSD: reloc.c,v 1.103 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: reloc.c,v 1.103 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/bitops.h>
#include <dirent.h>
#include "debug.h"
#include "rtld.h"
#ifndef RTLD_INHIBIT_COPY_RELOCS
static int _rtld_do_copy_relocation(const Obj_Entry *, const Elf_Rela *);
static int
_rtld_do_copy_relocation(const Obj_Entry *dstobj, const Elf_Rela *rela)
{
void *dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
const Elf_Sym *dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
const char *name = dstobj->strtab + dstsym->st_name;
unsigned long hash = _rtld_elf_hash(name);
size_t size = dstsym->st_size;
const void *srcaddr;
const Elf_Sym *srcsym = NULL;
Obj_Entry *srcobj;
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = _rtld_symlook_obj(name, hash, srcobj, false)) != NULL)
break;
if (srcobj == NULL) {
_rtld_error("Undefined symbol \"%s\" referenced from COPY"
" relocation in %s", name, dstobj->path);
return (-1);
}
srcaddr = (const void *)(srcobj->relocbase + srcsym->st_value);
(void)memcpy(dstaddr, srcaddr, size);
rdbg(("COPY %s %s %s --> src=%p dst=%p size %ld",
dstobj->path, srcobj->path, name, srcaddr,
(void *)dstaddr, (long)size));
return (0);
}
#endif /* RTLD_INHIBIT_COPY_RELOCS */
/*
* Process the special R_xxx_COPY relocations in the main program. These
* copy data from a shared object into a region in the main program's BSS
* segment.
*
* Returns 0 on success, -1 on failure.
*/
int
_rtld_do_copy_relocations(const Obj_Entry *dstobj)
{
#ifndef RTLD_INHIBIT_COPY_RELOCS
/* COPY relocations are invalid elsewhere */
assert(!dstobj->isdynamic);
if (dstobj->rel != NULL) {
const Elf_Rel *rel;
for (rel = dstobj->rel; rel < dstobj->rellim; ++rel) {
if (ELF_R_TYPE(rel->r_info) == R_TYPE(COPY)) {
Elf_Rela ourrela;
ourrela.r_info = rel->r_info;
ourrela.r_offset = rel->r_offset;
ourrela.r_addend = 0;
if (_rtld_do_copy_relocation(dstobj,
&ourrela) < 0)
return (-1);
}
}
}
if (dstobj->rela != NULL) {
const Elf_Rela *rela;
for (rela = dstobj->rela; rela < dstobj->relalim; ++rela) {
if (ELF_R_TYPE(rela->r_info) == R_TYPE(COPY)) {
if (_rtld_do_copy_relocation(dstobj, rela) < 0)
return (-1);
}
}
}
#endif /* RTLD_INHIBIT_COPY_RELOCS */
return (0);
}
/*
* Relocate newly-loaded shared objects. The argument is a pointer to
* the Obj_Entry for the first such object. All objects from the first
* to the end of the list of objects are relocated. Returns 0 on success,
* or -1 on failure.
*/
int
_rtld_relocate_objects(Obj_Entry *first, bool bind_now)
{
Obj_Entry *obj;
int ok = 1;
for (obj = first; obj != NULL; obj = obj->next) {
if (obj->nbuckets == 0 || obj->nchains == 0 ||
obj->buckets == NULL || obj->symtab == NULL ||
obj->strtab == NULL) {
_rtld_error("%s: Shared object has no run-time"
" symbol table", obj->path);
return -1;
}
if (obj->nbuckets == UINT32_MAX) {
_rtld_error("%s: Symbol table too large", obj->path);
return -1;
}
rdbg((" relocating %s (%ld/%ld rel/rela, %ld/%ld plt rel/rela)",
obj->path,
(long)(obj->rellim - obj->rel),
(long)(obj->relalim - obj->rela),
(long)(obj->pltrellim - obj->pltrel),
(long)(obj->pltrelalim - obj->pltrela)));
if (obj->textrel) {
/*
* There are relocations to the write-protected text
* segment.
*/
if (mprotect(obj->mapbase, obj->textsize,
PROT_READ | PROT_WRITE | PROT_EXEC) == -1) {
_rtld_error("%s: Cannot write-enable text "
"segment: %s", obj->path, xstrerror(errno));
return -1;
}
}
dbg(("doing non-PLT relocations"));
if (_rtld_relocate_nonplt_objects(obj) < 0)
ok = 0;
if (obj->textrel) { /* Re-protected the text segment. */
if (mprotect(obj->mapbase, obj->textsize,
PROT_READ | PROT_EXEC) == -1) {
_rtld_error("%s: Cannot write-protect text "
"segment: %s", obj->path, xstrerror(errno));
return -1;
}
}
dbg(("doing lazy PLT binding"));
if (_rtld_relocate_plt_lazy(obj) < 0)
ok = 0;
#if defined(__hppa__)
bind_now = 1;
#endif
if (obj->z_now || bind_now) {
dbg(("doing immediate PLT binding"));
if (_rtld_relocate_plt_objects(obj) < 0)
ok = 0;
}
if (!ok)
return -1;
/* Set some sanity-checking numbers in the Obj_Entry. */
obj->magic = RTLD_MAGIC;
obj->version = RTLD_VERSION;
/* Fill in the dynamic linker entry points. */
obj->dlopen = dlopen;
obj->dlsym = dlsym;
obj->dlerror = dlerror;
obj->dlclose = dlclose;
obj->dladdr = dladdr;
dbg(("fixing up PLTGOT"));
/* Set the special PLTGOT entries. */
if (obj->pltgot != NULL)
_rtld_setup_pltgot(obj);
}
return 0;
}

1265
libexec/ld.elf_so/rtld.c Normal file

File diff suppressed because it is too large Load Diff

362
libexec/ld.elf_so/rtld.h Normal file
View File

@@ -0,0 +1,362 @@
/* $NetBSD: rtld.h,v 1.99 2011/01/16 15:56:37 matt Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef RTLD_H
#define RTLD_H
#include <dlfcn.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/exec_elf.h>
#include "rtldenv.h"
#include "link.h"
#if defined(_RTLD_SOURCE)
#ifndef RTLD_DEFAULT_LIBRARY_PATH
#define RTLD_DEFAULT_LIBRARY_PATH "/usr/lib"
#endif
#define _PATH_LD_HINTS "/etc/ld.so.conf"
extern size_t _rtld_pagesz;
#define round_down(x) ((x) & ~(_rtld_pagesz - 1))
#define round_up(x) round_down((x) + _rtld_pagesz - 1)
#define NEW(type) ((type *) xmalloc(sizeof(type)))
#define CNEW(type) ((type *) xcalloc(sizeof(type)))
/*
* Fill in a DoneList with an allocation large enough to hold all of
* the currently-loaded objects. Keep this in a macro since it calls
* alloca and we want that to occur within the scope of the caller.
*/
#define _rtld_donelist_init(dlp) \
((dlp)->num_alloc = _rtld_objcount, \
(dlp)->objs = alloca((dlp)->num_alloc * sizeof((dlp)->objs[0])), \
assert((dlp)->objs != NULL), \
(dlp)->num_used = 0)
#endif /* _RTLD_SOURCE */
/*
* C++ has mandated the use of the following keywords for its new boolean
* type. We might as well follow their lead.
*/
struct Struct_Obj_Entry;
typedef struct Struct_Objlist_Entry {
SIMPLEQ_ENTRY(Struct_Objlist_Entry) link;
struct Struct_Obj_Entry *obj;
} Objlist_Entry;
typedef SIMPLEQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist;
typedef struct Struct_Name_Entry {
STAILQ_ENTRY(Struct_Name_Entry) link;
char name[1];
} Name_Entry;
typedef struct Struct_Needed_Entry {
struct Struct_Needed_Entry *next;
struct Struct_Obj_Entry *obj;
unsigned long name; /* Offset of name in string table */
} Needed_Entry;
typedef struct _rtld_search_path_t {
struct _rtld_search_path_t *sp_next;
const char *sp_path;
size_t sp_pathlen;
} Search_Path;
#define RTLD_MAX_ENTRY 10
#define RTLD_MAX_LIBRARY 4
#define RTLD_MAX_CTL 2
typedef struct _rtld_library_xform_t {
struct _rtld_library_xform_t *next;
char *name;
const char *ctlname;
struct {
char *value;
char *library[RTLD_MAX_LIBRARY];
} entry[RTLD_MAX_ENTRY];
} Library_Xform;
/*
* Shared object descriptor.
*
* Items marked with "(%)" are dynamically allocated, and must be freed
* when the structure is destroyed.
*
* The layout of this structure needs to be preserved because pre-2.0 binaries
* hard-coded the location of dlopen() and friends.
*/
#define RTLD_MAGIC 0xd550b87a
#define RTLD_VERSION 1
typedef struct Struct_Obj_Entry {
Elf32_Word magic; /* Magic number (sanity check) */
Elf32_Word version; /* Version number of struct format */
struct Struct_Obj_Entry *next;
char *path; /* Pathname of underlying file (%) */
int refcount;
int dl_refcount; /* Number of times loaded by dlopen */
/* These items are computed by map_object() or by digest_phdr(). */
caddr_t mapbase; /* Base address of mapped region */
size_t mapsize; /* Size of mapped region in bytes */
size_t textsize; /* Size of text segment in bytes */
Elf_Addr vaddrbase; /* Base address in shared object file */
caddr_t relocbase; /* Reloc const = mapbase - *vaddrbase */
Elf_Dyn *dynamic; /* Dynamic section */
caddr_t entry; /* Entry point */
const Elf_Phdr *phdr; /* Program header (may be xmalloc'ed) */
size_t phsize; /* Size of program header in bytes */
/* Items from the dynamic section. */
Elf_Addr *pltgot; /* PLTGOT table */
const Elf_Rel *rel; /* Relocation entries */
const Elf_Rel *rellim; /* Limit of Relocation entries */
const Elf_Rela *rela; /* Relocation entries */
const Elf_Rela *relalim; /* Limit of Relocation entries */
const Elf_Rel *pltrel; /* PLT relocation entries */
const Elf_Rel *pltrellim; /* Limit of PLT relocation entries */
const Elf_Rela *pltrela; /* PLT relocation entries */
const Elf_Rela *pltrelalim; /* Limit of PLT relocation entries */
const Elf_Sym *symtab; /* Symbol table */
const char *strtab; /* String table */
unsigned long strsize; /* Size in bytes of string table */
#ifdef __mips__
Elf_Word local_gotno; /* Number of local GOT entries */
Elf_Word symtabno; /* Number of dynamic symbols */
Elf_Word gotsym; /* First dynamic symbol in GOT */
#endif
const Elf_Symindx *buckets; /* Hash table buckets array */
unsigned long unused1; /* Used to be nbuckets */
const Elf_Symindx *chains; /* Hash table chain array */
unsigned long nchains; /* Number of chains */
Search_Path *rpaths; /* Search path specified in object */
Needed_Entry *needed; /* Shared objects needed by this (%) */
void (*init)(void); /* Initialization function to call */
void (*fini)(void); /* Termination function to call */
/* Entry points for dlopen() and friends. */
void *(*dlopen)(const char *, int);
void *(*dlsym)(void *, const char *);
char *(*dlerror)(void);
int (*dlclose)(void *);
int (*dladdr)(const void *, Dl_info *);
u_int32_t mainprog:1, /* True if this is the main program */
rtld:1, /* True if this is the dynamic linker */
textrel:1, /* True if there are relocations to
* text seg */
symbolic:1, /* True if generated with
* "-Bsymbolic" */
printed:1, /* True if ldd has printed it */
isdynamic:1, /* True if this is a pure PIC object */
mainref:1, /* True if on _rtld_list_main */
globalref:1, /* True if on _rtld_list_global */
init_done:1, /* True if .init has been added */
init_called:1, /* True if .init function has been
* called */
fini_called:1, /* True if .fini function has been
* called */
z_now:1, /* True if object's symbols should be
bound immediately */
z_nodelete:1, /* True if object should never be
unloaded */
z_initfirst:1, /* True if object's .init/.fini take
* priority over others */
z_noopen:1, /* True if object should never be
dlopen'ed */
phdr_loaded:1, /* Phdr is loaded and doesn't need to
* be freed. */
ref_nodel:1; /* Refcount increased to prevent dlclose */
struct link_map linkmap; /* for GDB */
/* These items are computed by map_object() or by digest_phdr(). */
const char *interp; /* Pathname of the interpreter, if any */
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
Objlist dagmembers; /* DAG has these members (%) */
dev_t dev; /* Object's filesystem's device */
ino_t ino; /* Object's inode number */
void *ehdr;
uint32_t nbuckets; /* Number of buckets */
uint32_t nbuckets_m; /* Precomputed for fast remainder */
uint8_t nbuckets_s1;
uint8_t nbuckets_s2;
size_t pathlen; /* Pathname length */
STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this object we
know about. */
#ifdef __powerpc__
Elf_Addr *gotptr; /* GOT table (secure-plt only) */
#endif
} Obj_Entry;
typedef struct Struct_DoneList {
const Obj_Entry **objs; /* Array of object pointers */
unsigned int num_alloc; /* Allocated size of the array */
unsigned int num_used; /* Number of array slots used */
} DoneList;
#if defined(_RTLD_SOURCE)
extern struct r_debug _rtld_debug;
extern Search_Path *_rtld_default_paths;
extern Obj_Entry *_rtld_objlist;
extern Obj_Entry **_rtld_objtail;
extern u_int _rtld_objcount;
extern u_int _rtld_objloads;
extern Obj_Entry *_rtld_objmain;
extern Obj_Entry _rtld_objself;
extern Search_Path *_rtld_paths;
extern Library_Xform *_rtld_xforms;
extern bool _rtld_trust;
extern Objlist _rtld_list_global;
extern Objlist _rtld_list_main;
extern Elf_Sym _rtld_sym_zero;
#define RTLD_MODEMASK 0x3
/* Flags for _rtld_load_object() and friends. */
#define _RTLD_GLOBAL 0x01 /* Add object to global DAG. */
#define _RTLD_MAIN 0x02
#define _RTLD_NOLOAD 0x04 /* dlopen() specified RTLD_NOLOAD. */
#define _RTLD_DLOPEN 0x08 /* Load_object() called from dlopen(). */
/* rtld.c */
/* We export these symbols using _rtld_symbol_lookup and is_exported. */
__dso_public char *dlerror(void);
__dso_public void *dlopen(const char *, int);
__dso_public void *dlsym(void *, const char *);
__dso_public int dlclose(void *);
__dso_public int dladdr(const void *, Dl_info *);
__dso_public int dlinfo(void *, int, void *);
__dso_public int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *),
void *);
/* These aren't exported */
void _rtld_error(const char *, ...)
__attribute__((__format__(__printf__,1,2)));
void _rtld_die(void) __attribute__((__noreturn__));
void *_rtld_objmain_sym(const char *);
void _rtld_debug_state(void);
void _rtld_linkmap_add(Obj_Entry *);
void _rtld_linkmap_delete(Obj_Entry *);
void _rtld_objlist_push_head(Objlist *, Obj_Entry *);
void _rtld_objlist_push_tail(Objlist *, Obj_Entry *);
Objlist_Entry *_rtld_objlist_find(Objlist *, const Obj_Entry *);
void _rtld_ref_dag(Obj_Entry *);
/* expand.c */
size_t _rtld_expand_path(char *, size_t, const char *, const char *,\
const char *);
/* headers.c */
void _rtld_digest_dynamic(const char *, Obj_Entry *);
Obj_Entry *_rtld_digest_phdr(const Elf_Phdr *, int, caddr_t);
/* load.c */
Obj_Entry *_rtld_load_object(const char *, int);
int _rtld_load_needed_objects(Obj_Entry *, int);
int _rtld_preload(const char *);
#define OBJ_ERR (Obj_Entry *)(-1)
/* path.c */
void _rtld_add_paths(const char *, Search_Path **, const char *);
void _rtld_process_hints(const char *, Search_Path **, Library_Xform **,
const char *);
int _rtld_sysctl(const char *, void *, size_t *);
/* reloc.c */
int _rtld_do_copy_relocations(const Obj_Entry *);
int _rtld_relocate_objects(Obj_Entry *, bool);
int _rtld_relocate_nonplt_objects(Obj_Entry *);
int _rtld_relocate_plt_lazy(const Obj_Entry *);
int _rtld_relocate_plt_objects(const Obj_Entry *);
void _rtld_setup_pltgot(const Obj_Entry *);
/* search.c */
Obj_Entry *_rtld_load_library(const char *, const Obj_Entry *, int);
/* symbol.c */
unsigned long _rtld_elf_hash(const char *);
const Elf_Sym *_rtld_symlook_obj(const char *, unsigned long,
const Obj_Entry *, bool);
const Elf_Sym *_rtld_find_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, bool);
const Elf_Sym *_rtld_find_plt_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, bool);
const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,
const Objlist *, const Obj_Entry **, bool, DoneList *);
const Elf_Sym *_rtld_symlook_default(const char *, unsigned long,
const Obj_Entry *, const Obj_Entry **, bool);
const Elf_Sym *_rtld_symlook_needed(const char *, unsigned long,
const Needed_Entry *, const Obj_Entry **, bool,
DoneList *, DoneList *);
#ifdef COMBRELOC
void _rtld_combreloc_reset(const Obj_Entry *);
#endif
/* map_object.c */
struct stat;
Obj_Entry *_rtld_map_object(const char *, int, const struct stat *);
void _rtld_obj_free(Obj_Entry *);
Obj_Entry *_rtld_obj_new(void);
/* function descriptors */
#ifdef __HAVE_FUNCTION_DESCRIPTORS
Elf_Addr _rtld_function_descriptor_alloc(const Obj_Entry *,
const Elf_Sym *, Elf_Addr);
const void *_rtld_function_descriptor_function(const void *);
#endif /* __HAVE_FUNCTION_DESCRIPTORS */
#endif /* _RTLD_SOURCE */
#endif /* RTLD_H */

View File

@@ -0,0 +1,86 @@
/* $NetBSD: rtldenv.h,v 1.10 2010/10/29 15:08:17 christos Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
#ifndef _RTLDENV_H
#define _RTLDENV_H
#include <stddef.h>
#include <stdarg.h>
void *xcalloc(size_t);
void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(const char *);
void xfree(void *);
#ifdef RTLD_LOADER
void xprintf(const char *, ...)
__attribute__((__format__(__printf__, 1, 2)));
void xvprintf(const char *, va_list)
__attribute__((__format__(__printf__, 1, 0)));
void xsnprintf(char *, size_t, const char *, ...)
__attribute__((__format__(__printf__, 3, 4)));
size_t xvsnprintf(char *, size_t, const char *, va_list)
__attribute__((__format__(__printf__, 3, 0)));
void xwarn(const char *, ...)
__attribute__((__format__(__printf__, 1, 2)));
void xwarnx(const char *, ...)
__attribute__((__format__(__printf__, 1, 2)));
void xerr(int, const char *, ...)
__attribute__((__noreturn__, __format__(__printf__, 2, 3)));
void xerrx(int, const char *, ...)
__attribute__((__noreturn__, __format__(__printf__, 2, 3)));
void xassert(const char *, int, const char *);
const char *xstrerror(int);
int xunsetenv(const char *);
# ifdef DEBUG
# define assert(cond) ((cond) ? (void) 0 : xassert(__FILE__, __LINE__, #cond))
# else
# define assert(cond) (void) 0
# endif
#else
# include <assert.h>
# include <stdio.h>
# include <err.h>
# define xprintf printf
# define xvprintf vprintf
# define xsnprintf snprintf
# define xvsnprintf vsnprintf
# define xwarn warn
# define xwarnx warnx
# define xerr err
# define xerrx errx
# define xassert assert
# define xstrerror strerror
#endif
#endif /* _RTLDENV_H */

192
libexec/ld.elf_so/search.c Normal file
View File

@@ -0,0 +1,192 @@
/* $NetBSD: search.c,v 1.23 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: search.c,v 1.23 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <dirent.h>
#include "debug.h"
#include "rtld.h"
/*
* Data declarations.
*/
Search_Path *_rtld_invalid_paths;
static Obj_Entry *_rtld_search_library_path(const char *, size_t,
const char *, size_t, int);
static Obj_Entry *
_rtld_search_library_path(const char *name, size_t namelen,
const char *dir, size_t dirlen, int flags)
{
char pathname[MAXPATHLEN];
size_t pathnamelen;
Obj_Entry *obj;
Search_Path *sp;
pathnamelen = dirlen + 1 + namelen;
if (pathnamelen >= sizeof(pathname))
return NULL;
for (sp = _rtld_invalid_paths; sp != NULL; sp = sp->sp_next) {
if (sp->sp_pathlen == pathnamelen &&
sp->sp_path[dirlen] == '/' &&
!memcmp(name, sp->sp_path + dirlen + 1, namelen) &&
!memcmp(dir, sp->sp_path, dirlen)) {
return NULL;
}
}
memcpy(pathname, dir, dirlen);
pathname[dirlen] = '/';
memcpy(pathname + dirlen + 1, name, namelen);
pathname[pathnamelen] = '\0';
dbg((" Trying \"%s\"", pathname));
obj = _rtld_load_object(pathname, flags);
if (obj == NULL) {
Search_Path *path;
path = NEW(Search_Path);
path->sp_pathlen = pathnamelen;
path->sp_path = xstrdup(pathname);
path->sp_next = _rtld_invalid_paths;
_rtld_invalid_paths = path;
}
return obj;
}
/*
* Find the library with the given name, and return its full pathname.
* The returned string is dynamically allocated. Generates an error
* message and returns NULL if the library cannot be found.
*
* If the second argument is non-NULL, then it refers to an already-
* loaded shared object, whose library search path will be searched.
*/
Obj_Entry *
_rtld_load_library(const char *name, const Obj_Entry *refobj, int flags)
{
char tmperror[512], *tmperrorp;
Search_Path *sp;
const char *pathname;
int namelen;
Obj_Entry *obj;
if (strchr(name, '/') != NULL) { /* Hard coded pathname */
if (name[0] != '/' && !_rtld_trust) {
_rtld_error(
"absolute pathname required for shared object \"%s\"",
name);
return NULL;
}
pathname = name;
goto found;
}
dbg((" Searching for \"%s\" (%p)", name, refobj));
tmperrorp = dlerror();
if (tmperrorp != NULL) {
strncpy(tmperror, tmperrorp, sizeof tmperror);
tmperrorp = tmperror;
}
namelen = strlen(name);
for (sp = _rtld_paths; sp != NULL; sp = sp->sp_next)
if ((obj = _rtld_search_library_path(name, namelen,
sp->sp_path, sp->sp_pathlen, flags)) != NULL)
goto pathfound;
if (refobj != NULL)
for (sp = refobj->rpaths; sp != NULL; sp = sp->sp_next)
if ((obj = _rtld_search_library_path(name,
namelen, sp->sp_path, sp->sp_pathlen, flags)) != NULL)
goto pathfound;
for (sp = _rtld_default_paths; sp != NULL; sp = sp->sp_next)
if ((obj = _rtld_search_library_path(name, namelen,
sp->sp_path, sp->sp_pathlen, flags)) != NULL)
goto pathfound;
_rtld_error("Shared object \"%s\" not found", name);
return NULL;
pathfound:
/*
* The library has been found, but it couldn't be loaded for some
* reason.
*/
if (obj == OBJ_ERR)
return NULL;
/*
* Successfully found a library; restore the dlerror state as it was
* before _rtld_load_library() was called (any failed call to
* _rtld_search_library_path() will set the dlerror state, but if the
* library was eventually found, then the error state should not
* change.
*/
if (tmperrorp)
_rtld_error("%s", tmperror);
else
(void)dlerror();
return obj;
found:
obj = _rtld_load_object(pathname, flags);
if (obj == OBJ_ERR)
return NULL;
return obj;
}

488
libexec/ld.elf_so/symbol.c Normal file
View File

@@ -0,0 +1,488 @@
/* $NetBSD: symbol.c,v 1.54 2010/10/16 10:27:07 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Copyright 2002 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: symbol.c,v 1.54 2010/10/16 10:27:07 skrll Exp $");
#endif /* not lint */
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/bitops.h>
#include <dirent.h>
#include "debug.h"
#include "rtld.h"
typedef void (*fptr_t)(void);
/*
* If the given object is already in the donelist, return true. Otherwise
* add the object to the list and return false.
*/
static bool
_rtld_donelist_check(DoneList *dlp, const Obj_Entry *obj)
{
unsigned int i;
for (i = 0; i < dlp->num_used; i++)
if (dlp->objs[i] == obj)
return true;
/*
* Our donelist allocation may not always be sufficient as we're not
* thread safe. We'll handle it properly anyway.
*/
if (dlp->num_used < dlp->num_alloc)
dlp->objs[dlp->num_used++] = obj;
return false;
}
static bool
_rtld_is_exported(const Elf_Sym *def)
{
static const fptr_t _rtld_exports[] = {
(fptr_t)dlopen,
(fptr_t)dlclose,
(fptr_t)dlsym,
(fptr_t)dlerror,
(fptr_t)dladdr,
(fptr_t)dlinfo,
(fptr_t)dl_iterate_phdr,
NULL
};
int i;
fptr_t value;
value = (fptr_t)(_rtld_objself.relocbase + def->st_value);
for (i = 0; _rtld_exports[i] != NULL; i++) {
if (value == _rtld_exports[i])
return true;
}
return false;
}
/*
* Hash function for symbol table lookup. Don't even think about changing
* this. It is specified by the System V ABI.
*/
unsigned long
_rtld_elf_hash(const char *name)
{
const unsigned char *p = (const unsigned char *) name;
unsigned long h = 0;
unsigned long g;
unsigned long c;
for (; __predict_true((c = *p) != '\0'); p++) {
h <<= 4;
h += c;
if ((g = h & 0xf0000000) != 0) {
h ^= g;
h ^= g >> 24;
}
}
return (h);
}
const Elf_Sym *
_rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
{
const Elf_Sym *symp;
const Elf_Sym *def;
const Obj_Entry *defobj;
const Objlist_Entry *elm;
def = NULL;
defobj = NULL;
SIMPLEQ_FOREACH(elm, objlist, link) {
if (_rtld_donelist_check(dlp, elm->obj))
continue;
rdbg(("search object %p (%s) for %s", elm->obj, elm->obj->path,
name));
if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
!= NULL) {
if ((def == NULL) ||
(ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = elm->obj;
if (ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
}
}
}
if (def != NULL)
*defobj_out = defobj;
return def;
}
/*
* Search the symbol table of a shared object and all objects needed by it for
* a symbol of the given name. Search order is breadth-first. Returns a pointer
* to the symbol, or NULL if no definition was found.
*/
const Elf_Sym *
_rtld_symlook_needed(const char *name, unsigned long hash,
const Needed_Entry *needed, const Obj_Entry **defobj_out, bool inplt,
DoneList *breadth, DoneList *depth)
{
const Elf_Sym *def, *def_w;
const Needed_Entry *n;
const Obj_Entry *obj, *defobj, *defobj1;
def = def_w = NULL;
defobj = NULL;
for (n = needed; n != NULL; n = n->next) {
if ((obj = n->obj) == NULL)
continue;
if (_rtld_donelist_check(breadth, obj))
continue;
if ((def = _rtld_symlook_obj(name, hash, obj, inplt)) == NULL)
continue;
defobj = obj;
if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
*defobj_out = defobj;
return (def);
}
}
/*
* Either the symbol definition has not been found in directly needed
* objects, or the found symbol is weak.
*/
for (n = needed; n != NULL; n = n->next) {
if ((obj = n->obj) == NULL)
continue;
if (_rtld_donelist_check(depth, obj))
continue;
def_w = _rtld_symlook_needed(name, hash, obj->needed, &defobj1,
inplt, breadth, depth);
if (def_w == NULL)
continue;
if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) {
def = def_w;
defobj = defobj1;
if (ELF_ST_BIND(def_w->st_info) != STB_WEAK)
break;
}
}
if (def != NULL)
*defobj_out = defobj;
return def;
}
/*
* Search the symbol table of a single shared object for a symbol of
* the given name. Returns a pointer to the symbol, or NULL if no
* definition was found.
*
* The symbol's hash value is passed in for efficiency reasons; that
* eliminates many recomputations of the hash value.
*/
const Elf_Sym *
_rtld_symlook_obj(const char *name, unsigned long hash,
const Obj_Entry *obj, bool in_plt)
{
unsigned long symnum;
for (symnum = obj->buckets[fast_remainder32(hash, obj->nbuckets,
obj->nbuckets_m, obj->nbuckets_s1, obj->nbuckets_s2)];
symnum != ELF_SYM_UNDEFINED;
symnum = obj->chains[symnum]) {
const Elf_Sym *symp;
const char *strp;
assert(symnum < obj->nchains);
symp = obj->symtab + symnum;
strp = obj->strtab + symp->st_name;
rdbg(("check \"%s\" vs \"%s\" in %p", name, strp, obj));
if (name[1] == strp[1] && !strcmp(name, strp)) {
if (symp->st_shndx != SHN_UNDEF)
return symp;
#ifndef __mips__
/*
* XXX DANGER WILL ROBINSON!
* If we have a function pointer in the executable's
* data section, it points to the executable's PLT
* slot, and there is NO relocation emitted. To make
* the function pointer comparable to function pointers
* in shared libraries, we must resolve data references
* in the libraries to point to PLT slots in the
* executable, if they exist.
*/
else if (!in_plt && symp->st_value != 0 &&
ELF_ST_TYPE(symp->st_info) == STT_FUNC)
return symp;
#endif
else
return NULL;
}
}
return NULL;
}
#ifdef COMBRELOC
static const Obj_Entry *_rtld_last_refobj;
/*
* Called when an object is freed. Reset the cached symbol look up if
* our last referencing or definition object just got unloaded.
*/
void
_rtld_combreloc_reset(const Obj_Entry *obj)
{
if (_rtld_last_refobj == obj)
_rtld_last_refobj = NULL;
}
#endif
/*
* Given a symbol number in a referencing object, find the corresponding
* definition of the symbol. Returns a pointer to the symbol, or NULL if
* no definition was found. Returns a pointer to the Obj_Entry of the
* defining object via the reference parameter DEFOBJ_OUT.
*/
const Elf_Sym *
_rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
const Obj_Entry **defobj_out, bool in_plt)
{
const Elf_Sym *ref;
const Elf_Sym *def;
const Obj_Entry *defobj;
const char *name;
unsigned long hash;
#ifdef COMBRELOC
/*
* COMBRELOC combines multiple reloc sections and sorts them to make
* dynamic symbol lookup caching possible.
*
* So if the lookup we are doing is the same as the previous lookup
* return the cached results.
*/
static unsigned long last_symnum;
static const Obj_Entry *last_defobj;
static const Elf_Sym *last_def;
if (symnum == last_symnum && refobj == _rtld_last_refobj
&& in_plt == false) {
*defobj_out = last_defobj;
return last_def;
}
#endif
ref = refobj->symtab + symnum;
name = refobj->strtab + ref->st_name;
/*
* We don't have to do a full scale lookup if the symbol is local.
* We know it will bind to the instance in this load module; to
* which we already have a pointer (ie ref).
*/
if (ELF_ST_BIND(ref->st_info) != STB_LOCAL) {
if (ELF_ST_TYPE(ref->st_info) == STT_SECTION) {
_rtld_error("%s: Bogus symbol table entry %lu",
refobj->path, symnum);
}
hash = _rtld_elf_hash(name);
defobj = NULL;
def = _rtld_symlook_default(name, hash, refobj, &defobj, in_plt);
} else {
rdbg(("STB_LOCAL symbol %s in %s", name, refobj->path));
def = ref;
defobj = refobj;
}
/*
* If we found no definition and the reference is weak, treat the
* symbol as having the value zero.
*/
if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) {
rdbg((" returning _rtld_sym_zero@_rtld_objself"));
def = &_rtld_sym_zero;
defobj = &_rtld_objself;
}
if (def != NULL) {
*defobj_out = defobj;
#ifdef COMBRELOC
if (in_plt == false) {
/*
* Cache the lookup arguments and results if this was
* non-PLT lookup.
*/
last_symnum = symnum;
_rtld_last_refobj = refobj;
last_def = def;
last_defobj = defobj;
}
#endif
} else {
rdbg(("lookup failed"));
_rtld_error("%s: Undefined %ssymbol \"%s\" (symnum = %ld)",
refobj->path, in_plt ? "PLT " : "", name, symnum);
}
return def;
}
const Elf_Sym *
_rtld_find_plt_symdef(unsigned long symnum, const Obj_Entry *obj,
const Obj_Entry **defobj, bool imm)
{
const Elf_Sym *def = _rtld_find_symdef(symnum, obj, defobj, true);
if (__predict_false(def == NULL))
return NULL;
if (__predict_false(def == &_rtld_sym_zero)) {
/* tp is set during lazy binding. */
if (imm) {
const Elf_Sym *ref = obj->symtab + symnum;
const char *name = obj->strtab + ref->st_name;
_rtld_error(
"%s: Trying to call undefined weak symbol `%s'",
obj->path, name);
return NULL;
}
}
return def;
}
/*
* Given a symbol name in a referencing object, find the corresponding
* definition of the symbol. Returns a pointer to the symbol, or NULL if
* no definition was found. Returns a pointer to the Obj_Entry of the
* defining object via the reference parameter DEFOBJ_OUT.
*/
const Elf_Sym *
_rtld_symlook_default(const char *name, unsigned long hash,
const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt)
{
const Elf_Sym *def;
const Elf_Sym *symp;
const Obj_Entry *obj;
const Obj_Entry *defobj;
const Objlist_Entry *elm;
def = NULL;
defobj = NULL;
DoneList donelist;
_rtld_donelist_init(&donelist);
/* Look first in the referencing object if linked symbolically. */
if (refobj->symbolic && !_rtld_donelist_check(&donelist, refobj)) {
rdbg(("search referencing object for %s", name));
symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
if (symp != NULL) {
def = symp;
defobj = refobj;
}
}
/* Search all objects loaded at program start up. */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
rdbg(("search _rtld_list_main for %s", name));
symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj,
in_plt, &donelist);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
/* Search all RTLD_GLOBAL objects. */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
rdbg(("search _rtld_list_global for %s", name));
symp = _rtld_symlook_list(name, hash, &_rtld_list_global,
&obj, in_plt, &donelist);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
/* Search all dlopened DAGs containing the referencing object. */
SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
rdbg(("search DAG with root %p (%s) for %s", elm->obj,
elm->obj->path, name));
symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers,
&obj, in_plt, &donelist);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
/*
* Search the dynamic linker itself, and possibly resolve the
* symbol from there. This is how the application links to
* dynamic linker services such as dlopen. Only the values listed
* in the "_rtld_exports" array can be resolved from the dynamic
* linker.
*/
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
rdbg(("Search the dynamic linker itself."));
symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
if (symp != NULL && _rtld_is_exported(symp)) {
def = symp;
defobj = &_rtld_objself;
}
}
if (def != NULL)
*defobj_out = defobj;
return def;
}

View File

@@ -0,0 +1,91 @@
/* $NetBSD: sysident.h,v 1.14 2007/06/24 20:35:36 christos Exp $ */
/*
* Copyright (c) 1997 Christopher G. Demetriou
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the
* NetBSD Project. See http://www.NetBSD.org/ for
* information about NetBSD.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
*/
/*
* Here we define the NetBSD OS Version in an ELF .note section, structured
* like:
*
* [NOTE HEADER]
* long name size
* long description size
* long note type
*
* [NOTE DATUM]
* string OS name
*
* OSVERSION notes also have:
* long OS version (__NetBSD_Version__ constant from param.h)
*
* The DATUM fields should be padded out such that their actual (not
* declared) sizes % 4 == 0.
*
* These are used by the kernel to determine if this binary is really a
* NetBSD binary, or some other OS's.
*/
/* XXX: NetBSD 1.5 compatibility only! */
#if __NetBSD_Version__ < 105010000
#define ELF_NOTE_TYPE_NETBSD_TAG 1
#endif
#define __S(x) __STRING(x)
__asm(
".section\t\".note.netbsd.ident\", \"a\"\n"
"\t.p2align\t2\n\n"
"\t.long\t" __S(ELF_NOTE_NETBSD_NAMESZ) "\n"
"\t.long\t" __S(ELF_NOTE_NETBSD_DESCSZ) "\n"
"\t.long\t" __S(ELF_NOTE_TYPE_NETBSD_TAG) "\n"
"\t.ascii\t" __S(ELF_NOTE_NETBSD_NAME) "\n"
"\t.long\t" __S(__NetBSD_Version__) "\n\n"
"\t.previous\n"
"\t.p2align\t2\n"
);
__asm(
".section\t\".note.netbsd.pax\", \"a\"\n"
"\t.p2align\t2\n\n"
"\t.long\t" __S(ELF_NOTE_PAX_NAMESZ) "\n"
"\t.long\t" __S(ELF_NOTE_PAX_DESCSZ) "\n"
"\t.long\t" __S(ELF_NOTE_TYPE_PAX_TAG) "\n"
"\t.ascii\t" __S(ELF_NOTE_PAX_NAME) "\n"
"\t.long\t" __S(0) "\n\n"
"\t.previous\n"
"\t.p2align\t2\n"
);

486
libexec/ld.elf_so/xmalloc.c Normal file
View File

@@ -0,0 +1,486 @@
/* $NetBSD: xmalloc.c,v 1.10 2010/12/03 23:07:49 joerg Exp $ */
/*
* Copyright 1996 John D. Polstra.
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Polstra.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/
#endif /* LIBC_SCCS and not lint */
/*
* malloc.c (Caltech) 2/21/82
* Chris Kingsley, kingsley@cit-20.
*
* This is a very fast storage allocator. It allocates blocks of a small
* number of different sizes, and keeps free lists of each size. Blocks that
* don't exactly fit are passed up to the next larger size. In this
* implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
* This is designed for use in a virtual memory environment.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: xmalloc.c,v 1.10 2010/12/03 23:07:49 joerg Exp $");
#endif /* not lint */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include "rtld.h"
/*
* Pre-allocate mmap'ed pages
*/
#define NPOOLPAGES (32*1024/pagesz)
static char *pagepool_start, *pagepool_end;
static int morepages(int);
#define PAGEPOOL_SIZE (size_t)(pagepool_end - pagepool_start)
/*
* The overhead on a block is at least 4 bytes. When free, this space
* contains a pointer to the next free block, and the bottom two bits must
* be zero. When in use, the first byte is set to MAGIC, and the second
* byte is the size index. The remaining bytes are for alignment.
* If range checking is enabled then a second word holds the size of the
* requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
* The order of elements is critical: ov_magic must overlay the low order
* bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
*/
union overhead {
union overhead *ov_next; /* when free */
struct {
u_char ovu_magic; /* magic number */
u_char ovu_index; /* bucket # */
#ifdef RCHECK
u_short ovu_rmagic; /* range magic number */
u_int ovu_size; /* actual block size */
#endif
} ovu;
#define ov_magic ovu.ovu_magic
#define ov_index ovu.ovu_index
#define ov_rmagic ovu.ovu_rmagic
#define ov_size ovu.ovu_size
};
static void morecore(size_t);
static void *imalloc(size_t);
#define MAGIC 0xef /* magic # on accounting info */
#define RMAGIC 0x5555 /* magic # on range info */
#ifdef RCHECK
#define RSLOP (sizeof (u_short))
#else
#define RSLOP 0
#endif
/*
* nextf[i] is the pointer to the next free block of size 2^(i+3). The
* smallest allocatable block is 8 bytes. The overhead information
* precedes the data area returned to the user.
*/
#define NBUCKETS 30
static union overhead *nextf[NBUCKETS];
static size_t pagesz; /* page size */
static size_t pagebucket; /* page size bucket */
#ifdef MSTATS
/*
* nmalloc[i] is the difference between the number of mallocs and frees
* for a given block size.
*/
static u_int nmalloc[NBUCKETS];
#endif
#if defined(MALLOC_DEBUG) || defined(RCHECK)
#define ASSERT(p) if (!(p)) botch("p")
static void
botch(const char *s)
{
xwarnx("\r\nassertion botched: %s\r\n", s);
abort();
}
#else
#define ASSERT(p)
#endif
#define TRACE() xprintf("TRACE %s:%d\n", __FILE__, __LINE__)
static void *
imalloc(size_t nbytes)
{
union overhead *op;
size_t bucket;
size_t n, m;
unsigned amt;
/*
* First time malloc is called, setup page size and
* align break pointer so all data will be page aligned.
*/
if (pagesz == 0) {
pagesz = n = _rtld_pagesz;
if (morepages(NPOOLPAGES) == 0)
return NULL;
op = (union overhead *)(pagepool_start);
m = sizeof (*op) - (((char *)op - (char *)NULL) & (n - 1));
if (n < m)
n += pagesz - m;
else
n -= m;
if (n) {
pagepool_start += n;
}
bucket = 0;
amt = sizeof(union overhead);
while (pagesz > amt) {
amt <<= 1;
bucket++;
}
pagebucket = bucket;
}
/*
* Convert amount of memory requested into closest block size
* stored in hash buckets which satisfies request.
* Account for space used per block for accounting.
*/
if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
if (sizeof(union overhead) & (sizeof(union overhead) - 1)) {
amt = sizeof(union overhead) * 2;
bucket = 1;
} else {
amt = sizeof(union overhead); /* size of first bucket */
bucket = 0;
}
n = -(sizeof (*op) + RSLOP);
} else {
amt = pagesz;
bucket = pagebucket;
}
while (nbytes > amt + n) {
amt <<= 1;
if (amt == 0)
return (NULL);
bucket++;
}
/*
* If nothing in hash bucket right now,
* request more memory from the system.
*/
if ((op = nextf[bucket]) == NULL) {
morecore(bucket);
if ((op = nextf[bucket]) == NULL)
return (NULL);
}
/* remove from linked list */
nextf[bucket] = op->ov_next;
op->ov_magic = MAGIC;
op->ov_index = bucket;
#ifdef MSTATS
nmalloc[bucket]++;
#endif
#ifdef RCHECK
/*
* Record allocated size of block and
* bound space with magic numbers.
*/
op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
op->ov_rmagic = RMAGIC;
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
return ((char *)(op + 1));
}
/*
* Allocate more memory to the indicated bucket.
*/
static void
morecore(size_t bucket)
{
union overhead *op;
size_t sz; /* size of desired block */
size_t amt; /* amount to allocate */
size_t nblks; /* how many blocks we get */
/*
* sbrk_size <= 0 only for big, FLUFFY, requests (about
* 2^30 bytes on a VAX, I think) or for a negative arg.
*/
sz = 1 << (bucket + 3);
#ifdef MALLOC_DEBUG
ASSERT(sz > 0);
#endif
if (sz < pagesz) {
amt = pagesz;
nblks = amt / sz;
} else {
amt = sz + pagesz;
nblks = 1;
}
if (amt > PAGEPOOL_SIZE)
if (morepages(amt/pagesz + NPOOLPAGES) == 0)
return;
op = (union overhead *)pagepool_start;
pagepool_start += amt;
/*
* Add new memory allocated to that on
* free list for this hash bucket.
*/
nextf[bucket] = op;
while (--nblks > 0) {
op->ov_next = (union overhead *)((caddr_t)op + sz);
op = (union overhead *)((caddr_t)op + sz);
}
}
void
xfree(void *cp)
{
int size;
union overhead *op;
if (cp == NULL)
return;
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
#ifdef MALLOC_DEBUG
ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
#else
if (op->ov_magic != MAGIC)
return; /* sanity */
#endif
#ifdef RCHECK
ASSERT(op->ov_rmagic == RMAGIC);
ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
#endif
size = op->ov_index;
ASSERT(size < NBUCKETS);
op->ov_next = nextf[size]; /* also clobbers ov_magic */
nextf[size] = op;
#ifdef MSTATS
nmalloc[size]--;
#endif
}
static void *
irealloc(void *cp, size_t nbytes)
{
size_t onb;
size_t i;
union overhead *op;
char *res;
if (cp == NULL)
return (imalloc(nbytes));
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
if (op->ov_magic != MAGIC) {
static const char *err_str =
"memory corruption or double free in realloc\n";
extern char *__progname;
write(STDERR_FILENO, __progname, strlen(__progname));
write(STDERR_FILENO, err_str, strlen(err_str));
abort();
}
i = op->ov_index;
onb = 1 << (i + 3);
if (onb < pagesz)
onb -= sizeof (*op) + RSLOP;
else
onb += pagesz - sizeof (*op) - RSLOP;
/* avoid the copy if same size block */
if (i) {
i = 1 << (i + 2);
if (i < pagesz)
i -= sizeof (*op) + RSLOP;
else
i += pagesz - sizeof (*op) - RSLOP;
}
if (nbytes <= onb && nbytes > i) {
#ifdef RCHECK
op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
return(cp);
} else
xfree(cp);
if ((res = imalloc(nbytes)) == NULL)
return (NULL);
if (cp != res) /* common optimization if "compacting" */
memcpy(res, cp, (nbytes < onb) ? nbytes : onb);
return (res);
}
#ifdef MSTATS
/*
* mstats - print out statistics about malloc
*
* Prints two lines of numbers, one showing the length of the free list
* for each size category, the second showing the number of mallocs -
* frees for each size category.
*/
void
mstats(char *s)
{
int i, j;
union overhead *p;
int totfree = 0,
totused = 0;
xprintf("Memory allocation statistics %s\nfree:\t", s);
for (i = 0; i < NBUCKETS; i++) {
for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
;
xprintf(" %d", j);
totfree += j * (1 << (i + 3));
}
xprintf("\nused:\t");
for (i = 0; i < NBUCKETS; i++) {
xprintf(" %d", nmalloc[i]);
totused += nmalloc[i] * (1 << (i + 3));
}
xprintf("\n\tTotal in use: %d, total free: %d\n",
totused, totfree);
}
#endif
static int
morepages(int n)
{
int fd = -1;
int offset;
#ifdef NEED_DEV_ZERO
fd = open("/dev/zero", O_RDWR, 0);
if (fd == -1)
xerr(1, "/dev/zero");
#endif
if (PAGEPOOL_SIZE > pagesz) {
caddr_t addr = (caddr_t)
(((long)pagepool_start + pagesz - 1) & ~(pagesz - 1));
if (munmap(addr, pagepool_end - addr) != 0)
xwarn("morepages: munmap %p", addr);
}
offset = (long)pagepool_start - ((long)pagepool_start & ~(pagesz - 1));
if ((pagepool_start = mmap(0, n * pagesz,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, fd, 0)) == (caddr_t)-1) {
xprintf("Cannot map anonymous memory");
return 0;
}
pagepool_end = pagepool_start + n * pagesz;
pagepool_start += offset;
#ifdef NEED_DEV_ZERO
close(fd);
#endif
return n;
}
void *
xcalloc(size_t size)
{
return memset(xmalloc(size), 0, size);
}
void *
xmalloc(size_t size)
{
void *p = imalloc(size);
if (p == NULL)
xerr(1, "%s", xstrerror(errno));
return p;
}
void *
xrealloc(void *p, size_t size)
{
p = irealloc(p, size);
if (p == NULL)
xerr(1, "%s", xstrerror(errno));
return p;
}
char *
xstrdup(const char *str)
{
size_t len;
char *copy;
len = strlen(str) + 1;
copy = xmalloc(len);
memcpy(copy, str, len);
return (copy);
}

323
libexec/ld.elf_so/xprintf.c Normal file
View File

@@ -0,0 +1,323 @@
/* $NetBSD: xprintf.c,v 1.21 2010/12/16 22:52:32 joerg Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: xprintf.c,v 1.21 2010/12/16 22:52:32 joerg Exp $");
#endif /* not lint */
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include "rtldenv.h"
#ifdef RTLD_LOADER
#define SZ_LONG 0x01
#define SZ_UNSIGNED 0x02
#define SZ_SIZE_T 0x04
/*
* Non-mallocing printf, for use by malloc and rtld itself.
* This avoids putting in most of stdio.
*
* deals withs formats %x, %p, %s, and %d.
*/
size_t
xvsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap)
{
char *bp = buf;
char *const ep = buf + buflen - 4;
int size, prec;
while (*fmt != '\0' && bp < ep) {
switch (*fmt) {
case '\\':{
if (fmt[1] != '\0')
*bp++ = *++fmt;
continue;
}
case '%':{
size = 0;
prec = -1;
rflag: switch (fmt[1]) {
case '*':
prec = va_arg(ap, int);
/* FALLTHROUGH */
case '.':
fmt++;
goto rflag;
case 'l':
size |= SZ_LONG;
fmt++;
goto rflag;
case 'z':
size |= SZ_SIZE_T;
fmt++;
goto rflag;
case 'u':
size |= SZ_UNSIGNED;
/* FALLTHROUGH */
case 'd':{
long sval;
unsigned long uval;
char digits[sizeof(int) * 3], *dp = digits;
#define SARG() \
(size & SZ_LONG ? va_arg(ap, long) : \
((size & SZ_SIZE_T ? (long)va_arg(ap, size_t) : \
va_arg(ap, int))))
#define UARG() \
(size & SZ_LONG ? va_arg(ap, unsigned long) : \
((size & SZ_SIZE_T ? va_arg(ap, size_t) : \
va_arg(ap, unsigned int))))
if (fmt[1] == 'd') {
if (size & SZ_UNSIGNED)
sval = UARG();
else
sval = SARG();
if (sval < 0) {
if ((sval << 1) == 0) {
/*
* We can't flip the
* sign of this since
* it can't be
* represented as a
* positive number in
* two complement,
* handle the first
* digit. After that,
* it can be flipped
* since it is now not
* 2^(n-1).
*/
*dp++ = '0'-(sval % 10);
sval /= 10;
}
*bp++ = '-';
uval = -sval;
} else {
uval = sval;
}
} else {
if (size & SZ_UNSIGNED)
uval = UARG();
else
uval = SARG();
}
do {
*dp++ = '0' + (uval % 10);
uval /= 10;
} while (uval != 0);
do {
*bp++ = *--dp;
} while (dp != digits && bp < ep);
fmt += 2;
break;
}
case 'x':
case 'p':{
unsigned long val = va_arg(ap, unsigned long);
unsigned long mask = ~(~0UL >> 4);
int bits = sizeof(val) * 8 - 4;
const char hexdigits[] = "0123456789abcdef";
if (fmt[1] == 'p') {
*bp++ = '0';
*bp++ = 'x';
}
/* handle the border case */
if (val == 0) {
*bp++ = '0';
fmt += 2;
break;
}
/* suppress 0s */
while ((val & mask) == 0)
bits -= 4, mask >>= 4;
/* emit the hex digits */
while (bits >= 0 && bp < ep) {
*bp++ = hexdigits[(val & mask) >> bits];
bits -= 4, mask >>= 4;
}
fmt += 2;
break;
}
case 's':{
const char *str = va_arg(ap, const char *);
int len;
if (str == NULL)
str = "(null)";
if (prec < 0)
len = strlen(str);
else
len = prec;
if (ep - bp < len)
len = ep - bp;
memcpy(bp, str, len);
bp += len;
fmt += 2;
break;
}
case 'c':{
int c = va_arg(ap, int);
*bp++ = (char)c;
fmt += 2;
break;
}
default:
*bp++ = *fmt;
break;
}
break;
}
default:
*bp++ = *fmt++;
break;
}
}
*bp = '\0';
return bp - buf;
}
void
xvprintf(const char *fmt, va_list ap)
{
char buf[256];
(void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap));
}
void
xprintf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
xvprintf(fmt, ap);
va_end(ap);
}
void
xsnprintf(char *buf, size_t buflen, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
xvsnprintf(buf, buflen, fmt, ap);
va_end(ap);
}
#include "errlist_concat.h"
const char *
xstrerror(int error)
{
if (error >= concat_nerr || error < 0) {
static char buf[128];
xsnprintf(buf, sizeof(buf), "Unknown error: %d", error);
return buf;
}
return concat_errlist + concat_offset[error];
}
void
xerrx(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
xvprintf(fmt, ap);
va_end(ap);
(void) write(2, "\n", 1);
exit(eval);
}
void
xerr(int eval, const char *fmt, ...)
{
int saved_errno = errno;
va_list ap;
va_start(ap, fmt);
xvprintf(fmt, ap);
va_end(ap);
xprintf(": %s\n", xstrerror(saved_errno));
exit(eval);
}
void
xwarn(const char *fmt, ...)
{
int saved_errno = errno;
va_list ap;
va_start(ap, fmt);
xvprintf(fmt, ap);
va_end(ap);
xprintf(": %s\n", xstrerror(saved_errno));
errno = saved_errno;
}
void
xwarnx(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
xvprintf(fmt, ap);
va_end(ap);
(void) write(2, "\n", 1);
}
#ifdef DEBUG
void
xassert(const char *file, int line, const char *failedexpr)
{
xprintf("assertion \"%s\" failed: file \"%s\", line %d\n",
failedexpr, file, line);
abort();
/* NOTREACHED */
}
#endif
#endif