First cut at an ELF shared loader. Originally from John Polstra's FreeBSD elf
kit, then hacked on by Matt Thomas <matt@3am-software.com>, then by me (to make it work with new versions of the toolchain, etc.). This runs, but it's in serious need of cleaning and/or a fair bit of reworking. See the README file for more information, and a list of things to do.
This commit is contained in:
parent
5a09b2d886
commit
41fe218b25
|
@ -0,0 +1,29 @@
|
||||||
|
/* $NetBSD: link_elf.h,v 1.1 1996/12/16 20:37:59 cgd Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This only exists for GDB.
|
||||||
|
*/
|
||||||
|
#ifndef _LINK_H
|
||||||
|
#define _LINK_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
struct link_map {
|
||||||
|
caddr_t l_addr; /* Base Address of library */
|
||||||
|
const char *l_name; /* Absolute Path to Library */
|
||||||
|
void *l_ld; /* Pointer to .dynamic in memory */
|
||||||
|
struct link_map *l_next, *l_prev; /* linked list of of mapped libs */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct r_debug {
|
||||||
|
int r_version; /* not used */
|
||||||
|
struct link_map *r_map; /* list of loaded images */
|
||||||
|
void (*r_brk)(void); /* pointer to break point */
|
||||||
|
enum {
|
||||||
|
RT_CONSISTENT, /* things are stable */
|
||||||
|
RT_ADD, /* adding a shared library */
|
||||||
|
RT_DELETE /* removing a shared library */
|
||||||
|
} r_state;
|
||||||
|
};
|
||||||
|
#endif /* _LINK_H */
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# $NetBSD: Makefile,v 1.1 1996/12/16 20:37:55 cgd Exp $
|
||||||
|
|
||||||
|
PROG= ld.elf_so
|
||||||
|
|
||||||
|
# Adds SRCS, CFLAGS, LDFLAGS, etc. Must go first so MD startup source
|
||||||
|
# is first.
|
||||||
|
.include "${.CURDIR}/${MACHINE_ARCH}/Makefile.inc"
|
||||||
|
|
||||||
|
SRCS+= rtld.c reloc.c symbol.c malloc.c xmalloc.c xprintf.c debug.c \
|
||||||
|
map_object.c load.c search.c headers.c paths.c
|
||||||
|
CFLAGS+= -Wall -DLIBDIR=\"${LIBDIR}\" -D_PATH_RTLD=\"${BINDIR}/${PROG}\"
|
||||||
|
CFLAGS+= -DDEBUG -DRTLD_LOADER
|
||||||
|
#CFLAGS+= -DRTLD_DEBUG
|
||||||
|
|
||||||
|
LDADD+= -L${LIBDIR} -non_shared -lc_pic
|
||||||
|
DPADD+= ${LIBDIR}/libc_pic.a
|
||||||
|
|
||||||
|
# to be installed
|
||||||
|
HDRS= link.h
|
||||||
|
|
||||||
|
NOMAN=
|
||||||
|
STRIP=
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/${MACHINE_ARCH}
|
||||||
|
|
||||||
|
${PROG}: ${OBJS} ${DPADD}
|
||||||
|
${LD} ${LDFLAGS} -o ${PROG} ${OBJS} ${LDADD}
|
||||||
|
|
||||||
|
includes:
|
||||||
|
@cd ${.CURDIR}; for i in $(HDRS); do \
|
||||||
|
j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \
|
||||||
|
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 $$i \
|
||||||
|
${DESTDIR}/usr/include"; \
|
||||||
|
echo $$j; \
|
||||||
|
eval "$$j"; \
|
||||||
|
done
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
|
@ -0,0 +1,49 @@
|
||||||
|
$NetBSD: README,v 1.1 1996/12/16 20:37:56 cgd Exp $
|
||||||
|
|
||||||
|
BUGS/PROBLEMS:
|
||||||
|
|
||||||
|
* rtld.c around line 147:
|
||||||
|
|
||||||
|
#iffdef __alpha__
|
||||||
|
/* XXX XXX XXX */
|
||||||
|
_rtld_objself.pltgot = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
It's a workaround for a linker bug, and will go away when the linker is
|
||||||
|
fixed.
|
||||||
|
|
||||||
|
* Formerly, _DYNAMIC was _GLOBAL_OFFSET_TABLE_[0], but that isn't true with
|
||||||
|
newer snapshots of gas/binutils (at least on the Alpha), which support
|
||||||
|
multiple GOTs. That's what the OLD_GOT #ifdefs are about.
|
||||||
|
|
||||||
|
* The method used to relocate ld.so is shoddy and fragile. Currently it's
|
||||||
|
something like:
|
||||||
|
|
||||||
|
(1) assembly code relocates RELATIVE relocations in the GOT
|
||||||
|
(on some ports, all relative relocations; this will probably
|
||||||
|
have to be #ifdef'd in reloc.c), assuming that everything
|
||||||
|
in the GOT is a RELATIVE relocation.
|
||||||
|
|
||||||
|
(2) C code relocates the rest of the loader, excluding those
|
||||||
|
RELATIVE relocations already done (via an ... iffy heuristic).
|
||||||
|
|
||||||
|
Something better (like that the glibc ELF ld.so does) should be done
|
||||||
|
eventually, where a single set of C code is compiled twice, once for
|
||||||
|
normal use, and once to be used to relocate the shared linker. No
|
||||||
|
relocations should be processed in assembly language.
|
||||||
|
|
||||||
|
* On the Alpha, this code Really needs to be checked to be sure that
|
||||||
|
it doesn't make calls that could use FP, while doing lazy binding.
|
||||||
|
|
||||||
|
|
||||||
|
TO DO:
|
||||||
|
|
||||||
|
* Support for other platforms (e.g. mips)
|
||||||
|
|
||||||
|
* Support for coexistance of 32-bit and 64-bit ELF on platforms that can
|
||||||
|
do that.
|
||||||
|
|
||||||
|
* KNF
|
||||||
|
|
||||||
|
* Possible support for ldd (standalone operation) and program loading
|
||||||
|
a la the glibc shared loader.
|
|
@ -0,0 +1,6 @@
|
||||||
|
# $NetBSD: Makefile.inc,v 1.1 1996/12/16 20:38:09 cgd Exp $
|
||||||
|
|
||||||
|
SRCS+= rtld_start.S
|
||||||
|
|
||||||
|
CFLAGS+= -fpic -mno-fp-regs -DELFSIZE=64
|
||||||
|
LDFLAGS+= -Bshareable -Bsymbolic -e .rtld_start
|
|
@ -0,0 +1,169 @@
|
||||||
|
/* $NetBSD: rtld_start.S,v 1.1 1996/12/16 20:38:09 cgd 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 <machine/asm.h>
|
||||||
|
|
||||||
|
.extern _GLOBAL_OFFSET_TABLE_
|
||||||
|
|
||||||
|
LEAF(_rtld_start, 0) /* XXX */
|
||||||
|
.set noreorder
|
||||||
|
br pv, $33
|
||||||
|
$33: LDGP(pv)
|
||||||
|
|
||||||
|
/* save away the stack pointer */
|
||||||
|
|
||||||
|
lda s0, 0(sp) /* get argc from stack */
|
||||||
|
lda sp, -16(sp)
|
||||||
|
|
||||||
|
/* save ps_strings pointer */
|
||||||
|
mov a3, s1
|
||||||
|
|
||||||
|
/* Step 1 -- Figure out the displacement */
|
||||||
|
|
||||||
|
br t2, $34 /* get our PC */
|
||||||
|
$34: ldiq t3, $34 /* get where the linker thought we were */
|
||||||
|
subq t2, t3, t8 /* calculate the displacement */
|
||||||
|
|
||||||
|
|
||||||
|
/* Step 2 -- Find bounds of global offset table */
|
||||||
|
|
||||||
|
lda t5, _GLOBAL_OFFSET_TABLE_
|
||||||
|
addq t8, t5, t9 /* add the displacement */
|
||||||
|
#if defined(OLD_GOT)
|
||||||
|
ldq t4, 0(t9) /* Get the address of dynamic table */
|
||||||
|
#else
|
||||||
|
lda t4, _DYNAMIC
|
||||||
|
#endif
|
||||||
|
addq t8, t4, t10 /* add the displacement */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Step 3 -- Every entry in the global offset table needs to
|
||||||
|
* modified for the displacement before any code will work.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$35: ldq t1, 0(t9) /* load the value */
|
||||||
|
addq t8, t1, t1 /* add the displacement */
|
||||||
|
stq t1, 0(t9) /* save the new value */
|
||||||
|
lda t9, 8(t9) /* point to next entry */
|
||||||
|
cmpult t9, t10, t1 /* are we done? */
|
||||||
|
bne t1, $35 /* no, do more */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ya! Things are far enough so we can do some dynamic linking!
|
||||||
|
*/
|
||||||
|
|
||||||
|
lda a0, -16(s0)
|
||||||
|
CALL(_rtld) /* v0 = _rtld(sp); */
|
||||||
|
|
||||||
|
ldq a1, -16(s0) /* our atexit function */
|
||||||
|
ldq a2, -8(s0) /* obj_main entry */
|
||||||
|
lda sp, 16(sp) /* readjust our stack */
|
||||||
|
mov s0, a0 /* stack pointer */
|
||||||
|
mov s1, a3 /* ps_strings pointer */
|
||||||
|
mov v0, t12
|
||||||
|
jsr ra, (v0), 0 /* (*_start)(sp, cleanup, obj); */
|
||||||
|
ldgp gp, 0(ra)
|
||||||
|
|
||||||
|
CALL(exit)
|
||||||
|
halt
|
||||||
|
END(_rtld_start)
|
||||||
|
|
||||||
|
.set noat
|
||||||
|
.globl _rtld_bind_start
|
||||||
|
.ent _rtld_bind_start
|
||||||
|
_rtld_bind_start:
|
||||||
|
|
||||||
|
lda sp, -168(sp)
|
||||||
|
.frame sp, 168, $26
|
||||||
|
/* Preserve all registers that C normally doesn't. */
|
||||||
|
stq $26, 0(sp)
|
||||||
|
stq $0, 8(sp)
|
||||||
|
stq $1, 16(sp)
|
||||||
|
stq $2, 24(sp)
|
||||||
|
stq $3, 32(sp)
|
||||||
|
stq $4, 40(sp)
|
||||||
|
stq $5, 48(sp)
|
||||||
|
stq $6, 56(sp)
|
||||||
|
stq $7, 64(sp)
|
||||||
|
stq $8, 72(sp)
|
||||||
|
stq $16, 80(sp)
|
||||||
|
stq $17, 88(sp)
|
||||||
|
stq $18, 96(sp)
|
||||||
|
stq $19, 104(sp)
|
||||||
|
stq $20, 112(sp)
|
||||||
|
stq $21, 120(sp)
|
||||||
|
stq $22, 128(sp)
|
||||||
|
stq $23, 136(sp)
|
||||||
|
stq $24, 144(sp)
|
||||||
|
stq $25, 152(sp)
|
||||||
|
stq $29, 160(sp)
|
||||||
|
.mask 0x27ff01ff, -168
|
||||||
|
/* Set up our $gp */
|
||||||
|
br gp, $100
|
||||||
|
$100: ldgp gp, 0(gp)
|
||||||
|
.prologue 1
|
||||||
|
/* Set up the arguments for _rtld_bind. */
|
||||||
|
ldq a0, 8(t12) /* object structure */
|
||||||
|
mov at_reg, a1 /* offset of reloc entry */
|
||||||
|
CALL(_rtld_bind)
|
||||||
|
|
||||||
|
/* Move the destination address into position. */
|
||||||
|
mov $0, $27
|
||||||
|
/* Restore program registers. */
|
||||||
|
ldq $26, 0(sp)
|
||||||
|
ldq $0, 8(sp)
|
||||||
|
ldq $1, 16(sp)
|
||||||
|
ldq $2, 24(sp)
|
||||||
|
ldq $3, 32(sp)
|
||||||
|
ldq $4, 40(sp)
|
||||||
|
ldq $5, 48(sp)
|
||||||
|
ldq $6, 56(sp)
|
||||||
|
ldq $7, 64(sp)
|
||||||
|
ldq $8, 72(sp)
|
||||||
|
ldq $16, 80(sp)
|
||||||
|
ldq $17, 88(sp)
|
||||||
|
ldq $18, 96(sp)
|
||||||
|
ldq $19, 104(sp)
|
||||||
|
ldq $20, 112(sp)
|
||||||
|
ldq $21, 120(sp)
|
||||||
|
ldq $22, 128(sp)
|
||||||
|
ldq $23, 136(sp)
|
||||||
|
ldq $24, 144(sp)
|
||||||
|
ldq $25, 152(sp)
|
||||||
|
ldq $29, 160(sp)
|
||||||
|
/* Flush the Icache after having modified the .plt code. */
|
||||||
|
imb
|
||||||
|
/* Clean up and turn control to the destination */
|
||||||
|
lda sp, 168(sp)
|
||||||
|
jmp $31, ($27)
|
||||||
|
.end _rtld_bind_start
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# $NetBSD: Makefile.inc,v 1.1 1996/12/16 20:38:09 cgd Exp $
|
||||||
|
|
||||||
|
SRCS+= rtld_start.S
|
||||||
|
|
||||||
|
CFLAGS+= -fpic -mno-fp-regs -DELFSIZE=64
|
||||||
|
LDFLAGS+= -Bshareable -Bsymbolic -e .rtld_start
|
|
@ -0,0 +1,169 @@
|
||||||
|
/* $NetBSD: rtld_start.S,v 1.1 1996/12/16 20:38:09 cgd 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 <machine/asm.h>
|
||||||
|
|
||||||
|
.extern _GLOBAL_OFFSET_TABLE_
|
||||||
|
|
||||||
|
LEAF(_rtld_start, 0) /* XXX */
|
||||||
|
.set noreorder
|
||||||
|
br pv, $33
|
||||||
|
$33: LDGP(pv)
|
||||||
|
|
||||||
|
/* save away the stack pointer */
|
||||||
|
|
||||||
|
lda s0, 0(sp) /* get argc from stack */
|
||||||
|
lda sp, -16(sp)
|
||||||
|
|
||||||
|
/* save ps_strings pointer */
|
||||||
|
mov a3, s1
|
||||||
|
|
||||||
|
/* Step 1 -- Figure out the displacement */
|
||||||
|
|
||||||
|
br t2, $34 /* get our PC */
|
||||||
|
$34: ldiq t3, $34 /* get where the linker thought we were */
|
||||||
|
subq t2, t3, t8 /* calculate the displacement */
|
||||||
|
|
||||||
|
|
||||||
|
/* Step 2 -- Find bounds of global offset table */
|
||||||
|
|
||||||
|
lda t5, _GLOBAL_OFFSET_TABLE_
|
||||||
|
addq t8, t5, t9 /* add the displacement */
|
||||||
|
#if defined(OLD_GOT)
|
||||||
|
ldq t4, 0(t9) /* Get the address of dynamic table */
|
||||||
|
#else
|
||||||
|
lda t4, _DYNAMIC
|
||||||
|
#endif
|
||||||
|
addq t8, t4, t10 /* add the displacement */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Step 3 -- Every entry in the global offset table needs to
|
||||||
|
* modified for the displacement before any code will work.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$35: ldq t1, 0(t9) /* load the value */
|
||||||
|
addq t8, t1, t1 /* add the displacement */
|
||||||
|
stq t1, 0(t9) /* save the new value */
|
||||||
|
lda t9, 8(t9) /* point to next entry */
|
||||||
|
cmpult t9, t10, t1 /* are we done? */
|
||||||
|
bne t1, $35 /* no, do more */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ya! Things are far enough so we can do some dynamic linking!
|
||||||
|
*/
|
||||||
|
|
||||||
|
lda a0, -16(s0)
|
||||||
|
CALL(_rtld) /* v0 = _rtld(sp); */
|
||||||
|
|
||||||
|
ldq a1, -16(s0) /* our atexit function */
|
||||||
|
ldq a2, -8(s0) /* obj_main entry */
|
||||||
|
lda sp, 16(sp) /* readjust our stack */
|
||||||
|
mov s0, a0 /* stack pointer */
|
||||||
|
mov s1, a3 /* ps_strings pointer */
|
||||||
|
mov v0, t12
|
||||||
|
jsr ra, (v0), 0 /* (*_start)(sp, cleanup, obj); */
|
||||||
|
ldgp gp, 0(ra)
|
||||||
|
|
||||||
|
CALL(exit)
|
||||||
|
halt
|
||||||
|
END(_rtld_start)
|
||||||
|
|
||||||
|
.set noat
|
||||||
|
.globl _rtld_bind_start
|
||||||
|
.ent _rtld_bind_start
|
||||||
|
_rtld_bind_start:
|
||||||
|
|
||||||
|
lda sp, -168(sp)
|
||||||
|
.frame sp, 168, $26
|
||||||
|
/* Preserve all registers that C normally doesn't. */
|
||||||
|
stq $26, 0(sp)
|
||||||
|
stq $0, 8(sp)
|
||||||
|
stq $1, 16(sp)
|
||||||
|
stq $2, 24(sp)
|
||||||
|
stq $3, 32(sp)
|
||||||
|
stq $4, 40(sp)
|
||||||
|
stq $5, 48(sp)
|
||||||
|
stq $6, 56(sp)
|
||||||
|
stq $7, 64(sp)
|
||||||
|
stq $8, 72(sp)
|
||||||
|
stq $16, 80(sp)
|
||||||
|
stq $17, 88(sp)
|
||||||
|
stq $18, 96(sp)
|
||||||
|
stq $19, 104(sp)
|
||||||
|
stq $20, 112(sp)
|
||||||
|
stq $21, 120(sp)
|
||||||
|
stq $22, 128(sp)
|
||||||
|
stq $23, 136(sp)
|
||||||
|
stq $24, 144(sp)
|
||||||
|
stq $25, 152(sp)
|
||||||
|
stq $29, 160(sp)
|
||||||
|
.mask 0x27ff01ff, -168
|
||||||
|
/* Set up our $gp */
|
||||||
|
br gp, $100
|
||||||
|
$100: ldgp gp, 0(gp)
|
||||||
|
.prologue 1
|
||||||
|
/* Set up the arguments for _rtld_bind. */
|
||||||
|
ldq a0, 8(t12) /* object structure */
|
||||||
|
mov at_reg, a1 /* offset of reloc entry */
|
||||||
|
CALL(_rtld_bind)
|
||||||
|
|
||||||
|
/* Move the destination address into position. */
|
||||||
|
mov $0, $27
|
||||||
|
/* Restore program registers. */
|
||||||
|
ldq $26, 0(sp)
|
||||||
|
ldq $0, 8(sp)
|
||||||
|
ldq $1, 16(sp)
|
||||||
|
ldq $2, 24(sp)
|
||||||
|
ldq $3, 32(sp)
|
||||||
|
ldq $4, 40(sp)
|
||||||
|
ldq $5, 48(sp)
|
||||||
|
ldq $6, 56(sp)
|
||||||
|
ldq $7, 64(sp)
|
||||||
|
ldq $8, 72(sp)
|
||||||
|
ldq $16, 80(sp)
|
||||||
|
ldq $17, 88(sp)
|
||||||
|
ldq $18, 96(sp)
|
||||||
|
ldq $19, 104(sp)
|
||||||
|
ldq $20, 112(sp)
|
||||||
|
ldq $21, 120(sp)
|
||||||
|
ldq $22, 128(sp)
|
||||||
|
ldq $23, 136(sp)
|
||||||
|
ldq $24, 144(sp)
|
||||||
|
ldq $25, 152(sp)
|
||||||
|
ldq $29, 160(sp)
|
||||||
|
/* Flush the Icache after having modified the .plt code. */
|
||||||
|
imb
|
||||||
|
/* Clean up and turn control to the destination */
|
||||||
|
lda sp, 168(sp)
|
||||||
|
jmp $31, ($27)
|
||||||
|
.end _rtld_bind_start
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/* $NetBSD: debug.c,v 1.1 1996/12/16 20:37:57 cgd 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 <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
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* $NetBSD: debug.h,v 1.1 1996/12/16 20:37:57 cgd 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 1
|
||||||
|
|
||||||
|
#ifndef __GNUC__ /* { */
|
||||||
|
#error "Sorry, this module relies on some GNU extensions"
|
||||||
|
#endif /* } */
|
||||||
|
|
||||||
|
extern void xprintf(const char *fmt, ...);
|
||||||
|
extern void xvprintf(const char *fmt, va_list ap);
|
||||||
|
extern void debug_printf(const char *, ...);
|
||||||
|
extern int debug;
|
||||||
|
|
||||||
|
#ifdef DEBUG /* { */
|
||||||
|
#define dbg(format, args...) debug_printf(format, ## args)
|
||||||
|
#else /* } { */
|
||||||
|
#define dbg(format, args...) ((void) 0)
|
||||||
|
#endif /* } */
|
||||||
|
|
||||||
|
#endif /* } */
|
|
@ -0,0 +1,266 @@
|
||||||
|
/* $NetBSD: headers.c,v 1.1 1996/12/16 20:37:58 cgd 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 <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 <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(
|
||||||
|
Obj_Entry *obj)
|
||||||
|
{
|
||||||
|
Elf_Dyn *dynp;
|
||||||
|
Needed_Entry **needed_tail = &obj->needed;
|
||||||
|
const Elf_Dyn *dyn_rpath = NULL;
|
||||||
|
enum Elf_e_dynamic_type plttype = Elf_edt_rel;
|
||||||
|
Elf_Word relsize = 0, relasize = 0, pltrelsize = 0, pltrelasize = 0;
|
||||||
|
|
||||||
|
for (dynp = obj->dynamic; dynp->d_tag != Elf_edt_null; ++dynp) {
|
||||||
|
switch(dynp->d_tag) {
|
||||||
|
|
||||||
|
case Elf_edt_rel:
|
||||||
|
obj->rel = (const Elf_Rel *) (obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_relsz:
|
||||||
|
relsize = dynp->d_un.d_val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_relent:
|
||||||
|
assert(dynp->d_un.d_val == sizeof(Elf_Rel));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_jmprel:
|
||||||
|
if (plttype == Elf_edt_rel) {
|
||||||
|
obj->pltrel = (const Elf_Rel *)
|
||||||
|
(obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
} else {
|
||||||
|
obj->pltrela = (const Elf_RelA *)
|
||||||
|
(obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_pltrelsz:
|
||||||
|
if (plttype == Elf_edt_rel) {
|
||||||
|
pltrelsize = dynp->d_un.d_val;
|
||||||
|
} else {
|
||||||
|
pltrelasize = dynp->d_un.d_val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_rela:
|
||||||
|
obj->rela = (const Elf_RelA *) (obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_relasz:
|
||||||
|
relasize = dynp->d_un.d_val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_relaent:
|
||||||
|
assert(dynp->d_un.d_val == sizeof(Elf_RelA));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_pltrel:
|
||||||
|
plttype = dynp->d_un.d_val;
|
||||||
|
assert(plttype == Elf_edt_rel || plttype == Elf_edt_rela);
|
||||||
|
if (plttype == Elf_edt_rela) {
|
||||||
|
obj->pltrela = (const Elf_RelA *) obj->pltrel;
|
||||||
|
obj->pltrel = NULL;
|
||||||
|
pltrelasize = pltrelsize;
|
||||||
|
pltrelsize = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_symtab:
|
||||||
|
obj->symtab = (const Elf_Sym *)
|
||||||
|
(obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_syment:
|
||||||
|
assert(dynp->d_un.d_val == sizeof(Elf_Sym));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_strtab:
|
||||||
|
obj->strtab = (const char *) (obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_strsz:
|
||||||
|
obj->strsize = dynp->d_un.d_val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_hash:
|
||||||
|
{
|
||||||
|
const Elf_Word *hashtab = (const Elf_Word *)
|
||||||
|
(obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
obj->nbuckets = hashtab[0];
|
||||||
|
obj->nchains = hashtab[1];
|
||||||
|
obj->buckets = hashtab + 2;
|
||||||
|
obj->chains = obj->buckets + obj->nbuckets;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_needed:
|
||||||
|
assert(!obj->rtld);
|
||||||
|
{
|
||||||
|
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 Elf_edt_pltgot:
|
||||||
|
obj->pltgot = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_textrel:
|
||||||
|
obj->textrel = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_symbolic:
|
||||||
|
obj->symbolic = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_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 Elf_edt_soname:
|
||||||
|
/* Not used by the dynamic linker. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_init:
|
||||||
|
obj->init = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_fini:
|
||||||
|
obj->fini = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_edt_debug:
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
dynp->d_un.d_ptr = (Elf_Addr) &_rtld_debug;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->rellim = (const Elf_Rel *) ((caddr_t) obj->rel + relsize);
|
||||||
|
obj->relalim = (const Elf_RelA *) ((caddr_t) obj->rela + relasize);
|
||||||
|
obj->pltrellim = (const Elf_Rel *) ((caddr_t) obj->pltrel + pltrelsize);
|
||||||
|
obj->pltrelalim = (const Elf_RelA *) ((caddr_t) obj->pltrela + pltrelasize);
|
||||||
|
|
||||||
|
if (dyn_rpath != NULL) {
|
||||||
|
_rtld_add_paths(&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 = CNEW(Obj_Entry);
|
||||||
|
const Elf_Phdr *phlimit = phdr + phnum;
|
||||||
|
const Elf_Phdr *ph;
|
||||||
|
int nsegs = 0;
|
||||||
|
|
||||||
|
for (ph = phdr; ph < phlimit; ++ph) {
|
||||||
|
switch(ph->p_type) {
|
||||||
|
|
||||||
|
case Elf_pt_phdr:
|
||||||
|
assert((const Elf_Phdr *) ph->p_vaddr == phdr);
|
||||||
|
obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
|
||||||
|
obj->phsize = ph->p_memsz;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_pt_load:
|
||||||
|
assert(nsegs < 2);
|
||||||
|
if (nsegs == 0) { /* First load segment */
|
||||||
|
obj->vaddrbase = round_down(ph->p_vaddr);
|
||||||
|
obj->mapbase = (caddr_t) obj->vaddrbase;
|
||||||
|
obj->relocbase = obj->mapbase - obj->vaddrbase;
|
||||||
|
obj->textsize = round_up(ph->p_vaddr + ph->p_memsz) -
|
||||||
|
obj->vaddrbase;
|
||||||
|
} else { /* Last load segment */
|
||||||
|
obj->mapsize = round_up(ph->p_vaddr + ph->p_memsz) -
|
||||||
|
obj->vaddrbase;
|
||||||
|
}
|
||||||
|
++nsegs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_pt_dynamic:
|
||||||
|
obj->dynamic = (Elf_Dyn *) ph->p_vaddr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(nsegs == 2);
|
||||||
|
|
||||||
|
obj->entry = entry;
|
||||||
|
return obj;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* $NetBSD: link.h,v 1.1 1996/12/16 20:37:59 cgd Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This only exists for GDB.
|
||||||
|
*/
|
||||||
|
#ifndef _LINK_H
|
||||||
|
#define _LINK_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
struct link_map {
|
||||||
|
caddr_t l_addr; /* Base Address of library */
|
||||||
|
const char *l_name; /* Absolute Path to Library */
|
||||||
|
void *l_ld; /* Pointer to .dynamic in memory */
|
||||||
|
struct link_map *l_next, *l_prev; /* linked list of of mapped libs */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct r_debug {
|
||||||
|
int r_version; /* not used */
|
||||||
|
struct link_map *r_map; /* list of loaded images */
|
||||||
|
void (*r_brk)(void); /* pointer to break point */
|
||||||
|
enum {
|
||||||
|
RT_CONSISTENT, /* things are stable */
|
||||||
|
RT_ADD, /* adding a shared library */
|
||||||
|
RT_DELETE /* removing a shared library */
|
||||||
|
} r_state;
|
||||||
|
};
|
||||||
|
#endif /* _LINK_H */
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/* $NetBSD: load.c,v 1.1 1996/12/16 20:37:59 cgd 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 <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 <dirent.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "rtld.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load a shared object into memory, if it is not already loaded. The
|
||||||
|
* argument must be a string allocated on the heap. This function assumes
|
||||||
|
* responsibility for freeing it when necessary.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the Obj_Entry for the object. Returns NULL
|
||||||
|
* on failure.
|
||||||
|
*/
|
||||||
|
Obj_Entry *
|
||||||
|
_rtld_load_object(
|
||||||
|
char *filepath)
|
||||||
|
{
|
||||||
|
Obj_Entry *obj;
|
||||||
|
|
||||||
|
for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
|
||||||
|
if (strcmp(obj->path, filepath) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (obj == NULL) { /* First use of this object, so we must map it in */
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if ((fd = open(filepath, O_RDONLY)) == -1) {
|
||||||
|
_rtld_error("Cannot open \"%s\"", filepath);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
obj = _rtld_map_object(filepath, fd);
|
||||||
|
close(fd);
|
||||||
|
if (obj == NULL) {
|
||||||
|
free(filepath);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->path = filepath;
|
||||||
|
_rtld_digest_dynamic(obj);
|
||||||
|
|
||||||
|
*_rtld_objtail = obj;
|
||||||
|
_rtld_objtail = &obj->next;
|
||||||
|
#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);
|
||||||
|
} else
|
||||||
|
free(filepath);
|
||||||
|
|
||||||
|
++obj->refcount;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
char *libpath = _rtld_find_library(name, obj);
|
||||||
|
|
||||||
|
if (libpath == NULL) {
|
||||||
|
status = -1;
|
||||||
|
} else {
|
||||||
|
needed->obj = _rtld_load_object(libpath);
|
||||||
|
if (needed->obj == NULL)
|
||||||
|
status = -1; /* FIXME - cleanup */
|
||||||
|
}
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
if (status == -1)
|
||||||
|
return status;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
|
@ -0,0 +1,472 @@
|
||||||
|
/* $NetBSD: malloc.c,v 1.1 1996/12/16 20:38:00 cgd Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. 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 "rtldenv.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
static void morecore();
|
||||||
|
static int findbucket();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pre-allocate mmap'ed pages
|
||||||
|
*/
|
||||||
|
#define NPOOLPAGES (32*1024/pagesz)
|
||||||
|
static caddr_t pagepool_start, pagepool_end;
|
||||||
|
static int morepages();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
};
|
||||||
|
|
||||||
|
#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 int pagesz; /* page size */
|
||||||
|
static int 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
|
||||||
|
|
||||||
|
/* Polstra's debugging stuff */
|
||||||
|
extern void xprintf(const char *, ...);
|
||||||
|
#define TRACE() xprintf("TRACE %s:%d\n", __FILE__, __LINE__)
|
||||||
|
|
||||||
|
void *
|
||||||
|
malloc(nbytes)
|
||||||
|
size_t nbytes;
|
||||||
|
{
|
||||||
|
register union overhead *op;
|
||||||
|
register int bucket;
|
||||||
|
register long n;
|
||||||
|
register 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 = getpagesize();
|
||||||
|
if (morepages(NPOOLPAGES) == 0)
|
||||||
|
return NULL;
|
||||||
|
op = (union overhead *)(pagepool_start);
|
||||||
|
n = n - sizeof (*op) - (((char *)op - (char *)NULL) & (n - 1));
|
||||||
|
if (n < 0)
|
||||||
|
n += pagesz;
|
||||||
|
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(bucket)
|
||||||
|
int bucket;
|
||||||
|
{
|
||||||
|
register union overhead *op;
|
||||||
|
register int sz; /* size of desired block */
|
||||||
|
int amt; /* amount to allocate */
|
||||||
|
int 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);
|
||||||
|
#else
|
||||||
|
if (sz <= 0)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
if (sz < pagesz) {
|
||||||
|
amt = pagesz;
|
||||||
|
nblks = amt / sz;
|
||||||
|
} else {
|
||||||
|
amt = sz + pagesz;
|
||||||
|
nblks = 1;
|
||||||
|
}
|
||||||
|
if (amt > pagepool_end - pagepool_start)
|
||||||
|
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
|
||||||
|
free(cp)
|
||||||
|
void *cp;
|
||||||
|
{
|
||||||
|
register int size;
|
||||||
|
register 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When a program attempts "storage compaction" as mentioned in the
|
||||||
|
* old malloc man page, it realloc's an already freed block. Usually
|
||||||
|
* this is the last block it freed; occasionally it might be farther
|
||||||
|
* back. We have to search all the free lists for the block in order
|
||||||
|
* to determine its bucket: 1st we make one pass thru the lists
|
||||||
|
* checking only the first block in each; if that fails we search
|
||||||
|
* ``realloc_srchlen'' blocks in each list for a match (the variable
|
||||||
|
* is extern so the caller can modify it). If that fails we just copy
|
||||||
|
* however many bytes was given to realloc() and hope it's not huge.
|
||||||
|
*/
|
||||||
|
int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
|
||||||
|
|
||||||
|
void *
|
||||||
|
realloc(cp, nbytes)
|
||||||
|
void *cp;
|
||||||
|
size_t nbytes;
|
||||||
|
{
|
||||||
|
register u_int onb;
|
||||||
|
register int i;
|
||||||
|
union overhead *op;
|
||||||
|
char *res;
|
||||||
|
int was_alloced = 0;
|
||||||
|
|
||||||
|
if (cp == NULL)
|
||||||
|
return (malloc(nbytes));
|
||||||
|
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
|
||||||
|
if (op->ov_magic == MAGIC) {
|
||||||
|
was_alloced++;
|
||||||
|
i = op->ov_index;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Already free, doing "compaction".
|
||||||
|
*
|
||||||
|
* Search for the old block of memory on the
|
||||||
|
* free list. First, check the most common
|
||||||
|
* case (last element free'd), then (this failing)
|
||||||
|
* the last ``realloc_srchlen'' items free'd.
|
||||||
|
* If all lookups fail, then assume the size of
|
||||||
|
* the memory block being realloc'd is the
|
||||||
|
* largest possible (so that all "nbytes" of new
|
||||||
|
* memory are copied into). Note that this could cause
|
||||||
|
* a memory fault if the old area was tiny, and the moon
|
||||||
|
* is gibbous. However, that is very unlikely.
|
||||||
|
*/
|
||||||
|
if ((i = findbucket(op, 1)) < 0 &&
|
||||||
|
(i = findbucket(op, realloc_srchlen)) < 0)
|
||||||
|
i = NBUCKETS;
|
||||||
|
}
|
||||||
|
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 (was_alloced) {
|
||||||
|
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
|
||||||
|
free(cp);
|
||||||
|
}
|
||||||
|
if ((res = malloc(nbytes)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
if (cp != res) /* common optimization if "compacting" */
|
||||||
|
memcpy(res, cp, (nbytes < onb) ? nbytes : onb);
|
||||||
|
return (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search ``srchlen'' elements of each free list for a block whose
|
||||||
|
* header starts at ``freep''. If srchlen is -1 search the whole list.
|
||||||
|
* Return bucket number, or -1 if not found.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
findbucket(freep, srchlen)
|
||||||
|
union overhead *freep;
|
||||||
|
int srchlen;
|
||||||
|
{
|
||||||
|
register union overhead *p;
|
||||||
|
register int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < NBUCKETS; i++) {
|
||||||
|
j = 0;
|
||||||
|
for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
|
||||||
|
if (p == freep)
|
||||||
|
return (i);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#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.
|
||||||
|
*/
|
||||||
|
mstats(s)
|
||||||
|
char *s;
|
||||||
|
{
|
||||||
|
register int i, j;
|
||||||
|
register 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(n)
|
||||||
|
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_end - pagepool_start > 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_COPY, 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;
|
||||||
|
}
|
|
@ -0,0 +1,264 @@
|
||||||
|
/* $NetBSD: map_object.c,v 1.1 1996/12/16 20:38:01 cgd 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "rtld.h"
|
||||||
|
|
||||||
|
#define CONCAT(x,y) __CONCAT(x,y)
|
||||||
|
#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
|
||||||
|
#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
|
||||||
|
#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE))
|
||||||
|
#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
|
||||||
|
|
||||||
|
static int protflags(int); /* Elf flags -> mmap protection */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
Obj_Entry *obj;
|
||||||
|
union {
|
||||||
|
Elf_Ehdr hdr;
|
||||||
|
char buf[PAGESIZE];
|
||||||
|
} u;
|
||||||
|
int nbytes;
|
||||||
|
Elf_Phdr *phdr;
|
||||||
|
Elf_Phdr *phlimit;
|
||||||
|
Elf_Phdr *segs[2];
|
||||||
|
int nsegs;
|
||||||
|
Elf_Phdr *phdyn;
|
||||||
|
Elf_Phdr *phphdr;
|
||||||
|
caddr_t mapbase;
|
||||||
|
size_t mapsize;
|
||||||
|
Elf_Off base_offset;
|
||||||
|
Elf_Addr base_vaddr;
|
||||||
|
Elf_Addr base_vlimit;
|
||||||
|
caddr_t base_addr;
|
||||||
|
Elf_Off data_offset;
|
||||||
|
Elf_Addr data_vaddr;
|
||||||
|
Elf_Addr data_vlimit;
|
||||||
|
caddr_t data_addr;
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
Elf_Addr clear_vaddr;
|
||||||
|
caddr_t clear_addr;
|
||||||
|
size_t nclear;
|
||||||
|
Elf_Addr bss_vaddr;
|
||||||
|
Elf_Addr bss_vlimit;
|
||||||
|
caddr_t bss_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((nbytes = read(fd, u.buf, PAGESIZE)) == -1) {
|
||||||
|
_rtld_error("%s: read error: %s", path, xstrerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the file is valid */
|
||||||
|
if (nbytes < sizeof(Elf_Ehdr)
|
||||||
|
|| memcmp(Elf_e_ident, u.hdr.e_ident, Elf_e_siz) != 0) {
|
||||||
|
_rtld_error("%s: unrecognized file format", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Elf_e_ident includes class */
|
||||||
|
if (u.hdr.e_ident[Elf_ei_version] != Elf_ev_current
|
||||||
|
|| u.hdr.e_version != Elf_ev_current
|
||||||
|
|| u.hdr.e_ident[Elf_ei_data] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
|
||||||
|
_rtld_error("%s: Unsupported file version", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (u.hdr.e_type != Elf_et_exec && u.hdr.e_type != Elf_et_dyn) {
|
||||||
|
_rtld_error("%s: Unsupported file type", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
switch (u.hdr.e_machine) {
|
||||||
|
ELFDEFNNAME(MACHDEP_ID_CASES)
|
||||||
|
|
||||||
|
default:
|
||||||
|
_rtld_error("%s: Unsupported machine", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(u.hdr.e_phentsize == sizeof(Elf_Phdr));
|
||||||
|
assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGESIZE);
|
||||||
|
assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 *) (u.buf + u.hdr.e_phoff);
|
||||||
|
phlimit = phdr + u.hdr.e_phnum;
|
||||||
|
nsegs = 0;
|
||||||
|
phdyn = NULL;
|
||||||
|
phphdr = NULL;
|
||||||
|
while(phdr < phlimit) {
|
||||||
|
switch(phdr->p_type) {
|
||||||
|
|
||||||
|
case Elf_pt_load:
|
||||||
|
assert(nsegs < 2);
|
||||||
|
segs[nsegs] = phdr;
|
||||||
|
++nsegs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_pt_phdr:
|
||||||
|
phphdr = phdr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Elf_pt_dynamic:
|
||||||
|
phdyn = phdr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++phdr;
|
||||||
|
}
|
||||||
|
if (phdyn == NULL) {
|
||||||
|
_rtld_error("%s: not dynamically-linked", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(nsegs == 2);
|
||||||
|
#ifdef __i386__
|
||||||
|
assert(segs[0]->p_align <= PAGESIZE);
|
||||||
|
assert(segs[1]->p_align <= PAGESIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map the entire address space of the object, to stake out our
|
||||||
|
* contiguous region, and to establish the base address for relocation.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
mapsize = base_vlimit - base_vaddr;
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
base_addr = u.hdr.e_type == Elf_et_exec ? (caddr_t) base_vaddr : NULL;
|
||||||
|
#else
|
||||||
|
base_addr = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mapbase = mmap(base_addr, mapsize, protflags(segs[0]->p_flags),
|
||||||
|
MAP_PRIVATE, fd, base_offset);
|
||||||
|
if (mapbase == (caddr_t) -1) {
|
||||||
|
_rtld_error("mmap of entire address space failed: %s", xstrerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (base_addr != NULL && mapbase != base_addr) {
|
||||||
|
_rtld_error("mmap returned wrong address: wanted %p, got %p", base_addr,
|
||||||
|
mapbase);
|
||||||
|
munmap(mapbase, mapsize);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overlay the data segment onto the proper region. */
|
||||||
|
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_addr = mapbase + (data_vaddr - base_vaddr);
|
||||||
|
if (mmap(data_addr, data_vlimit - data_vaddr, protflags(segs[1]->p_flags),
|
||||||
|
MAP_PRIVATE|MAP_FIXED, fd, data_offset) == (caddr_t) -1) {
|
||||||
|
_rtld_error("mmap of data failed: %s", xstrerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
/* Clear any BSS in the last page of the data segment. */
|
||||||
|
clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
|
||||||
|
clear_addr = mapbase + (clear_vaddr - base_vaddr);
|
||||||
|
if ((nclear = data_vlimit - clear_vaddr) > 0)
|
||||||
|
memset(clear_addr, 0, nclear);
|
||||||
|
|
||||||
|
/* Overlay the BSS segment onto the proper region. */
|
||||||
|
bss_vaddr = data_vlimit;
|
||||||
|
bss_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
|
||||||
|
bss_addr = mapbase + (bss_vaddr - base_vaddr);
|
||||||
|
if (bss_vlimit > bss_vaddr) { /* There is something to do */
|
||||||
|
if (mmap(bss_addr, bss_vlimit - bss_vaddr, protflags(segs[1]->p_flags),
|
||||||
|
MAP_PRIVATE|MAP_FIXED|MAP_ANON, -1, 0) == (caddr_t) -1) {
|
||||||
|
_rtld_error("mmap of bss failed: %s", xstrerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
obj = CNEW(Obj_Entry);
|
||||||
|
obj->mapbase = mapbase;
|
||||||
|
obj->mapsize = mapsize;
|
||||||
|
obj->textsize = round_up(segs[0]->p_vaddr + segs[0]->p_memsz) - base_vaddr;
|
||||||
|
obj->vaddrbase = base_vaddr;
|
||||||
|
obj->relocbase = mapbase - base_vaddr;
|
||||||
|
obj->dynamic = (Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr);
|
||||||
|
if (u.hdr.e_entry != 0)
|
||||||
|
obj->entry = (caddr_t) (obj->relocbase + u.hdr.e_entry);
|
||||||
|
if (phphdr != NULL) {
|
||||||
|
obj->phdr = (const Elf_Phdr *) (obj->relocbase + phphdr->p_vaddr);
|
||||||
|
obj->phsize = phphdr->p_memsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 & Elf_pf_r) prot |= PROT_READ;
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
if (elfflags & Elf_pf_w) prot |= PROT_WRITE;
|
||||||
|
#endif
|
||||||
|
if (elfflags & Elf_pf_x) prot |= PROT_EXEC;
|
||||||
|
return prot;
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/* $NetBSD: paths.c,v 1.1 1996/12/16 20:38:01 cgd 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 <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 <dirent.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "rtld.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_rtld_add_paths(
|
||||||
|
Search_Path **path_p,
|
||||||
|
const char *pathstr)
|
||||||
|
{
|
||||||
|
Search_Path *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)];
|
||||||
|
|
||||||
|
if (bp < ep && (path = _rtld_find_path(*head_p, bp, ep - bp)) == NULL) {
|
||||||
|
char *cp;
|
||||||
|
path = CNEW(Search_Path);
|
||||||
|
path->sp_pathlen = ep - bp;
|
||||||
|
cp = xmalloc(path->sp_pathlen + 1);
|
||||||
|
strncpy(cp, bp, path->sp_pathlen);
|
||||||
|
cp[path->sp_pathlen] = '\0';
|
||||||
|
path->sp_path = cp;
|
||||||
|
path->sp_next = (*path_p);
|
||||||
|
(*path_p) = path;
|
||||||
|
path_p = &path->sp_next;
|
||||||
|
|
||||||
|
dbg(" added path \"%s\"", path->sp_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ep[0] == '\0')
|
||||||
|
break;
|
||||||
|
pathstr = ep + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,431 @@
|
||||||
|
/* $NetBSD: reloc.c,v 1.1 1996/12/16 20:38:02 cgd 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 <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 <dirent.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "rtld.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
memcpy(dstaddr, srcaddr, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_rtld_relocate_nonplt_object(
|
||||||
|
const Obj_Entry *obj,
|
||||||
|
const Elf_RelA *rela)
|
||||||
|
{
|
||||||
|
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
|
||||||
|
|
||||||
|
switch (ELF_R_TYPE(rela->r_info)) {
|
||||||
|
|
||||||
|
case R_TYPE(NONE):
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
case R_386_GOT32: {
|
||||||
|
const Elf_Sym *def;
|
||||||
|
const Obj_Entry *defobj;
|
||||||
|
|
||||||
|
def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
|
||||||
|
if (def == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (*where != (Elf_Addr) (defobj->relocbase + def->st_value + rela->r_addend))
|
||||||
|
*where = (Elf_Addr) (defobj->relocbase + def->st_value + rela->r_addend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case R_386_PC32:
|
||||||
|
/*
|
||||||
|
* I don't think the dynamic linker should ever see this
|
||||||
|
* type of relocation. But the binutils-2.6 tools sometimes
|
||||||
|
* generate it.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const Elf_Sym *def;
|
||||||
|
const Obj_Entry *defobj;
|
||||||
|
|
||||||
|
def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
|
||||||
|
if (def == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*where += (Elf_Addr) (defobj->relocbase + def->st_value)
|
||||||
|
- (Elf_Addr) where;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef __alpha__
|
||||||
|
case R_ALPHA_REFQUAD: {
|
||||||
|
const Elf_Sym *def;
|
||||||
|
const Obj_Entry *defobj;
|
||||||
|
Elf_Addr tmp_value;
|
||||||
|
|
||||||
|
def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
|
||||||
|
if (def == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tmp_value = (Elf_Addr) (defobj->relocbase + def->st_value)
|
||||||
|
+ *where + rela->r_addend;
|
||||||
|
if (*where != tmp_value)
|
||||||
|
*where = tmp_value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case R_TYPE(GLOB_DAT):
|
||||||
|
{
|
||||||
|
const Elf_Sym *def;
|
||||||
|
const Obj_Entry *defobj;
|
||||||
|
|
||||||
|
def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
|
||||||
|
if (def == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (*where != (Elf_Addr) (defobj->relocbase + def->st_value))
|
||||||
|
*where = (Elf_Addr) (defobj->relocbase + def->st_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case R_TYPE(RELATIVE): {
|
||||||
|
extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
|
||||||
|
extern Elf_Dyn _DYNAMIC;
|
||||||
|
|
||||||
|
if (obj != &_rtld_objself ||
|
||||||
|
(caddr_t)where < (caddr_t)_GLOBAL_OFFSET_TABLE_ ||
|
||||||
|
(caddr_t)where >= (caddr_t)&_DYNAMIC)
|
||||||
|
*where += (Elf_Addr) obj->relocbase;
|
||||||
|
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->mainprog) {
|
||||||
|
_rtld_error("%s: Unexpected R_COPY relocation in shared library",
|
||||||
|
obj->path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
const Elf_Sym *def;
|
||||||
|
const Obj_Entry *defobj;
|
||||||
|
|
||||||
|
def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, true);
|
||||||
|
dbg("sym = %d, type = %d, offset = %p, addend = %p, contents = %p, symbol = %s",
|
||||||
|
ELF_R_SYM(rela->r_info), ELF_R_TYPE(rela->r_info),
|
||||||
|
rela->r_offset, rela->r_addend, *where,
|
||||||
|
def ? defobj->strtab + def->st_name : "??");
|
||||||
|
_rtld_error("%s: Unsupported relocation type %d in non-PLT relocations\n",
|
||||||
|
obj->path, ELF_R_TYPE(rela->r_info));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_rtld_relocate_plt_object(
|
||||||
|
const Obj_Entry *obj,
|
||||||
|
const Elf_RelA *rela,
|
||||||
|
bool bind_now)
|
||||||
|
{
|
||||||
|
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
|
||||||
|
Elf_Addr new_value;
|
||||||
|
|
||||||
|
/* Fully resolve procedure addresses now */
|
||||||
|
if (bind_now || obj->pltgot == NULL) {
|
||||||
|
const Elf_Sym *def;
|
||||||
|
const Obj_Entry *defobj;
|
||||||
|
|
||||||
|
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
|
||||||
|
|
||||||
|
def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, true);
|
||||||
|
if (def == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
new_value = (Elf_Addr) (defobj->relocbase + def->st_value);
|
||||||
|
#if 0
|
||||||
|
dbg("fixup %s in %s --> %p in %s",
|
||||||
|
defobj->strtab + def->st_name, obj->path,
|
||||||
|
new_value, defobj->path);
|
||||||
|
#endif
|
||||||
|
} else if (!obj->mainprog) {
|
||||||
|
/* Just relocate the GOT slots pointing into the PLT */
|
||||||
|
new_value = *where + (Elf_Addr) (obj->relocbase);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Since this page is probably copy-on-write, let's not write
|
||||||
|
* it unless we really really have to.
|
||||||
|
*/
|
||||||
|
if (*where != new_value)
|
||||||
|
*where = new_value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
caddr_t
|
||||||
|
_rtld_bind(
|
||||||
|
const Obj_Entry *obj,
|
||||||
|
Elf_Word reloff)
|
||||||
|
{
|
||||||
|
const Elf_RelA *rela;
|
||||||
|
Elf_RelA ourrela;
|
||||||
|
|
||||||
|
if (obj->pltrel != NULL) {
|
||||||
|
ourrela.r_info = ((const Elf_Rel *) ((caddr_t) obj->pltrel + reloff))->r_info;
|
||||||
|
ourrela.r_offset = ((const Elf_Rel *) ((caddr_t) obj->pltrel + reloff))->r_offset;
|
||||||
|
rela = &ourrela;
|
||||||
|
} else {
|
||||||
|
rela = (const Elf_RelA *) ((caddr_t) obj->pltrela + reloff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (_rtld_relocate_plt_object(obj, rela, true) < 0)
|
||||||
|
_rtld_die();
|
||||||
|
|
||||||
|
return *(caddr_t *)(obj->relocbase + rela->r_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg(" relocating %s (%d/%d rel/rela, %d/%d plt rel/rela)",
|
||||||
|
obj->path,
|
||||||
|
obj->rellim - obj->rel, obj->relalim - obj->rela,
|
||||||
|
obj->pltrellim - obj->pltrel, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->rel != NULL) {
|
||||||
|
/* Process the non-PLT relocations. */
|
||||||
|
const Elf_Rel *rel;
|
||||||
|
for (rel = obj->rel; rel < obj->rellim; ++rel) {
|
||||||
|
Elf_RelA ourrela;
|
||||||
|
ourrela.r_info = rel->r_info;
|
||||||
|
ourrela.r_offset = rel->r_offset;
|
||||||
|
ourrela.r_addend = *(Elf_Word *) (obj->relocbase + rel->r_offset);
|
||||||
|
|
||||||
|
if (_rtld_relocate_nonplt_object(obj, &ourrela) < 0)
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->rela != NULL) {
|
||||||
|
/* Process the non-PLT relocations. */
|
||||||
|
const Elf_RelA *rela;
|
||||||
|
for (rela = obj->rela; rela < obj->relalim; ++rela) {
|
||||||
|
if (_rtld_relocate_nonplt_object(obj, rela) < 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the PLT relocations. */
|
||||||
|
if (obj->pltrel != NULL) {
|
||||||
|
const Elf_Rel *rel;
|
||||||
|
for (rel = obj->pltrel; rel < obj->pltrellim; ++rel) {
|
||||||
|
Elf_RelA ourrela;
|
||||||
|
ourrela.r_info = rel->r_info;
|
||||||
|
ourrela.r_offset = rel->r_offset;
|
||||||
|
ourrela.r_addend = *(Elf_Word *) (obj->relocbase + rel->r_offset);
|
||||||
|
if (_rtld_relocate_plt_object(obj, &ourrela, bind_now) < 0)
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->pltrela != NULL) {
|
||||||
|
const Elf_RelA *rela;
|
||||||
|
for (rela = obj->pltrela; rela < obj->pltrelalim; ++rela) {
|
||||||
|
if (_rtld_relocate_plt_object(obj, rela, bind_now) < 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 = _rtld_dlopen;
|
||||||
|
obj->dlsym = _rtld_dlsym;
|
||||||
|
obj->dlerror = _rtld_dlerror;
|
||||||
|
obj->dlclose = _rtld_dlclose;
|
||||||
|
|
||||||
|
/* Set the special PLTGOT entries. */
|
||||||
|
if (obj->pltgot != NULL) {
|
||||||
|
#if defined(__i386__)
|
||||||
|
obj->pltgot[1] = (Elf_Addr) obj;
|
||||||
|
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
|
||||||
|
#endif
|
||||||
|
#if defined(__alpha__)
|
||||||
|
/* This function will be called to perform the relocation. */
|
||||||
|
obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
|
||||||
|
/* Identify this shared object */
|
||||||
|
obj->pltgot[3] = (Elf_Addr) obj;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,568 @@
|
||||||
|
/* $NetBSD: rtld.c,v 1.1 1996/12/16 20:38:03 cgd 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 <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 <dirent.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "rtld.h"
|
||||||
|
|
||||||
|
/* FIXME - Theses don't belong here. */
|
||||||
|
#define RTLD_LAZY 1
|
||||||
|
#define RTLD_NOW 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debugging support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef void (*funcptr)(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function declarations.
|
||||||
|
*/
|
||||||
|
static void _rtld_init(caddr_t);
|
||||||
|
static void _rtld_exit(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data declarations.
|
||||||
|
*/
|
||||||
|
static char *error_message; /* Message for dlopen(), or NULL */
|
||||||
|
|
||||||
|
struct r_debug _rtld_debug; /* for GDB; */
|
||||||
|
bool _rtld_trust; /* False for setuid and setgid programs */
|
||||||
|
Obj_Entry *_rtld_objlist; /* Head of linked list of shared objects */
|
||||||
|
Obj_Entry **_rtld_objtail; /* Link field of last object in list */
|
||||||
|
Obj_Entry *_rtld_objmain; /* The main program shared object */
|
||||||
|
Obj_Entry _rtld_objself; /* The dynamic linker shared object */
|
||||||
|
|
||||||
|
Search_Path *_rtld_paths;
|
||||||
|
/*
|
||||||
|
* Global declarations normally provided by crt0.
|
||||||
|
*/
|
||||||
|
char *__progname;
|
||||||
|
char **environ;
|
||||||
|
|
||||||
|
#ifdef OLD_GOT
|
||||||
|
extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
|
||||||
|
#else
|
||||||
|
extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
|
||||||
|
extern Elf_Dyn _DYNAMIC;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rtld_call_fini_functions(
|
||||||
|
Obj_Entry *first)
|
||||||
|
{
|
||||||
|
Obj_Entry *obj;
|
||||||
|
|
||||||
|
for (obj = first; obj != NULL; obj = obj->next)
|
||||||
|
if (obj->fini != NULL)
|
||||||
|
(*obj->fini)();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rtld_call_init_functions(
|
||||||
|
Obj_Entry *first)
|
||||||
|
{
|
||||||
|
if (first != NULL) {
|
||||||
|
_rtld_call_init_functions(first->next);
|
||||||
|
if (first->init != NULL)
|
||||||
|
(*first->init)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the dynamic linker. The argument is the address at which
|
||||||
|
* the dynamic linker has been mapped into memory. The primary task of
|
||||||
|
* this function is to relocate the dynamic linker.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_rtld_init(
|
||||||
|
caddr_t mapbase)
|
||||||
|
{
|
||||||
|
_rtld_add_paths(&_rtld_paths, RTLD_DEFAULT_LIBRARY_PATH);
|
||||||
|
|
||||||
|
/* Conjure up an Obj_Entry structure for the dynamic linker. */
|
||||||
|
|
||||||
|
_rtld_objself.path = _PATH_RTLD;
|
||||||
|
_rtld_objself.rtld = true;
|
||||||
|
_rtld_objself.mapbase = mapbase;
|
||||||
|
_rtld_objself.relocbase = mapbase;
|
||||||
|
_rtld_objself.pltgot = NULL;
|
||||||
|
#ifdef OLD_GOT
|
||||||
|
_rtld_objself.dynamic = (Elf_Dyn *) _GLOBAL_OFFSET_TABLE_[0];
|
||||||
|
#else
|
||||||
|
_rtld_objself.dynamic = &_DYNAMIC;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_rtld_digest_dynamic(&_rtld_objself);
|
||||||
|
#ifdef __alpha__
|
||||||
|
/* XXX XXX XXX */
|
||||||
|
_rtld_objself.pltgot = NULL;
|
||||||
|
#endif
|
||||||
|
assert(_rtld_objself.needed == NULL);
|
||||||
|
assert(!_rtld_objself.textrel);
|
||||||
|
|
||||||
|
/* Set up the _rtld_objlist pointer, so that rtld symbols can be found. */
|
||||||
|
_rtld_objlist = &_rtld_objself;
|
||||||
|
|
||||||
|
_rtld_relocate_objects(&_rtld_objself, true);
|
||||||
|
|
||||||
|
/* Make the object list empty again. */
|
||||||
|
_rtld_objlist = NULL;
|
||||||
|
_rtld_objtail = &_rtld_objlist;
|
||||||
|
|
||||||
|
_rtld_debug.r_brk = _rtld_debug_state;
|
||||||
|
_rtld_debug.r_state = RT_CONSISTENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup procedure. It will be called (by the atexit() mechanism) just
|
||||||
|
* before the process exits.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_rtld_exit(void)
|
||||||
|
{
|
||||||
|
dbg("rtld_exit()");
|
||||||
|
|
||||||
|
_rtld_call_fini_functions(_rtld_objlist->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main entry point for dynamic linking. The argument is the stack
|
||||||
|
* pointer. The stack is expected to be laid out as described in the
|
||||||
|
* SVR4 ABI specification, Intel 386 Processor Supplement. Specifically,
|
||||||
|
* the stack pointer points to a word containing ARGC. Following that
|
||||||
|
* in the stack is a null-terminated sequence of pointers to argument
|
||||||
|
* strings. Then comes a null-terminated sequence of pointers to
|
||||||
|
* environment strings. Finally, there is a sequence of "auxiliary
|
||||||
|
* vector" entries.
|
||||||
|
*
|
||||||
|
* This function returns the entry point for the main program in %eax,
|
||||||
|
* and the dynamic linker's exit procedure in %edx. We accomplish this
|
||||||
|
* by declaring the return value to have the 64-bit type "long long".
|
||||||
|
* Such values are returned with their most-significant 32 bits in %edx,
|
||||||
|
* and their least-significant 32 bits in %eax.
|
||||||
|
*/
|
||||||
|
Elf_Addr
|
||||||
|
_rtld(
|
||||||
|
Elf_Word *sp)
|
||||||
|
{
|
||||||
|
const AuxInfo *aux_info[AUX_count];
|
||||||
|
int i = 0;
|
||||||
|
char **env;
|
||||||
|
const AuxInfo *aux;
|
||||||
|
const AuxInfo *auxp;
|
||||||
|
Elf_Word * const osp = sp;
|
||||||
|
bool bind_now = 0;
|
||||||
|
const char *ld_bind_now;
|
||||||
|
const char **argv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On entry, the dynamic linker itself has not been relocated yet.
|
||||||
|
* Be very careful not to reference any global data until after
|
||||||
|
* _rtld_init has returned. It is OK to reference file-scope statics
|
||||||
|
* and string constants, and to call static and global functions.
|
||||||
|
*/
|
||||||
|
/* Find the auxiliary vector on the stack. */
|
||||||
|
/* first Elf_Word reserved to address of exit routine */
|
||||||
|
#ifdef RTLD_DEBUG
|
||||||
|
xprintf("sp = %p, argc = %d, argv = %p <%s>\n", sp, sp[2], &sp[3], sp[3]);
|
||||||
|
xprintf("got is at %p, dynamic is at %p\n", _GLOBAL_OFFSET_TABLE_, &_DYNAMIC);
|
||||||
|
debug = 1;
|
||||||
|
xprintf("_ctype_ is %p\n", _ctype_);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sp += 2; /* skip over return argument space */
|
||||||
|
argv = (const char **) &sp[1];
|
||||||
|
sp += sp[0] + 2; /* Skip over argc, arguments, and NULL terminator */
|
||||||
|
env = (char **) sp;
|
||||||
|
while (*sp++ != 0) { /* Skip over environment, and NULL terminator */
|
||||||
|
#ifdef RTLD_DEBUG
|
||||||
|
xprintf("env[%d] = %p\n", i++, sp[-1]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
aux = (const AuxInfo *) sp;
|
||||||
|
|
||||||
|
/* Digest the auxiliary vector. */
|
||||||
|
for (i = 0; i < AUX_count; ++i)
|
||||||
|
aux_info[i] = NULL;
|
||||||
|
for (auxp = aux; auxp->au_id != AUX_null; ++auxp) {
|
||||||
|
if (auxp->au_id < AUX_count)
|
||||||
|
aux_info[auxp->au_id] = auxp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize and relocate ourselves. */
|
||||||
|
assert(aux_info[AUX_base] != NULL);
|
||||||
|
_rtld_init((caddr_t) aux_info[AUX_base]->au_v);
|
||||||
|
|
||||||
|
#ifdef RTLD_DEBUG
|
||||||
|
xprintf("_ctype_ is %p\n", _ctype_);
|
||||||
|
#endif
|
||||||
|
if (aux_info[AUX_debug] != NULL) /* Set debugging level */
|
||||||
|
debug = aux_info[AUX_debug]->au_v;
|
||||||
|
|
||||||
|
__progname = _rtld_objself.path;
|
||||||
|
environ = env;
|
||||||
|
|
||||||
|
_rtld_trust = geteuid() == getuid() && getegid() == getgid();
|
||||||
|
|
||||||
|
ld_bind_now = getenv("LD_BIND_NOW");
|
||||||
|
if (ld_bind_now != NULL && *ld_bind_now != '\0')
|
||||||
|
bind_now = true;
|
||||||
|
if (_rtld_trust) {
|
||||||
|
const char *ld_debug = getenv("LD_DEBUG");
|
||||||
|
if (ld_debug != NULL && *ld_debug != '\0')
|
||||||
|
debug = 1;
|
||||||
|
_rtld_add_paths(&_rtld_paths, getenv("LD_LIBRARY_PATH"));
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("%s is initialized, base address = %p", __progname,
|
||||||
|
(caddr_t) aux_info[AUX_base]->au_v);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the main program, or process its program header if it is
|
||||||
|
* already loaded.
|
||||||
|
*/
|
||||||
|
if (aux_info[AUX_execfd] != NULL) { /* Load the main program. */
|
||||||
|
int fd = aux_info[AUX_execfd]->au_v;
|
||||||
|
dbg("loading main program");
|
||||||
|
_rtld_objmain = _rtld_map_object(argv[0], fd);
|
||||||
|
close(fd);
|
||||||
|
if (_rtld_objmain == NULL)
|
||||||
|
_rtld_die();
|
||||||
|
} else { /* Main program already loaded. */
|
||||||
|
const Elf_Phdr *phdr;
|
||||||
|
int phnum;
|
||||||
|
caddr_t entry;
|
||||||
|
|
||||||
|
dbg("processing main program's program header");
|
||||||
|
assert(aux_info[AUX_phdr] != NULL);
|
||||||
|
phdr = (const Elf_Phdr *) aux_info[AUX_phdr]->au_v;
|
||||||
|
assert(aux_info[AUX_phnum] != NULL);
|
||||||
|
phnum = aux_info[AUX_phnum]->au_v;
|
||||||
|
assert(aux_info[AUX_phent] != NULL);
|
||||||
|
assert(aux_info[AUX_phent]->au_v == sizeof(Elf_Phdr));
|
||||||
|
assert(aux_info[AUX_entry] != NULL);
|
||||||
|
entry = (caddr_t) aux_info[AUX_entry]->au_v;
|
||||||
|
_rtld_objmain = _rtld_digest_phdr(phdr, phnum, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_rtld_objmain->path = xstrdup("main program");
|
||||||
|
_rtld_objmain->mainprog = true;
|
||||||
|
_rtld_digest_dynamic(_rtld_objmain);
|
||||||
|
|
||||||
|
_rtld_linkmap_add(_rtld_objmain);
|
||||||
|
_rtld_linkmap_add(&_rtld_objself);
|
||||||
|
|
||||||
|
/* Link the main program into the list of objects. */
|
||||||
|
*_rtld_objtail = _rtld_objmain;
|
||||||
|
_rtld_objtail = &_rtld_objmain->next;
|
||||||
|
++_rtld_objmain->refcount;
|
||||||
|
|
||||||
|
dbg("loading needed objects");
|
||||||
|
if (_rtld_load_needed_objects(_rtld_objmain) == -1)
|
||||||
|
_rtld_die();
|
||||||
|
|
||||||
|
dbg("relocating objects");
|
||||||
|
if (_rtld_relocate_objects(_rtld_objmain, bind_now) == -1)
|
||||||
|
_rtld_die();
|
||||||
|
|
||||||
|
dbg("doing copy relocations");
|
||||||
|
if (_rtld_do_copy_relocations(_rtld_objmain) == -1)
|
||||||
|
_rtld_die();
|
||||||
|
|
||||||
|
dbg("calling _init functions");
|
||||||
|
_rtld_call_init_functions(_rtld_objmain->next);
|
||||||
|
|
||||||
|
dbg("transferring control to program entry point = %p",
|
||||||
|
_rtld_objmain->entry);
|
||||||
|
|
||||||
|
/* Return with the entry point and the exit procedure in at the top of
|
||||||
|
* stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_rtld_debug_state(); /* say hello to gdb! */
|
||||||
|
|
||||||
|
((void **) osp)[0] = _rtld_exit;
|
||||||
|
((void **) osp)[1] = _rtld_objmain;
|
||||||
|
return (Elf_Addr) _rtld_objmain->entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_rtld_die(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
const char *msg = _rtld_dlerror();
|
||||||
|
|
||||||
|
if (msg == NULL)
|
||||||
|
msg = "Fatal error";
|
||||||
|
xerrx(1, "%s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Obj_Entry *
|
||||||
|
_rtld_dlcheck(
|
||||||
|
void *handle)
|
||||||
|
{
|
||||||
|
Obj_Entry *obj;
|
||||||
|
|
||||||
|
for (obj = _rtld_objlist; obj != NULL; obj = obj->next)
|
||||||
|
if (obj == (Obj_Entry *) handle)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (obj == NULL || obj->dl_refcount == 0) {
|
||||||
|
xwarnx("Invalid shared object handle %p", handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rtld_unref_object_dag(
|
||||||
|
Obj_Entry *root)
|
||||||
|
{
|
||||||
|
assert(root->refcount != 0);
|
||||||
|
--root->refcount;
|
||||||
|
if (root->refcount == 0) {
|
||||||
|
const Needed_Entry *needed;
|
||||||
|
|
||||||
|
for (needed = root->needed; needed != NULL; needed = needed->next)
|
||||||
|
_rtld_unref_object_dag(needed->obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_rtld_dlclose(
|
||||||
|
void *handle)
|
||||||
|
{
|
||||||
|
Obj_Entry *root = _rtld_dlcheck(handle);
|
||||||
|
|
||||||
|
if (root == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
_rtld_debug.r_state = RT_DELETE;
|
||||||
|
_rtld_debug_state();
|
||||||
|
|
||||||
|
--root->dl_refcount;
|
||||||
|
_rtld_unref_object_dag(root);
|
||||||
|
if (root->refcount == 0) { /* We are finished with some objects. */
|
||||||
|
Obj_Entry *obj;
|
||||||
|
Obj_Entry **linkp;
|
||||||
|
|
||||||
|
/* Finalize objects that are about to be unmapped. */
|
||||||
|
for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
|
||||||
|
if (obj->refcount == 0 && obj->fini != NULL)
|
||||||
|
(*obj->fini)();
|
||||||
|
|
||||||
|
/* Unmap all objects that are no longer referenced. */
|
||||||
|
linkp = &_rtld_objlist->next;
|
||||||
|
while((obj = *linkp) != NULL) {
|
||||||
|
if (obj->refcount == 0) {
|
||||||
|
munmap(obj->mapbase, obj->mapsize);
|
||||||
|
free(obj->path);
|
||||||
|
while(obj->needed != NULL) {
|
||||||
|
Needed_Entry *needed = obj->needed;
|
||||||
|
obj->needed = needed->next;
|
||||||
|
free(needed);
|
||||||
|
}
|
||||||
|
_rtld_linkmap_delete(obj);
|
||||||
|
*linkp = obj->next;
|
||||||
|
free(obj);
|
||||||
|
} else
|
||||||
|
linkp = &obj->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_rtld_debug.r_state = RT_CONSISTENT;
|
||||||
|
_rtld_debug_state();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
_rtld_dlerror(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
char *msg = error_message;
|
||||||
|
error_message = NULL;
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
_rtld_dlopen(
|
||||||
|
const char *name,
|
||||||
|
int mode)
|
||||||
|
{
|
||||||
|
Obj_Entry **old_obj_tail = _rtld_objtail;
|
||||||
|
Obj_Entry *obj = NULL;
|
||||||
|
|
||||||
|
_rtld_debug.r_state = RT_ADD;
|
||||||
|
_rtld_debug_state();
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
obj = _rtld_objmain;
|
||||||
|
} else {
|
||||||
|
char *path = _rtld_find_library(name, NULL);
|
||||||
|
if (path != NULL)
|
||||||
|
obj = _rtld_load_object(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj != NULL) {
|
||||||
|
++obj->dl_refcount;
|
||||||
|
if (*old_obj_tail != NULL) { /* We loaded something new. */
|
||||||
|
assert(*old_obj_tail == obj);
|
||||||
|
|
||||||
|
/* FIXME - Clean up properly after an error. */
|
||||||
|
if (_rtld_load_needed_objects(obj) == -1) {
|
||||||
|
--obj->dl_refcount;
|
||||||
|
obj = NULL;
|
||||||
|
} else if (_rtld_relocate_objects(obj, mode == RTLD_NOW) == -1) {
|
||||||
|
--obj->dl_refcount;
|
||||||
|
obj = NULL;
|
||||||
|
} else {
|
||||||
|
_rtld_call_init_functions(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_rtld_debug.r_state = RT_CONSISTENT;
|
||||||
|
_rtld_debug_state();
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
_rtld_dlsym(
|
||||||
|
void *handle,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
const Obj_Entry *obj = _rtld_dlcheck(handle);
|
||||||
|
const Elf_Sym *def;
|
||||||
|
const Obj_Entry *defobj;
|
||||||
|
|
||||||
|
if (obj == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME - This isn't correct. The search should include the whole
|
||||||
|
* DAG rooted at the given object.
|
||||||
|
*/
|
||||||
|
def = _rtld_find_symdef(_rtld_objlist, 0, name, obj, &defobj, false);
|
||||||
|
if (def != NULL)
|
||||||
|
return defobj->relocbase + def->st_value;
|
||||||
|
|
||||||
|
_rtld_error("Undefined symbol \"%s\"", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error reporting function. Use it like printf. If formats the message
|
||||||
|
* into a buffer, and sets things up so that the next call to dlerror()
|
||||||
|
* will return the message.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_rtld_error(
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
static char buf[512];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
xvsnprintf(buf, sizeof buf, fmt, ap);
|
||||||
|
error_message = buf;
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_rtld_debug_state(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
/* do nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_rtld_linkmap_add(
|
||||||
|
Obj_Entry *obj)
|
||||||
|
{
|
||||||
|
struct link_map *l = &obj->linkmap;
|
||||||
|
struct link_map *prev;
|
||||||
|
|
||||||
|
obj->linkmap.l_name = obj->path;
|
||||||
|
obj->linkmap.l_addr = obj->mapbase;
|
||||||
|
obj->linkmap.l_ld = obj->dynamic;
|
||||||
|
|
||||||
|
if (_rtld_debug.r_map == NULL) {
|
||||||
|
_rtld_debug.r_map = l;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (prev = _rtld_debug.r_map; prev->l_next != NULL; prev = prev->l_next)
|
||||||
|
;
|
||||||
|
l->l_prev = prev;
|
||||||
|
prev->l_next = l;
|
||||||
|
l->l_next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_rtld_linkmap_delete(
|
||||||
|
Obj_Entry *obj)
|
||||||
|
{
|
||||||
|
struct link_map *l = &obj->linkmap;
|
||||||
|
|
||||||
|
if (l->l_prev == NULL) {
|
||||||
|
if ((_rtld_debug.r_map = l->l_next) != NULL)
|
||||||
|
l->l_next->l_prev = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((l->l_prev->l_next = l->l_next) != NULL)
|
||||||
|
l->l_next->l_prev = l->l_prev;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
/* $NetBSD: rtld.h,v 1.1 1996/12/16 20:38:04 cgd 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 1
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/exec_elf.h>
|
||||||
|
#include "rtldenv.h"
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
#include "link.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RTLD_DEFAULT_LIBRARY_PATH \
|
||||||
|
"/usr/localelf/lib:/usr/lib:/usr/local/lib"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define SVR4_LIBDIR "/usr/lib"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LIBDIRLEN (sizeof LIBDIR - 1)
|
||||||
|
#define SVR4_LIBDIRLEN (sizeof SVR4_LIBDIR - 1)
|
||||||
|
|
||||||
|
#define PAGESIZE CLBYTES
|
||||||
|
#define round_down(x) ((x) & ~(PAGESIZE-1))
|
||||||
|
#define round_up(x) round_down((x) + PAGESIZE - 1)
|
||||||
|
|
||||||
|
#define NEW(type) ((type *) xmalloc(sizeof(type)))
|
||||||
|
#define CNEW(type) ((type *) xcalloc(sizeof(type)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* C++ has mandated the use of the following keywords for its new boolean
|
||||||
|
* type. We might as well follow their lead.
|
||||||
|
*/
|
||||||
|
typedef unsigned char bool;
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
|
||||||
|
struct Struct_Obj_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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shared object descriptor.
|
||||||
|
*
|
||||||
|
* Items marked with "(%)" are dynamically allocated, and must be freed
|
||||||
|
* when the structure is destroyed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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; /* Relocation constant = mapbase - vaddrbase */
|
||||||
|
Elf_Dyn *dynamic; /* Dynamic section */
|
||||||
|
caddr_t entry; /* Entry point */
|
||||||
|
const Elf_Phdr *phdr; /* Program header if it is mapped, else NULL */
|
||||||
|
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 */
|
||||||
|
|
||||||
|
const Elf_Word *buckets; /* Hash table buckets array */
|
||||||
|
unsigned long nbuckets; /* Number of buckets */
|
||||||
|
const Elf_Word *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 one (%) */
|
||||||
|
|
||||||
|
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 mainprog : 1; /* True if this is the main program */
|
||||||
|
int rtld : 1; /* True if this is the dynamic linker */
|
||||||
|
int textrel : 1; /* True if there are relocations to text seg */
|
||||||
|
int symbolic : 1; /* True if generated with "-Bsymbolic" */
|
||||||
|
int printed : 1; /* True if ldd has printed it */
|
||||||
|
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
struct link_map linkmap; /* for GDB */
|
||||||
|
#endif
|
||||||
|
} Obj_Entry;
|
||||||
|
|
||||||
|
extern struct r_debug _rtld_debug;
|
||||||
|
extern Obj_Entry *_rtld_objlist;
|
||||||
|
extern Obj_Entry **_rtld_objtail;
|
||||||
|
extern Obj_Entry _rtld_objself;
|
||||||
|
extern Search_Path *_rtld_paths;
|
||||||
|
extern bool _rtld_trust;
|
||||||
|
extern const char *_rtld_error_message;
|
||||||
|
|
||||||
|
/* rtld_start.S */
|
||||||
|
extern void _rtld_bind_start(void);
|
||||||
|
|
||||||
|
/* rtld.c */
|
||||||
|
|
||||||
|
extern void _rtld_error(const char *, ...);
|
||||||
|
extern void _rtld_die(void);
|
||||||
|
|
||||||
|
extern char *_rtld_dlerror(void);
|
||||||
|
extern void *_rtld_dlopen(const char *, int);
|
||||||
|
extern void *_rtld_dlsym(void *, const char *);
|
||||||
|
extern int _rtld_dlclose(void *);
|
||||||
|
|
||||||
|
extern void _rtld_debug_state(void);
|
||||||
|
|
||||||
|
extern void _rtld_linkmap_add(Obj_Entry *);
|
||||||
|
extern void _rtld_linkmap_delete(Obj_Entry *);
|
||||||
|
|
||||||
|
/* headers.c */
|
||||||
|
|
||||||
|
extern void _rtld_digest_dynamic(Obj_Entry *);
|
||||||
|
extern Obj_Entry *_rtld_digest_phdr(const Elf_Phdr *, int, caddr_t);
|
||||||
|
|
||||||
|
/* load.c */
|
||||||
|
|
||||||
|
extern Obj_Entry *_rtld_load_object(char *path);
|
||||||
|
extern int _rtld_load_needed_objects(Obj_Entry *);
|
||||||
|
|
||||||
|
/* path.c */
|
||||||
|
|
||||||
|
extern void _rtld_add_paths(Search_Path **, const char *);
|
||||||
|
|
||||||
|
/* reloc.c */
|
||||||
|
extern int _rtld_do_copy_relocations(const Obj_Entry *);
|
||||||
|
extern caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
|
||||||
|
extern int _rtld_relocate_objects(Obj_Entry *, bool);
|
||||||
|
|
||||||
|
/* search.c */
|
||||||
|
|
||||||
|
extern char *_rtld_find_library(const char *, const Obj_Entry *);
|
||||||
|
|
||||||
|
/* symbol.c */
|
||||||
|
extern unsigned long _rtld_elf_hash(const char *);
|
||||||
|
extern const Elf_Sym *_rtld_symlook_obj(const char *, unsigned long,
|
||||||
|
const Obj_Entry *, bool);
|
||||||
|
extern const Elf_Sym *_rtld_find_symdef(const Obj_Entry *, Elf_Word,
|
||||||
|
const char *, const Obj_Entry *, const Obj_Entry **, bool);
|
||||||
|
|
||||||
|
/* map_object.c */
|
||||||
|
extern Obj_Entry *_rtld_map_object(const char *, int);
|
||||||
|
|
||||||
|
#endif /* } */
|
|
@ -0,0 +1,70 @@
|
||||||
|
/* $NetBSD: rtldenv.h,v 1.1 1996/12/16 20:38:05 cgd 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>
|
||||||
|
|
||||||
|
extern void *xcalloc(size_t);
|
||||||
|
extern void *xmalloc(size_t);
|
||||||
|
extern char *xstrdup(const char *);
|
||||||
|
|
||||||
|
#ifdef RTLD_LOADER
|
||||||
|
extern void xprintf(const char *fmt, ...);
|
||||||
|
extern void xvprintf(const char *fmt, va_list ap);
|
||||||
|
extern size_t xvsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap);
|
||||||
|
extern void xwarn(const char *fmt, ...);
|
||||||
|
extern void xwarnx(const char *fmt, ...);
|
||||||
|
extern void xerr(int eval, const char *fmt, ...);
|
||||||
|
extern void xerrx(int eval, const char *fmt, ...);
|
||||||
|
extern void xassert(const char *file, int line, const char *failedexpr);
|
||||||
|
extern const char *xstrerror(int error);
|
||||||
|
|
||||||
|
#define assert(cond) ((cond) \
|
||||||
|
? (void) 0 :\
|
||||||
|
(xassert(__FILE__, __LINE__, #cond "\n"), abort()))
|
||||||
|
#else
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
#define xprintf printf
|
||||||
|
#define xvprintf vprintf
|
||||||
|
#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 */
|
|
@ -0,0 +1,347 @@
|
||||||
|
/* $NetBSD: search.c,v 1.1 1996/12/16 20:38:05 cgd 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 <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"
|
||||||
|
|
||||||
|
#define CONCAT(x,y) __CONCAT(x,y)
|
||||||
|
#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
|
||||||
|
#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
|
||||||
|
#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE))
|
||||||
|
#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data declarations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *si_name;
|
||||||
|
const char *si_best_name;
|
||||||
|
char *si_best_fullpath;
|
||||||
|
const Search_Path *si_best_path;
|
||||||
|
size_t si_namelen;
|
||||||
|
int si_desired_major;
|
||||||
|
int si_desired_minor;
|
||||||
|
int si_best_major;
|
||||||
|
int si_best_minor;
|
||||||
|
unsigned si_exact : 1;
|
||||||
|
} Search_Info;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Search_FoundNothing,
|
||||||
|
Search_FoundLower,
|
||||||
|
Search_FoundHigher,
|
||||||
|
Search_FoundExact
|
||||||
|
} Search_Result;
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_rtld_check_library(
|
||||||
|
const Search_Path *sp,
|
||||||
|
const char *name,
|
||||||
|
size_t namelen,
|
||||||
|
char **fullpath_p)
|
||||||
|
{
|
||||||
|
struct stat mystat;
|
||||||
|
char *fullpath;
|
||||||
|
Elf_Ehdr ehdr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fullpath = xmalloc(sp->sp_pathlen + 1 + namelen + 1);
|
||||||
|
strncpy(fullpath, sp->sp_path, sp->sp_pathlen);
|
||||||
|
fullpath[sp->sp_pathlen] = '/';
|
||||||
|
strcpy(&fullpath[sp->sp_pathlen + 1], name);
|
||||||
|
|
||||||
|
dbg(" Trying \"%s\"", fullpath);
|
||||||
|
if (stat(fullpath, &mystat) >= 0 && S_ISREG(mystat.st_mode)) {
|
||||||
|
if ((fd = open(fullpath, O_RDONLY)) >= 0) {
|
||||||
|
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
|
||||||
|
goto lose;
|
||||||
|
|
||||||
|
/* Elf_e_ident includes class */
|
||||||
|
if (memcmp(Elf_e_ident, ehdr.e_ident, Elf_e_siz) != 0)
|
||||||
|
goto lose;
|
||||||
|
|
||||||
|
switch (ehdr.e_machine) {
|
||||||
|
ELFDEFNNAME(MACHDEP_ID_CASES)
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto lose;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ehdr.e_ident[Elf_ei_version] != Elf_ev_current ||
|
||||||
|
ehdr.e_version != Elf_ev_current ||
|
||||||
|
ehdr.e_ident[Elf_ei_data] != ELFDEFNNAME(MACHDEP_ENDIANNESS) ||
|
||||||
|
ehdr.e_type != Elf_et_dyn)
|
||||||
|
goto lose;
|
||||||
|
|
||||||
|
if (*fullpath_p != NULL)
|
||||||
|
free(*fullpath_p);
|
||||||
|
*fullpath_p = fullpath;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
lose:
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fullpath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Search_Result
|
||||||
|
_rtld_search_directory(
|
||||||
|
const Search_Path *sp,
|
||||||
|
Search_Info *si)
|
||||||
|
{
|
||||||
|
struct dirent *entry;
|
||||||
|
DIR *dirp;
|
||||||
|
Search_Result result = Search_FoundNothing;
|
||||||
|
|
||||||
|
dbg("_rtld_search_directory");
|
||||||
|
if (sp->sp_path == NULL || sp->sp_path[0] == '\0')
|
||||||
|
return result;
|
||||||
|
|
||||||
|
dbg("_rtld_search_directory 2");
|
||||||
|
if ((dirp = opendir(sp->sp_path)) == NULL) {
|
||||||
|
dbg("_rtld_search_directory 2.1");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("_rtld_search_directory 3");
|
||||||
|
while ((entry = readdir(dirp)) != NULL) {
|
||||||
|
long major = -1;
|
||||||
|
long minor = -1;
|
||||||
|
if (strncmp(entry->d_name, si->si_name, si->si_namelen))
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* We are matching libfoo.so only (no more info). Only take
|
||||||
|
* it as a last resort.
|
||||||
|
*/
|
||||||
|
if (si->si_exact) {
|
||||||
|
if (strcmp(entry->d_name, si->si_name))
|
||||||
|
continue;
|
||||||
|
#ifdef notyet
|
||||||
|
} else if (entry->d_namlen == si->si_namelen) {
|
||||||
|
if (si->si_best_path != NULL || si->si_best_major != -1)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
char *cp;
|
||||||
|
/*
|
||||||
|
* We expect (demand!) that it be of the form
|
||||||
|
* "libfoo.so.<something>"
|
||||||
|
*/
|
||||||
|
if (entry->d_name[si->si_namelen] != '.')
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* This file has a least a major number (well, maybe not if it
|
||||||
|
* has a name of "libfoo.so." but treat that as equivalent to 0.
|
||||||
|
* It had better match what we are looking for.
|
||||||
|
*/
|
||||||
|
major = strtol(&entry->d_name[si->si_namelen+1], &cp, 10);
|
||||||
|
if (major < 0 || (cp[0] != '\0' && cp[0] != '.')
|
||||||
|
|| &entry->d_name[si->si_namelen+1] == cp)
|
||||||
|
continue;
|
||||||
|
if (cp[0] == '.') {
|
||||||
|
char *cp2;
|
||||||
|
minor = strtol(&cp[1], &cp2, 10);
|
||||||
|
if (minor < 0 || cp2[0] != '\0' || cp == cp2)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
minor = 0;
|
||||||
|
}
|
||||||
|
if (major != si->si_desired_major || minor <= si->si_best_minor)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We have a better candidate...
|
||||||
|
*/
|
||||||
|
if (!_rtld_check_library(sp, entry->d_name, entry->d_namlen,
|
||||||
|
&si->si_best_fullpath))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
si->si_best_name = &si->si_best_fullpath[sp->sp_pathlen + 1];
|
||||||
|
si->si_best_major = major;
|
||||||
|
si->si_best_minor = minor;
|
||||||
|
si->si_best_path = sp;
|
||||||
|
|
||||||
|
if (si->si_exact || si->si_best_minor == si->si_desired_minor)
|
||||||
|
result = Search_FoundExact;
|
||||||
|
else if (si->si_best_minor > si->si_desired_minor)
|
||||||
|
result = Search_FoundHigher;
|
||||||
|
else
|
||||||
|
result = Search_FoundLower;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We were looking for, and found, an exact match. We're done.
|
||||||
|
*/
|
||||||
|
if (si->si_exact)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("found %s (%d.%d) match for %s (%d.%d) -> %s",
|
||||||
|
result == Search_FoundNothing ? "no"
|
||||||
|
: result == Search_FoundLower ? "lower"
|
||||||
|
: result == Search_FoundExact ? "exact" : "higher",
|
||||||
|
si->si_best_major, si->si_best_minor,
|
||||||
|
si->si_name,
|
||||||
|
si->si_desired_major, si->si_desired_minor,
|
||||||
|
si->si_best_fullpath ? si->si_best_fullpath : sp->sp_path);
|
||||||
|
|
||||||
|
closedir(dirp);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
_rtld_search_library_paths(
|
||||||
|
const char *name,
|
||||||
|
Search_Path *paths,
|
||||||
|
const Search_Path *rpaths)
|
||||||
|
{
|
||||||
|
Search_Info info;
|
||||||
|
Search_Path *path;
|
||||||
|
const char *cp;
|
||||||
|
Search_Result result = Search_FoundNothing;
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.si_name = name;
|
||||||
|
info.si_desired_major = -1;
|
||||||
|
info.si_desired_minor = -1;
|
||||||
|
info.si_best_major = -1;
|
||||||
|
info.si_best_minor = -1;
|
||||||
|
|
||||||
|
cp = strstr(name, ".so");
|
||||||
|
if (cp == NULL) {
|
||||||
|
info.si_exact = true;
|
||||||
|
} else {
|
||||||
|
cp += sizeof(".so") - 1;
|
||||||
|
info.si_namelen = cp - name;
|
||||||
|
if (cp[0] != '.') {
|
||||||
|
info.si_exact = true;
|
||||||
|
} else {
|
||||||
|
info.si_desired_major = atoi(&cp[1]);
|
||||||
|
if ((cp = strchr(&cp[1], '.')) != NULL) {
|
||||||
|
info.si_desired_minor = atoi(&cp[1]);
|
||||||
|
} else {
|
||||||
|
info.si_desired_minor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rpaths != NULL && result < Search_FoundHigher) { /* Exact? */
|
||||||
|
dbg(" checking rpaths..");
|
||||||
|
for (; rpaths != NULL; rpaths = rpaths->sp_next) {
|
||||||
|
dbg(" in \"%s\"", rpaths->sp_path);
|
||||||
|
result = _rtld_search_directory(rpaths, &info);
|
||||||
|
if (result >= Search_FoundHigher) /* Exact? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result < Search_FoundHigher) { /* Exact? */
|
||||||
|
dbg(" checking default paths..");
|
||||||
|
for (path = paths; path != NULL; path = path->sp_next) {
|
||||||
|
dbg(" in \"%s\"", path->sp_path);
|
||||||
|
result = _rtld_search_directory(path, &info);
|
||||||
|
if (result >= Search_FoundHigher) /* Exact? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result >= Search_FoundHigher)
|
||||||
|
return info.si_best_fullpath;
|
||||||
|
|
||||||
|
if (info.si_best_fullpath != NULL)
|
||||||
|
free(info.si_best_fullpath);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
_rtld_find_library(
|
||||||
|
const char *name,
|
||||||
|
const Obj_Entry *refobj)
|
||||||
|
{
|
||||||
|
char *pathname;
|
||||||
|
|
||||||
|
if (strchr(name, '/') != NULL) { /* Hard coded pathname */
|
||||||
|
if (name[0] != '/' && !_rtld_trust) {
|
||||||
|
_rtld_error("Absolute pathname required for shared object \"%s\"",
|
||||||
|
name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#ifdef SVR4_LIBDIR
|
||||||
|
if (strncmp(name, SVR4_LIBDIR, SVR4_LIBDIRLEN) == 0
|
||||||
|
&& name[SVR4_LIBDIRLEN] == '/') { /* In "/usr/lib" */
|
||||||
|
/* Map hard-coded "/usr/lib" onto our ELF library directory. */
|
||||||
|
pathname = xmalloc(strlen(name) + LIBDIRLEN - SVR4_LIBDIRLEN + 1);
|
||||||
|
strcpy(pathname, LIBDIR);
|
||||||
|
strcpy(pathname + LIBDIRLEN, name + SVR4_LIBDIRLEN);
|
||||||
|
return pathname;
|
||||||
|
}
|
||||||
|
#endif /* SVR4_LIBDIR */
|
||||||
|
return xstrdup(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg(" Searching for \"%s\" (%p)", name, refobj);
|
||||||
|
|
||||||
|
pathname = _rtld_search_library_paths(name, _rtld_paths,
|
||||||
|
refobj ? refobj->rpaths : NULL);
|
||||||
|
if (pathname == NULL)
|
||||||
|
_rtld_error("Shared object \"%s\" not found", name);
|
||||||
|
return pathname;
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
/* $NetBSD: symbol.c,v 1.1 1996/12/16 20:38:06 cgd 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 <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 <dirent.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "rtld.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
while(*p != '\0') {
|
||||||
|
h = (h << 4) + *p++;
|
||||||
|
if ((g = h & 0xf0000000) != 0)
|
||||||
|
h ^= g >> 24;
|
||||||
|
h &= ~g;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 = obj->buckets[hash % obj->nbuckets];
|
||||||
|
|
||||||
|
while (symnum != ELF_SYM_UNDEFINED) {
|
||||||
|
const Elf_Sym *symp;
|
||||||
|
const char *strp;
|
||||||
|
|
||||||
|
assert(symnum < obj->nchains);
|
||||||
|
symp = obj->symtab + symnum;
|
||||||
|
strp = obj->strtab + symp->st_name;
|
||||||
|
#if 0
|
||||||
|
assert(symp->st_name != 0);
|
||||||
|
#endif
|
||||||
|
if (strcmp(name, strp) == 0) {
|
||||||
|
if (symp->st_shndx != Elf_eshn_undefined
|
||||||
|
|| (!in_plt && symp->st_value != 0 &&
|
||||||
|
ELF_SYM_TYPE(symp->st_info) == Elf_estt_func)) {
|
||||||
|
return symp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
symnum = obj->chains[symnum];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(
|
||||||
|
const Obj_Entry *obj_list,
|
||||||
|
Elf_Word r_info,
|
||||||
|
const char *name,
|
||||||
|
const Obj_Entry *refobj,
|
||||||
|
const Obj_Entry **defobj_out,
|
||||||
|
bool in_plt)
|
||||||
|
{
|
||||||
|
Elf_Word symnum = ELF_R_SYM(r_info);
|
||||||
|
const Elf_Sym *ref;
|
||||||
|
const Obj_Entry *obj;
|
||||||
|
unsigned long hash;
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
ref = refobj->symtab + symnum;
|
||||||
|
name = refobj->strtab + ref->st_name;
|
||||||
|
}
|
||||||
|
hash = _rtld_elf_hash(name);
|
||||||
|
|
||||||
|
if (refobj->symbolic) { /* Look first in the referencing object */
|
||||||
|
const Elf_Sym *def = _rtld_symlook_obj(name, hash, refobj, in_plt);
|
||||||
|
if (def != NULL) {
|
||||||
|
*defobj_out = refobj;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look in all loaded objects. Skip the referencing object, if
|
||||||
|
* we have already searched it.
|
||||||
|
*/
|
||||||
|
for (obj = obj_list; obj != NULL; obj = obj->next) {
|
||||||
|
if (obj != refobj || !refobj->symbolic) {
|
||||||
|
const Elf_Sym *def = _rtld_symlook_obj(name, hash, obj, in_plt);
|
||||||
|
if (def != NULL) {
|
||||||
|
*defobj_out = obj;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
|
||||||
|
_rtld_error("%s: Undefined %ssymbol \"%s\" (reloc type = %d, symnum = %d)",
|
||||||
|
refobj->path, in_plt ? "PLT " : "", name,
|
||||||
|
ELF_R_TYPE(r_info), symnum);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* $NetBSD: xmalloc.c,v 1.1 1996/12/16 20:38:07 cgd 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rtldenv.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void *
|
||||||
|
xcalloc(size_t size)
|
||||||
|
{
|
||||||
|
return memset(xmalloc(size), 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
xmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *p = malloc(size);
|
||||||
|
if(p == NULL)
|
||||||
|
xerr(1, "Out of memory");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
xstrdup(const char *s)
|
||||||
|
{
|
||||||
|
char *p = strdup(s);
|
||||||
|
if(p == NULL)
|
||||||
|
xerr(1, "Out of memory");
|
||||||
|
return p;
|
||||||
|
}
|
|
@ -0,0 +1,272 @@
|
||||||
|
/* $NetBSD: xprintf.c,v 1.1 1996/12/16 20:38:07 cgd 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 "rtldenv.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
while (*fmt != NULL && bp < ep) {
|
||||||
|
switch (*fmt) {
|
||||||
|
case '\\': {
|
||||||
|
if (fmt[1] != '\0')
|
||||||
|
*bp++ = *++fmt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case '%': {
|
||||||
|
switch (fmt[1]) {
|
||||||
|
case 'd': case 'u': {
|
||||||
|
int ival;
|
||||||
|
unsigned uval;
|
||||||
|
char digits[sizeof(int) * 3], *dp = digits;
|
||||||
|
|
||||||
|
if (fmt[1] == 'd') {
|
||||||
|
ival = va_arg(ap, int);
|
||||||
|
if (ival < 0) {
|
||||||
|
if ((ival << 1) == 0) {
|
||||||
|
/*
|
||||||
|
* We can't flip the sign of this since
|
||||||
|
* it's can't represented as a postive
|
||||||
|
* number in two complement, handle the
|
||||||
|
* first digit. After that, it can be
|
||||||
|
* flipped since it is now not 2^(n-1).
|
||||||
|
*/
|
||||||
|
*dp++ = '0' - (ival % 10);
|
||||||
|
ival /= 10;
|
||||||
|
}
|
||||||
|
*bp++ = '-';
|
||||||
|
uval = -ival;
|
||||||
|
} else {
|
||||||
|
uval = ival;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uval = va_arg(ap, unsigned);
|
||||||
|
}
|
||||||
|
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)";
|
||||||
|
|
||||||
|
len = strlen(str);
|
||||||
|
if (ep - bp < len)
|
||||||
|
len = ep - bp;
|
||||||
|
memcpy(bp, str, len);
|
||||||
|
bp += len;
|
||||||
|
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);
|
||||||
|
|
||||||
|
xvprintf(fmt, ap);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
xstrerror(
|
||||||
|
int error)
|
||||||
|
{
|
||||||
|
if (error >= sys_nerr) {
|
||||||
|
static char buf[128];
|
||||||
|
xsnprintf(buf, sizeof(buf), "Unknown error: %d", error);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
return sys_errlist[error];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xerrx(
|
||||||
|
int eval,
|
||||||
|
const char *fmt,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
xvprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
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
|
||||||
|
xassert(
|
||||||
|
const char *file,
|
||||||
|
int line,
|
||||||
|
const char *failedexpr)
|
||||||
|
{
|
||||||
|
xprintf("assertion \"%s\" failed: file \"%s\", line %d\n",
|
||||||
|
failedexpr, file, line);
|
||||||
|
abort();
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
Loading…
Reference in New Issue