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:
133
libexec/ld.elf_so/Makefile
Normal file
133
libexec/ld.elf_so/Makefile
Normal 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
6
libexec/ld.elf_so/README
Normal 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
33
libexec/ld.elf_so/TODO
Normal 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
|
||||
11
libexec/ld.elf_so/arch/alpha/Makefile.inc
Normal file
11
libexec/ld.elf_so/arch/alpha/Makefile.inc
Normal 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
|
||||
503
libexec/ld.elf_so/arch/alpha/alpha_reloc.c
Normal file
503
libexec/ld.elf_so/arch/alpha/alpha_reloc.c
Normal 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;
|
||||
}
|
||||
194
libexec/ld.elf_so/arch/alpha/rtld_start.S
Normal file
194
libexec/ld.elf_so/arch/alpha/rtld_start.S
Normal 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)
|
||||
10
libexec/ld.elf_so/arch/arm/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/arm/Makefile.inc
Normal 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
|
||||
276
libexec/ld.elf_so/arch/arm/mdreloc.c
Normal file
276
libexec/ld.elf_so/arch/arm/mdreloc.c
Normal 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;
|
||||
}
|
||||
104
libexec/ld.elf_so/arch/arm/rtld_start.S
Normal file
104
libexec/ld.elf_so/arch/arm/rtld_start.S
Normal 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
|
||||
|
||||
14
libexec/ld.elf_so/arch/hppa/Makefile.inc
Normal file
14
libexec/ld.elf_so/arch/hppa/Makefile.inc
Normal 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'
|
||||
617
libexec/ld.elf_so/arch/hppa/hppa_reloc.c
Normal file
617
libexec/ld.elf_so/arch/hppa/hppa_reloc.c
Normal 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;
|
||||
}
|
||||
231
libexec/ld.elf_so/arch/hppa/rtld_start.S
Normal file
231
libexec/ld.elf_so/arch/hppa/rtld_start.S
Normal 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)
|
||||
10
libexec/ld.elf_so/arch/i386/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/i386/Makefile.inc
Normal 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
|
||||
216
libexec/ld.elf_so/arch/i386/mdreloc.c
Normal file
216
libexec/ld.elf_so/arch/i386/mdreloc.c
Normal 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;
|
||||
}
|
||||
88
libexec/ld.elf_so/arch/i386/rtld_start.S
Normal file
88
libexec/ld.elf_so/arch/i386/rtld_start.S
Normal 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
|
||||
10
libexec/ld.elf_so/arch/m68k/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/m68k/Makefile.inc
Normal 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
|
||||
224
libexec/ld.elf_so/arch/m68k/mdreloc.c
Normal file
224
libexec/ld.elf_so/arch/m68k/mdreloc.c
Normal 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;
|
||||
}
|
||||
79
libexec/ld.elf_so/arch/m68k/rtld_start.S
Normal file
79
libexec/ld.elf_so/arch/m68k/rtld_start.S
Normal 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
|
||||
17
libexec/ld.elf_so/arch/mips/Makefile.inc
Normal file
17
libexec/ld.elf_so/arch/mips/Makefile.inc
Normal 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
|
||||
454
libexec/ld.elf_so/arch/mips/mips_reloc.c
Normal file
454
libexec/ld.elf_so/arch/mips/mips_reloc.c
Normal 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;
|
||||
}
|
||||
140
libexec/ld.elf_so/arch/mips/rtld_start.S
Normal file
140
libexec/ld.elf_so/arch/mips/rtld_start.S
Normal 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)
|
||||
11
libexec/ld.elf_so/arch/powerpc/Makefile.inc
Normal file
11
libexec/ld.elf_so/arch/powerpc/Makefile.inc
Normal 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
|
||||
271
libexec/ld.elf_so/arch/powerpc/ld.so.script
Normal file
271
libexec/ld.elf_so/arch/powerpc/ld.so.script
Normal 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 . */
|
||||
}
|
||||
370
libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
Normal file
370
libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
Normal 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;
|
||||
}
|
||||
133
libexec/ld.elf_so/arch/powerpc/rtld_start.S
Normal file
133
libexec/ld.elf_so/arch/powerpc/rtld_start.S
Normal 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
|
||||
10
libexec/ld.elf_so/arch/sh3/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/sh3/Makefile.inc
Normal 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
|
||||
249
libexec/ld.elf_so/arch/sh3/mdreloc.c
Normal file
249
libexec/ld.elf_so/arch/sh3/mdreloc.c
Normal 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;
|
||||
}
|
||||
117
libexec/ld.elf_so/arch/sh3/rtld_start.S
Normal file
117
libexec/ld.elf_so/arch/sh3/rtld_start.S
Normal 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
|
||||
10
libexec/ld.elf_so/arch/sparc/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/sparc/Makefile.inc
Normal 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
|
||||
394
libexec/ld.elf_so/arch/sparc/mdreloc.c
Normal file
394
libexec/ld.elf_so/arch/sparc/mdreloc.c
Normal 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;
|
||||
}
|
||||
81
libexec/ld.elf_so/arch/sparc/rtld_start.S
Normal file
81
libexec/ld.elf_so/arch/sparc/rtld_start.S
Normal 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
|
||||
|
||||
10
libexec/ld.elf_so/arch/sparc64/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/sparc64/Makefile.inc
Normal 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
|
||||
732
libexec/ld.elf_so/arch/sparc64/mdreloc.c
Normal file
732
libexec/ld.elf_so/arch/sparc64/mdreloc.c
Normal 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;
|
||||
}
|
||||
172
libexec/ld.elf_so/arch/sparc64/rtld_start.S
Normal file
172
libexec/ld.elf_so/arch/sparc64/rtld_start.S
Normal 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 */
|
||||
|
||||
10
libexec/ld.elf_so/arch/vax/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/vax/Makefile.inc
Normal 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
|
||||
207
libexec/ld.elf_so/arch/vax/mdreloc.c
Normal file
207
libexec/ld.elf_so/arch/vax/mdreloc.c
Normal 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;
|
||||
}
|
||||
78
libexec/ld.elf_so/arch/vax/rtld_start.S
Normal file
78
libexec/ld.elf_so/arch/vax/rtld_start.S
Normal 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
|
||||
10
libexec/ld.elf_so/arch/x86_64/Makefile.inc
Normal file
10
libexec/ld.elf_so/arch/x86_64/Makefile.inc
Normal 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
|
||||
311
libexec/ld.elf_so/arch/x86_64/mdreloc.c
Normal file
311
libexec/ld.elf_so/arch/x86_64/mdreloc.c
Normal 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;
|
||||
}
|
||||
105
libexec/ld.elf_so/arch/x86_64/rtld_start.S
Normal file
105
libexec/ld.elf_so/arch/x86_64/rtld_start.S
Normal 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
64
libexec/ld.elf_so/debug.c
Normal 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
58
libexec/ld.elf_so/debug.h
Normal 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
172
libexec/ld.elf_so/expand.c
Normal 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
369
libexec/ld.elf_so/headers.c
Normal 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;
|
||||
}
|
||||
224
libexec/ld.elf_so/ld.elf_so.1
Normal file
224
libexec/ld.elf_so/ld.elf_so.1
Normal 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
350
libexec/ld.elf_so/load.c
Normal 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
|
||||
422
libexec/ld.elf_so/map_object.c
Normal file
422
libexec/ld.elf_so/map_object.c
Normal 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
478
libexec/ld.elf_so/paths.c
Normal 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
224
libexec/ld.elf_so/reloc.c
Normal 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
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
362
libexec/ld.elf_so/rtld.h
Normal 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 */
|
||||
86
libexec/ld.elf_so/rtldenv.h
Normal file
86
libexec/ld.elf_so/rtldenv.h
Normal 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
192
libexec/ld.elf_so/search.c
Normal 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
488
libexec/ld.elf_so/symbol.c
Normal 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;
|
||||
}
|
||||
91
libexec/ld.elf_so/sysident.h
Normal file
91
libexec/ld.elf_so/sysident.h
Normal 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
486
libexec/ld.elf_so/xmalloc.c
Normal 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
323
libexec/ld.elf_so/xprintf.c
Normal 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
|
||||
Reference in New Issue
Block a user