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:
cgd 1996-12-16 20:37:55 +00:00
parent 5a09b2d886
commit 41fe218b25
23 changed files with 3995 additions and 0 deletions

29
include/link_elf.h Normal file
View File

@ -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 */

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

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

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

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

@ -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 /* } */

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

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

29
libexec/ld.elf_so/link.h Normal file
View File

@ -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 */

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

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

472
libexec/ld.elf_so/malloc.c Normal file
View File

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

View File

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

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

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

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

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

568
libexec/ld.elf_so/rtld.c Normal file
View File

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

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

@ -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 /* } */

View File

@ -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 */

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

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

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

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

View File

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

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

@ -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 */
}