Add alpha support.

Submitted by: John Birrell <jb@cimlogic.com.au> (with extra hacks by me)
Obtained from: Probably NetBSD
This commit is contained in:
Doug Rabson 1998-09-04 19:03:57 +00:00
parent 26cdc317be
commit 13575fc46f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=38816
11 changed files with 1145 additions and 277 deletions

View File

@ -1,17 +1,25 @@
#
# $Id: Makefile,v 1.2 1998/04/30 07:47:58 dfr Exp $
# $Id: Makefile,v 1.3 1998/08/17 04:59:15 jdp Exp $
#
PROG= ld-elf.so.1
SRCS= rtld_start.S rtld.c map_object.c malloc.c xmalloc.c debug.c
SRCS= rtld_start.S rtld.c map_object.c malloc.c xmalloc.c debug.c \
reloc.c
NOMAN= true
CFLAGS+= -elf -fpic -DFREEBSD_ELF
CFLAGS+= -Wall
LDFLAGS+= -elf -nostdlib -Wl,-Bshareable,-Bsymbolic
CFLAGS+= -fpic -Wall -DFREEBSD_ELF -I${.CURDIR}
LDADD+= -lc_pic
.if ${MACHINE_ARCH} == "alpha"
CFLAGS+= -mno-fp-regs
LDFLAGS+= -nostdlib -Wl,-Bshareable,-Bsymbolic -e .rtld_start
.elif ${MACHINE_ARCH} == "i386"
CFLAGS+= -elf
LDFLAGS+= -elf -nostdlib -Wl,-Bshareable,-Bsymbolic
.endif
# Atomic installation with "-C" is very important for this program.
INSTALLFLAGS+= -C
.PATH: ${.CURDIR}/${MACHINE}
.PATH: ${.CURDIR}/${MACHINE_ARCH}
.include <bsd.prog.mk>

View File

@ -0,0 +1,309 @@
/*-
* Copyright 1996-1998 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: rtld.c,v 1.3 1998/05/01 08:39:27 dfr Exp $
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/param.h>
#include <sys/mman.h>
#include <dlfcn.h>
#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 "debug.h"
#include "rtld.h"
/*
* Debugging support.
*/
#define assert(cond) ((cond) ? (void) 0 :\
(msg("oops: " __XSTRING(__LINE__) "\n"), abort()))
#define msg(s) (write(1, s, strlen(s)))
#define trace() msg("trace: " __XSTRING(__LINE__) "\n");
extern Elf_Dyn _DYNAMIC;
/* Relocate a non-PLT object with addend. */
static int
reloc_non_plt_obj(Obj_Entry *obj_rtld, 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_ALPHA_REFQUAD: {
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf_Addr tmp_value;
def = find_symdef(ELF_R_SYM(rela->r_info), 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;
case R_ALPHA_GLOB_DAT: {
const Elf_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rela->r_info), 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_ALPHA_RELATIVE: {
if (obj != obj_rtld ||
(caddr_t)where < (caddr_t)_GLOBAL_OFFSET_TABLE_ ||
(caddr_t)where >= (caddr_t)&_DYNAMIC)
*where += (Elf_Addr) obj->relocbase;
}
break;
case R_ALPHA_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:
_rtld_error("%s: Unsupported relocation type %d"
" in non-PLT relocations\n", obj->path,
ELF_R_TYPE(rela->r_info));
return -1;
}
return(0);
}
/* Process the non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
const Elf_Rela *relalim;
const Elf_Rela *rela;
/* Perform relocations without addend if there are any: */
rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
for (rel = obj->rel; obj->rel != NULL && rel < rellim; rel++) {
Elf_Rela locrela;
locrela.r_info = rel->r_info;
locrela.r_offset = rel->r_offset;
locrela.r_addend = 0;
if (reloc_non_plt_obj(obj_rtld, obj, &locrela))
return -1;
}
/* Perform relocations with addend if there are any: */
relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
for (rela = obj->rela; obj->rela != NULL && rela < relalim; rela++) {
if (reloc_non_plt_obj(obj_rtld, obj, rela))
return -1;
}
return 0;
}
/* Process the PLT relocations. */
int
reloc_plt(Obj_Entry *obj, bool bind_now)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
const Elf_Rela *relalim;
const Elf_Rela *rela;
/* Process the PLT relocations without addend if there are any. */
rellim = (const Elf_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize);
if (bind_now) {
/* Fully resolve procedure addresses now */
for (rel = obj->pltrel; obj->pltrel != NULL && rel < rellim;
rel++) {
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
const Elf_Sym *def;
const Obj_Entry *defobj;
assert(ELF_R_TYPE(rel->r_info) == R_ALPHA_JMP_SLOT);
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
if (def == NULL)
return -1;
*where = (Elf_Addr) (defobj->relocbase + def->st_value);
}
} else { /* Just relocate the GOT slots pointing into the PLT */
for (rel = obj->pltrel; obj->pltrel != NULL && rel < rellim;
rel++) {
Elf_Addr *where = (Elf_Addr *)
(obj->relocbase + rel->r_offset);
*where += (Elf_Addr) obj->relocbase;
}
}
/* Process the PLT relocations with addend if there are any. */
relalim = (const Elf_Rela *) ((caddr_t) obj->pltrela +
obj->pltrelasize);
if (bind_now) {
/* Fully resolve procedure addresses now */
for (rela = obj->pltrela; obj->pltrela != NULL && rela < relalim;
rel++) {
Elf_Addr *where = (Elf_Addr *) (obj->relocbase +
rela->r_offset);
const Elf_Sym *def;
const Obj_Entry *defobj;
assert(ELF_R_TYPE(rela->r_info) == R_ALPHA_JMP_SLOT);
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true);
if (def == NULL)
return -1;
*where = (Elf_Addr) (defobj->relocbase + def->st_value);
}
} else { /* Just relocate the GOT slots pointing into the PLT */
for (rela = obj->pltrela; obj->pltrela != NULL && rela < relalim;
rela++) {
Elf_Addr *where = (Elf_Addr *)
(obj->relocbase + rela->r_offset);
*where += (Elf_Addr) obj->relocbase;
}
}
return 0;
}
/* Process an R_ALPHA_COPY relocation. */
static int
do_copy_relocation(Obj_Entry *dstobj, const Elf_Rela *rela)
{
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym;
Obj_Entry *srcobj;
dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = 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_ALPHA_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
do_copy_relocations(Obj_Entry *dstobj)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
const Elf_Rela *relalim;
const Elf_Rela *rela;
assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
for (rel = dstobj->rel; dstobj->rel != NULL && rel < rellim; rel++) {
if (ELF_R_TYPE(rel->r_info) == R_ALPHA_COPY) {
Elf_Rela locrela;
locrela.r_info = rel->r_info;
locrela.r_offset = rel->r_offset;
locrela.r_addend = 0;
if (do_copy_relocation(dstobj, &locrela))
return -1;
}
}
relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela +
dstobj->relasize);
for (rela = dstobj->rela; dstobj->rela != NULL && rela < relalim;
rela++) {
if (ELF_R_TYPE(rela->r_info) == R_ALPHA_COPY) {
if (do_copy_relocation(dstobj, rela))
return -1;
}
}
return 0;
}

View File

@ -0,0 +1,169 @@
/* $Id$ */
/* From: 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>
#include <machine/pal.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) /* space for arguments */
/* 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 */
lda t4, _DYNAMIC
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, 0(s0) /* initial sp */
lda a1, -16(s0) /* address for exit proc */
lda a2, -8(s0) /* address for obj_main */
CALL(_rtld) /* v0 = _rtld(sp, &exit_proc, &obj_main); */
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,236 @@
/*-
* Copyright 1996-1998 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: rtld.c,v 1.3 1998/05/01 08:39:27 dfr Exp $
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/param.h>
#include <sys/mman.h>
#include <dlfcn.h>
#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 "debug.h"
#include "rtld.h"
/*
* Debugging support.
*/
#define assert(cond) ((cond) ? (void) 0 :\
(msg("oops: " __XSTRING(__LINE__) "\n"), abort()))
#define msg(s) (write(1, s, strlen(s)))
#define trace() msg("trace: " __XSTRING(__LINE__) "\n");
/*
* Process the special R_386_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
do_copy_relocations(Obj_Entry *dstobj)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
for (rel = dstobj->rel; rel < rellim; rel++) {
if (ELF_R_TYPE(rel->r_info) == R_386_COPY) {
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym;
Obj_Entry *srcobj;
dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = 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 non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
for (rel = obj->rel; rel < rellim; rel++) {
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
switch (ELF_R_TYPE(rel->r_info)) {
case R_386_NONE:
break;
case R_386_32:
{
const Elf_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where += (Elf_Addr) (defobj->relocbase + def->st_value);
}
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 = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where +=
(Elf_Addr) (defobj->relocbase + def->st_value) -
(Elf_Addr) where;
}
break;
case R_386_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_386_COPY relocation"
" in shared library", obj->path);
return -1;
}
break;
case R_386_GLOB_DAT:
{
const Elf_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where = (Elf_Addr) (defobj->relocbase + def->st_value);
}
break;
case R_386_RELATIVE:
*where += (Elf_Addr) obj->relocbase;
break;
default:
_rtld_error("%s: Unsupported relocation type %d"
" in non-PLT relocations\n", obj->path,
ELF_R_TYPE(rel->r_info));
return -1;
}
}
return 0;
}
/* Process the PLT relocations. */
int
reloc_plt(Obj_Entry *obj, bool bind_now)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
/* Process the PLT relocations. */
rellim = (const Elf_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize);
if (bind_now) {
/* Fully resolve procedure addresses now */
for (rel = obj->pltrel; rel < rellim; rel++) {
Elf_Addr *where = (Elf_Addr *)
(obj->relocbase + rel->r_offset);
const Elf_Sym *def;
const Obj_Entry *defobj;
assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
if (def == NULL)
return -1;
*where = (Elf_Addr) (defobj->relocbase + def->st_value);
}
} else { /* Just relocate the GOT slots pointing into the PLT */
for (rel = obj->pltrel; rel < rellim; rel++) {
Elf_Addr *where = (Elf_Addr *)
(obj->relocbase + rel->r_offset);
*where += (Elf_Addr) obj->relocbase;
}
}
return 0;
}

View File

@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: rtld_start.S,v 1.6 1998/03/05 21:05:53 jdp Exp $
* $Id: rtld_start.S,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $
*/
.text
@ -32,12 +32,17 @@
.rtld_start:
xorl %ebp,%ebp # Clear frame pointer for good form
movl %esp,%eax # Save initial stack pointer
subl $4,%esp # A place to store exit procedure addr
pushl %esp # Pass its address to rtld
subl $8,%esp # A place to store exit procedure addr
movl %esp,%ebx # save address of exit proc
movl %esp,%ecx # construct address of obj_main
addl $4,%ecx
pushl %ecx # Pass address of obj_main
pushl %ebx # Pass address of exit proc
pushl %eax # Pass initial stack pointer to rtld
call _rtld@PLT # Call rtld(sp); returns entry point
addl $8,%esp # Remove arguments from stack
addl $12,%esp # Remove arguments from stack
popl %edx # Get exit procedure address
addl $4,%esp # Ignore obj_main
/*
* At this point, %eax contains the entry point of the main program, and
* %edx contains a pointer to a termination function that should be

View File

@ -0,0 +1,236 @@
/*-
* Copyright 1996-1998 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: rtld.c,v 1.3 1998/05/01 08:39:27 dfr Exp $
*/
/*
* Dynamic linker for ELF.
*
* John Polstra <jdp@polstra.com>.
*/
#include <sys/param.h>
#include <sys/mman.h>
#include <dlfcn.h>
#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 "debug.h"
#include "rtld.h"
/*
* Debugging support.
*/
#define assert(cond) ((cond) ? (void) 0 :\
(msg("oops: " __XSTRING(__LINE__) "\n"), abort()))
#define msg(s) (write(1, s, strlen(s)))
#define trace() msg("trace: " __XSTRING(__LINE__) "\n");
/*
* Process the special R_386_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
do_copy_relocations(Obj_Entry *dstobj)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
for (rel = dstobj->rel; rel < rellim; rel++) {
if (ELF_R_TYPE(rel->r_info) == R_386_COPY) {
void *dstaddr;
const Elf_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf_Sym *srcsym;
Obj_Entry *srcobj;
dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = 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 non-PLT relocations. */
int
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
for (rel = obj->rel; rel < rellim; rel++) {
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
switch (ELF_R_TYPE(rel->r_info)) {
case R_386_NONE:
break;
case R_386_32:
{
const Elf_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where += (Elf_Addr) (defobj->relocbase + def->st_value);
}
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 = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where +=
(Elf_Addr) (defobj->relocbase + def->st_value) -
(Elf_Addr) where;
}
break;
case R_386_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_386_COPY relocation"
" in shared library", obj->path);
return -1;
}
break;
case R_386_GLOB_DAT:
{
const Elf_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where = (Elf_Addr) (defobj->relocbase + def->st_value);
}
break;
case R_386_RELATIVE:
*where += (Elf_Addr) obj->relocbase;
break;
default:
_rtld_error("%s: Unsupported relocation type %d"
" in non-PLT relocations\n", obj->path,
ELF_R_TYPE(rel->r_info));
return -1;
}
}
return 0;
}
/* Process the PLT relocations. */
int
reloc_plt(Obj_Entry *obj, bool bind_now)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
/* Process the PLT relocations. */
rellim = (const Elf_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize);
if (bind_now) {
/* Fully resolve procedure addresses now */
for (rel = obj->pltrel; rel < rellim; rel++) {
Elf_Addr *where = (Elf_Addr *)
(obj->relocbase + rel->r_offset);
const Elf_Sym *def;
const Obj_Entry *defobj;
assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
if (def == NULL)
return -1;
*where = (Elf_Addr) (defobj->relocbase + def->st_value);
}
} else { /* Just relocate the GOT slots pointing into the PLT */
for (rel = obj->pltrel; rel < rellim; rel++) {
Elf_Addr *where = (Elf_Addr *)
(obj->relocbase + rel->r_offset);
*where += (Elf_Addr) obj->relocbase;
}
}
return 0;
}

View File

@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: rtld_start.S,v 1.6 1998/03/05 21:05:53 jdp Exp $
* $Id: rtld_start.S,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $
*/
.text
@ -32,12 +32,17 @@
.rtld_start:
xorl %ebp,%ebp # Clear frame pointer for good form
movl %esp,%eax # Save initial stack pointer
subl $4,%esp # A place to store exit procedure addr
pushl %esp # Pass its address to rtld
subl $8,%esp # A place to store exit procedure addr
movl %esp,%ebx # save address of exit proc
movl %esp,%ecx # construct address of obj_main
addl $4,%ecx
pushl %ecx # Pass address of obj_main
pushl %ebx # Pass address of exit proc
pushl %eax # Pass initial stack pointer to rtld
call _rtld@PLT # Call rtld(sp); returns entry point
addl $8,%esp # Remove arguments from stack
addl $12,%esp # Remove arguments from stack
popl %edx # Get exit procedure address
addl $4,%esp # Ignore obj_main
/*
* At this point, %eax contains the entry point of the main program, and
* %edx contains a pointer to a termination function that should be

View File

@ -33,7 +33,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/
static char *rcsid = "$Id: malloc.c,v 1.2 1996/01/19 18:36:54 jdp Exp $";
static char *rcsid = "$Id: malloc.c,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $";
#endif /* LIBC_SCCS and not lint */
/*
@ -156,7 +156,8 @@ malloc(nbytes)
size_t nbytes;
{
register union overhead *op;
register int bucket, n;
register int bucket;
register long n;
register unsigned amt;
/*
@ -168,7 +169,7 @@ malloc(nbytes)
if (morepages(NPOOLPAGES) == 0)
return NULL;
op = (union overhead *)(pagepool_start);
n = n - sizeof (*op) - ((int)op & (n - 1));
n = n - sizeof (*op) - ((long)op & (n - 1));
if (n < 0)
n += pagesz;
if (n) {
@ -462,12 +463,12 @@ int n;
if (pagepool_end - pagepool_start > pagesz) {
caddr_t addr = (caddr_t)
(((int)pagepool_start + pagesz - 1) & ~(pagesz - 1));
(((long)pagepool_start + pagesz - 1) & ~(pagesz - 1));
if (munmap(addr, pagepool_end - addr) != 0)
warn("morepages: munmap %p", addr);
}
offset = (int)pagepool_start - ((int)pagepool_start & ~(pagesz - 1));
offset = (long)pagepool_start - ((long)pagepool_start & ~(pagesz - 1));
if ((pagepool_start = mmap(0, n * pagesz,
PROT_READ|PROT_WRITE,

View File

@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: map_object.c,v 1.2 1998/03/06 22:14:53 jdp Exp $
* $Id: map_object.c,v 1.1.1.1 1998/03/07 19:24:35 jdp Exp $
*/
#include <sys/param.h>
@ -50,31 +50,31 @@ map_object(int fd)
{
Obj_Entry *obj;
union {
Elf32_Ehdr hdr;
Elf_Ehdr hdr;
char buf[PAGE_SIZE];
} u;
int nbytes;
Elf32_Phdr *phdr;
Elf32_Phdr *phlimit;
Elf32_Phdr *segs[2];
Elf_Phdr *phdr;
Elf_Phdr *phlimit;
Elf_Phdr *segs[2];
int nsegs;
Elf32_Phdr *phdyn;
Elf32_Phdr *phphdr;
Elf_Phdr *phdyn;
Elf_Phdr *phphdr;
caddr_t mapbase;
size_t mapsize;
Elf32_Off base_offset;
Elf32_Addr base_vaddr;
Elf32_Addr base_vlimit;
Elf_Off base_offset;
Elf_Addr base_vaddr;
Elf_Addr base_vlimit;
caddr_t base_addr;
Elf32_Off data_offset;
Elf32_Addr data_vaddr;
Elf32_Addr data_vlimit;
Elf_Off data_offset;
Elf_Addr data_vaddr;
Elf_Addr data_vlimit;
caddr_t data_addr;
Elf32_Addr clear_vaddr;
Elf_Addr clear_vaddr;
caddr_t clear_addr;
size_t nclear;
Elf32_Addr bss_vaddr;
Elf32_Addr bss_vlimit;
Elf_Addr bss_vaddr;
Elf_Addr bss_vlimit;
caddr_t bss_addr;
if ((nbytes = read(fd, u.buf, PAGE_SIZE)) == -1) {
@ -83,7 +83,7 @@ map_object(int fd)
}
/* Make sure the file is valid */
if (nbytes < sizeof(Elf32_Ehdr)
if (nbytes < sizeof(Elf_Ehdr)
|| u.hdr.e_ident[EI_MAG0] != ELFMAG0
|| u.hdr.e_ident[EI_MAG1] != ELFMAG1
|| u.hdr.e_ident[EI_MAG2] != ELFMAG2
@ -91,8 +91,8 @@ map_object(int fd)
_rtld_error("Invalid file format");
return NULL;
}
if (u.hdr.e_ident[EI_CLASS] != ELFCLASS32
|| u.hdr.e_ident[EI_DATA] != ELFDATA2LSB) {
if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS
|| u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) {
_rtld_error("Unsupported file layout");
return NULL;
}
@ -105,7 +105,7 @@ map_object(int fd)
_rtld_error("Unsupported file type");
return NULL;
}
if (u.hdr.e_machine != EM_386) {
if (u.hdr.e_machine != ELF_TARG_MACH) {
_rtld_error("Unsupported machine");
return NULL;
}
@ -115,9 +115,9 @@ map_object(int fd)
* 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(Elf32_Phdr));
assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf32_Phdr) <= PAGE_SIZE);
assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf32_Phdr) <= nbytes);
assert(u.hdr.e_phentsize == sizeof(Elf_Phdr));
assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE);
assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes);
/*
* Scan the program header entries, and save key information.
@ -125,7 +125,7 @@ map_object(int fd)
* We rely on there being exactly two load segments, text and data,
* in that order.
*/
phdr = (Elf32_Phdr *) (u.buf + u.hdr.e_phoff);
phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
phlimit = phdr + u.hdr.e_phnum;
nsegs = 0;
phdyn = NULL;
@ -156,8 +156,8 @@ map_object(int fd)
}
assert(nsegs == 2);
assert(segs[0]->p_align <= PAGE_SIZE);
assert(segs[1]->p_align <= PAGE_SIZE);
assert(segs[0]->p_align >= PAGE_SIZE);
assert(segs[1]->p_align >= PAGE_SIZE);
/*
* Map the entire address space of the object, to stake out our
@ -219,12 +219,12 @@ map_object(int fd)
base_vaddr;
obj->vaddrbase = base_vaddr;
obj->relocbase = mapbase - base_vaddr;
obj->dynamic = (const Elf32_Dyn *)
obj->dynamic = (const Elf_Dyn *)
(mapbase + (phdyn->p_vaddr - base_vaddr));
if (u.hdr.e_entry != 0)
obj->entry = (caddr_t) (mapbase + (u.hdr.e_entry - base_vaddr));
if (phphdr != NULL) {
obj->phdr = (const Elf32_Phdr *)
obj->phdr = (const Elf_Phdr *)
(mapbase + (phphdr->p_vaddr - base_vaddr));
obj->phsize = phphdr->p_memsz;
}

View File

@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: rtld.c,v 1.5 1998/09/02 02:00:20 jdp Exp $
* $Id: rtld.c,v 1.6 1998/09/02 02:51:12 jdp Exp $
*/
/*
@ -72,15 +72,11 @@ static void call_fini_functions(Obj_Entry *);
static void call_init_functions(Obj_Entry *);
static void die(void);
static void digest_dynamic(Obj_Entry *);
static Obj_Entry *digest_phdr(const Elf32_Phdr *, int, caddr_t);
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t);
static Obj_Entry *dlcheck(void *);
static int do_copy_relocations(Obj_Entry *);
static unsigned long elf_hash(const char *);
static char *find_library(const char *, const Obj_Entry *);
static const Elf32_Sym *find_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, bool);
static void init_rtld(caddr_t);
static bool is_exported(const Elf32_Sym *);
static bool is_exported(const Elf_Sym *);
static void linkmap_add(Obj_Entry *);
static void linkmap_delete(Obj_Entry *);
static int load_needed_objects(Obj_Entry *);
@ -89,8 +85,6 @@ static Obj_Entry *obj_from_addr(const void *);
static int relocate_objects(Obj_Entry *, bool);
static void rtld_exit(void);
static char *search_library_path(const char *, const char *);
static const Elf32_Sym *symlook_obj(const char *, unsigned long,
const Obj_Entry *, bool);
static void unref_object_dag(Obj_Entry *);
static void trace_loaded_objects(Obj_Entry *obj);
@ -109,11 +103,13 @@ extern void _rtld_bind_start(void);
*/
#ifdef __i386__
#define get_got_address() \
({ Elf32_Addr *thegot; \
({ Elf_Addr *thegot; \
__asm__("movl %%ebx,%0" : "=rm"(thegot)); \
thegot; })
#elif __alpha__
#define get_got_address() NULL
#else
#error "This file only supports the i386 architecture"
#error "This file only supports the i386 and alpha architectures"
#endif
/*
@ -135,6 +131,8 @@ static Obj_Entry obj_rtld; /* The dynamic linker shared object */
#define GDB_STATE(s) r_debug.r_state = s; r_debug_state();
extern Elf_Dyn _DYNAMIC;
/*
* These are the functions the dynamic linker exports to application
* programs. They are the only symbols the dynamic linker is willing
@ -167,20 +165,21 @@ char **environ;
* sequence of "auxiliary vector" entries.
*
* The second argument points to a place to store the dynamic linker's
* exit procedure pointer.
* exit procedure pointer and the third to a place to store the main
* program's object.
*
* The return value is the main program's entry point.
*/
func_ptr_type
_rtld(Elf32_Word *sp, func_ptr_type *exit_proc)
_rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
{
Elf32_Auxinfo *aux_info[AT_COUNT];
Elf_Auxinfo *aux_info[AT_COUNT];
int i;
int argc;
char **argv;
char **env;
Elf32_Auxinfo *aux;
Elf32_Auxinfo *auxp;
Elf_Auxinfo *aux;
Elf_Auxinfo *auxp;
/*
* On entry, the dynamic linker itself has not been relocated yet.
@ -196,7 +195,7 @@ _rtld(Elf32_Word *sp, func_ptr_type *exit_proc)
env = (char **) sp;
while (*sp++ != 0) /* Skip over environment, and NULL terminator */
;
aux = (Elf32_Auxinfo *) sp;
aux = (Elf_Auxinfo *) sp;
/* Digest the auxiliary vector. */
for (i = 0; i < AT_COUNT; i++)
@ -239,17 +238,17 @@ _rtld(Elf32_Word *sp, func_ptr_type *exit_proc)
if (obj_main == NULL)
die();
} else { /* Main program already loaded. */
const Elf32_Phdr *phdr;
const Elf_Phdr *phdr;
int phnum;
caddr_t entry;
dbg("processing main program's program header");
assert(aux_info[AT_PHDR] != NULL);
phdr = (const Elf32_Phdr *) aux_info[AT_PHDR]->a_un.a_ptr;
phdr = (const Elf_Phdr *) aux_info[AT_PHDR]->a_un.a_ptr;
assert(aux_info[AT_PHNUM] != NULL);
phnum = aux_info[AT_PHNUM]->a_un.a_val;
assert(aux_info[AT_PHENT] != NULL);
assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf32_Phdr));
assert(aux_info[AT_PHENT]->a_un.a_val == sizeof(Elf_Phdr));
assert(aux_info[AT_ENTRY] != NULL);
entry = (caddr_t) aux_info[AT_ENTRY]->a_un.a_ptr;
obj_main = digest_phdr(phdr, phnum, entry);
@ -294,24 +293,27 @@ _rtld(Elf32_Word *sp, func_ptr_type *exit_proc)
r_debug_state(); /* say hello to gdb! */
/* Return the exit procedure and the program entry point. */
*exit_proc = (func_ptr_type) rtld_exit;
*exit_proc = rtld_exit;
*objp = obj_main;
return (func_ptr_type) obj_main->entry;
}
caddr_t
_rtld_bind(const Obj_Entry *obj, Elf32_Word reloff)
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
{
const Elf32_Rel *rel;
const Elf32_Sym *def;
const Elf_Rel *rel;
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf32_Addr *where;
Elf_Addr *where;
caddr_t target;
rel = (const Elf32_Rel *) ((caddr_t) obj->pltrel + reloff);
assert(ELF32_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
if (obj->pltrel)
rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff);
else
rel = (const Elf_Rel *) ((caddr_t) obj->pltrela + reloff);
where = (Elf32_Addr *) (obj->relocbase + rel->r_offset);
def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj, true);
where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
if (def == NULL)
die();
@ -321,7 +323,7 @@ _rtld_bind(const Obj_Entry *obj, Elf32_Word reloff)
defobj->strtab + def->st_name, basename(obj->path),
target, basename(defobj->path));
*where = (Elf32_Addr) target;
*where = (Elf_Addr) target;
return target;
}
@ -388,15 +390,16 @@ die(void)
static void
digest_dynamic(Obj_Entry *obj)
{
const Elf32_Dyn *dynp;
const Elf_Dyn *dynp;
Needed_Entry **needed_tail = &obj->needed;
const Elf32_Dyn *dyn_rpath = NULL;
const Elf_Dyn *dyn_rpath = NULL;
int plttype = DT_REL;
for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
case DT_REL:
obj->rel = (const Elf32_Rel *) (obj->relocbase + dynp->d_un.d_ptr);
obj->rel = (const Elf_Rel *) (obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_RELSZ:
@ -404,11 +407,11 @@ digest_dynamic(Obj_Entry *obj)
break;
case DT_RELENT:
assert(dynp->d_un.d_val == sizeof(Elf32_Rel));
assert(dynp->d_un.d_val == sizeof(Elf_Rel));
break;
case DT_JMPREL:
obj->pltrel = (const Elf32_Rel *)
obj->pltrel = (const Elf_Rel *)
(obj->relocbase + dynp->d_un.d_ptr);
break;
@ -417,22 +420,29 @@ digest_dynamic(Obj_Entry *obj)
break;
case DT_RELA:
obj->rela = (const Elf_Rela *) (obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_RELASZ:
obj->relasize = dynp->d_un.d_val;
break;
case DT_RELAENT:
assert(0); /* Should never appear for i386 */
assert(dynp->d_un.d_val == sizeof(Elf_Rela));
break;
case DT_PLTREL:
assert(dynp->d_un.d_val == DT_REL); /* For the i386 */
plttype = dynp->d_un.d_val;
assert(dynp->d_un.d_val == DT_REL || plttype == DT_RELA);
break;
case DT_SYMTAB:
obj->symtab = (const Elf32_Sym *)
obj->symtab = (const Elf_Sym *)
(obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_SYMENT:
assert(dynp->d_un.d_val == sizeof(Elf32_Sym));
assert(dynp->d_un.d_val == sizeof(Elf_Sym));
break;
case DT_STRTAB:
@ -445,7 +455,7 @@ digest_dynamic(Obj_Entry *obj)
case DT_HASH:
{
const Elf32_Word *hashtab = (const Elf32_Word *)
const Elf_Addr *hashtab = (const Elf_Addr *)
(obj->relocbase + dynp->d_un.d_ptr);
obj->nbuckets = hashtab[0];
obj->nchains = hashtab[1];
@ -468,7 +478,7 @@ digest_dynamic(Obj_Entry *obj)
break;
case DT_PLTGOT:
obj->got = (Elf32_Addr *) (obj->relocbase + dynp->d_un.d_ptr);
obj->got = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_TEXTREL:
@ -502,11 +512,24 @@ digest_dynamic(Obj_Entry *obj)
case DT_DEBUG:
/* XXX - not implemented yet */
dbg("Filling in DT_DEBUG entry");
((Elf32_Dyn*)dynp)->d_un.d_ptr = (Elf32_Addr) &r_debug;
((Elf_Dyn*)dynp)->d_un.d_ptr = (Elf_Addr) &r_debug;
break;
default:
xprintf("Ignored d_tag %d\n",dynp->d_tag);
break;
}
}
obj->traced = false;
if (plttype == DT_RELA) {
obj->pltrela = (const Elf_Rela *) obj->pltrel;
obj->pltrel = NULL;
obj->pltrelasize = obj->pltrelsize;
obj->pltrelsize = 0;
}
if (dyn_rpath != NULL)
obj->rpath = obj->strtab + dyn_rpath->d_un.d_val;
}
@ -518,19 +541,19 @@ digest_dynamic(Obj_Entry *obj)
* returns an Obj_Entry structure.
*/
static Obj_Entry *
digest_phdr(const Elf32_Phdr *phdr, int phnum, caddr_t entry)
digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry)
{
Obj_Entry *obj = CNEW(Obj_Entry);
const Elf32_Phdr *phlimit = phdr + phnum;
const Elf32_Phdr *ph;
const Elf_Phdr *phlimit = phdr + phnum;
const Elf_Phdr *ph;
int nsegs = 0;
for (ph = phdr; ph < phlimit; ph++) {
switch (ph->p_type) {
case PT_PHDR:
assert((const Elf32_Phdr *) ph->p_vaddr == phdr);
obj->phdr = (const Elf32_Phdr *) ph->p_vaddr;
assert((const Elf_Phdr *) ph->p_vaddr == phdr);
obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
obj->phsize = ph->p_memsz;
break;
@ -550,7 +573,7 @@ digest_phdr(const Elf32_Phdr *phdr, int phnum, caddr_t entry)
break;
case PT_DYNAMIC:
obj->dynamic = (const Elf32_Dyn *) ph->p_vaddr;
obj->dynamic = (const Elf_Dyn *) ph->p_vaddr;
break;
}
}
@ -576,62 +599,11 @@ dlcheck(void *handle)
return obj;
}
/*
* Process the special R_386_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.
*/
static int
do_copy_relocations(Obj_Entry *dstobj)
{
const Elf32_Rel *rellim;
const Elf32_Rel *rel;
assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
rellim = (const Elf32_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
for (rel = dstobj->rel; rel < rellim; rel++) {
if (ELF32_R_TYPE(rel->r_info) == R_386_COPY) {
void *dstaddr;
const Elf32_Sym *dstsym;
const char *name;
unsigned long hash;
size_t size;
const void *srcaddr;
const Elf32_Sym *srcsym;
Obj_Entry *srcobj;
dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
dstsym = dstobj->symtab + ELF32_R_SYM(rel->r_info);
name = dstobj->strtab + dstsym->st_name;
hash = elf_hash(name);
size = dstsym->st_size;
for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
if ((srcsym = 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;
}
/*
* Hash function for symbol table lookup. Don't even think about changing
* this. It is specified by the System V ABI.
*/
static unsigned long
unsigned long
elf_hash(const char *name)
{
const unsigned char *p = (const unsigned char *) name;
@ -687,13 +659,13 @@ find_library(const char *name, const Obj_Entry *refobj)
* no definition was found. Returns a pointer to the Obj_Entry of the
* defining object via the reference parameter DEFOBJ_OUT.
*/
static const Elf32_Sym *
const Elf_Sym *
find_symdef(unsigned long symnum, const Obj_Entry *refobj,
const Obj_Entry **defobj_out, bool in_plt)
{
const Elf32_Sym *ref;
const Elf32_Sym *strongdef;
const Elf32_Sym *weakdef;
const Elf_Sym *ref;
const Elf_Sym *strongdef;
const Elf_Sym *weakdef;
const Obj_Entry *obj;
const Obj_Entry *strongobj;
const Obj_Entry *weakobj;
@ -705,7 +677,7 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj,
hash = elf_hash(name);
if (refobj->symbolic) { /* Look first in the referencing object */
const Elf32_Sym *def = symlook_obj(name, hash, refobj, in_plt);
const Elf_Sym *def = symlook_obj(name, hash, refobj, in_plt);
if (def != NULL) {
*defobj_out = refobj;
return def;
@ -723,9 +695,9 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj,
strongobj = weakobj = NULL;
for (obj = obj_list; obj != NULL; obj = obj->next) {
if (obj != refobj || !refobj->symbolic) {
const Elf32_Sym *def = symlook_obj(name, hash, obj, in_plt);
const Elf_Sym *def = symlook_obj(name, hash, obj, in_plt);
if (def != NULL) {
if (ELF32_ST_BIND(def->st_info) == STB_WEAK) {
if (ELF_ST_BIND(def->st_info) == STB_WEAK) {
if (weakdef == NULL) {
weakdef = def;
weakobj = obj;
@ -747,9 +719,9 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj,
* can be resolved from the dynamic linker.
*/
if (strongdef == NULL) {
const Elf32_Sym *def = symlook_obj(name, hash, &obj_rtld, in_plt);
const Elf_Sym *def = symlook_obj(name, hash, &obj_rtld, in_plt);
if (def != NULL && is_exported(def)) {
if (ELF32_ST_BIND(def->st_info) == STB_WEAK) {
if (ELF_ST_BIND(def->st_info) == STB_WEAK) {
if (weakdef == NULL) {
weakdef = def;
weakobj = &obj_rtld;
@ -789,9 +761,17 @@ init_rtld(caddr_t mapbase)
obj_rtld.mapbase = mapbase;
obj_rtld.relocbase = mapbase;
obj_rtld.got = get_got_address();
obj_rtld.dynamic = (const Elf32_Dyn *) (obj_rtld.mapbase + obj_rtld.got[0]);
#ifdef __alpha__
obj_rtld.dynamic = (const Elf_Dyn *) &_DYNAMIC;
#else
obj_rtld.dynamic = (const Elf_Dyn *) (obj_rtld.mapbase + obj_rtld.got[0]);
#endif
digest_dynamic(&obj_rtld);
#ifdef __alpha__
/* XXX XXX XXX */
obj_rtld.got = NULL;
#endif
assert(obj_rtld.needed == NULL);
assert(!obj_rtld.textrel);
@ -813,7 +793,7 @@ init_rtld(caddr_t mapbase)
}
static bool
is_exported(const Elf32_Sym *def)
is_exported(const Elf_Sym *def)
{
func_ptr_type value;
const func_ptr_type *p;
@ -914,7 +894,7 @@ obj_from_addr(const void *addr)
endhash = elf_hash(END_SYM);
for (obj = obj_list; obj != NULL; obj = obj->next) {
const Elf32_Sym *endsym;
const Elf_Sym *endsym;
if (addr < (void *) obj->mapbase)
continue;
@ -938,9 +918,6 @@ relocate_objects(Obj_Entry *first, bool bind_now)
Obj_Entry *obj;
for (obj = first; obj != NULL; obj = obj->next) {
const Elf32_Rel *rellim;
const Elf32_Rel *rel;
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",
@ -959,89 +936,8 @@ relocate_objects(Obj_Entry *first, bool bind_now)
}
/* Process the non-PLT relocations. */
rellim = (const Elf32_Rel *) ((caddr_t) obj->rel + obj->relsize);
for (rel = obj->rel; rel < rellim; rel++) {
Elf32_Addr *where = (Elf32_Addr *) (obj->relocbase + rel->r_offset);
switch (ELF32_R_TYPE(rel->r_info)) {
case R_386_NONE:
break;
case R_386_32:
{
const Elf32_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where += (Elf32_Addr) (defobj->relocbase + def->st_value);
}
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 Elf32_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where +=
(Elf32_Addr) (defobj->relocbase + def->st_value) -
(Elf32_Addr) where;
}
break;
case R_386_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_386_COPY relocation"
" in shared library", obj->path);
return -1;
}
break;
case R_386_GLOB_DAT:
{
const Elf32_Sym *def;
const Obj_Entry *defobj;
def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj,
false);
if (def == NULL)
return -1;
*where = (Elf32_Addr) (defobj->relocbase + def->st_value);
}
break;
case R_386_RELATIVE:
*where += (Elf32_Addr) obj->relocbase;
break;
default:
_rtld_error("%s: Unsupported relocation type %d"
" in non-PLT relocations\n", obj->path,
ELF32_R_TYPE(rel->r_info));
if (reloc_non_plt(obj, &obj_rtld))
return -1;
}
}
if (obj->textrel) { /* Re-protected the text segment. */
if (mprotect(obj->mapbase, obj->textsize,
@ -1053,30 +949,8 @@ relocate_objects(Obj_Entry *first, bool bind_now)
}
/* Process the PLT relocations. */
rellim = (const Elf32_Rel *) ((caddr_t) obj->pltrel + obj->pltrelsize);
if (bind_now) {
/* Fully resolve procedure addresses now */
for (rel = obj->pltrel; rel < rellim; rel++) {
Elf32_Addr *where = (Elf32_Addr *)
(obj->relocbase + rel->r_offset);
const Elf32_Sym *def;
const Obj_Entry *defobj;
assert(ELF32_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
def = find_symdef(ELF32_R_SYM(rel->r_info), obj, &defobj, true);
if (def == NULL)
return -1;
*where = (Elf32_Addr) (defobj->relocbase + def->st_value);
}
} else { /* Just relocate the GOT slots pointing into the PLT */
for (rel = obj->pltrel; rel < rellim; rel++) {
Elf32_Addr *where = (Elf32_Addr *)
(obj->relocbase + rel->r_offset);
*where += (Elf32_Addr) obj->relocbase;
}
}
if (reloc_plt(obj, bind_now))
return -1;
/*
* Set up the magic number and version in the Obj_Entry. These
@ -1088,8 +962,16 @@ relocate_objects(Obj_Entry *first, bool bind_now)
/* Set the special GOT entries. */
if (obj->got) {
obj->got[1] = (Elf32_Addr) obj;
obj->got[2] = (Elf32_Addr) &_rtld_bind_start;
#ifdef __i386__
obj->got[1] = (Elf_Addr) obj;
obj->got[2] = (Elf_Addr) &_rtld_bind_start;
#endif
#ifdef __alpha__
/* This function will be called to perform the relocation. */
obj->got[2] = (Elf_Addr) &_rtld_bind_start;
/* Identify this shared object */
obj->got[3] = (Elf_Addr) obj;
#endif
}
}
@ -1239,7 +1121,7 @@ dlsym(void *handle, const char *name)
{
const Obj_Entry *obj;
unsigned long hash;
const Elf32_Sym *def;
const Elf_Sym *def;
hash = elf_hash(name);
def = NULL;
@ -1341,14 +1223,14 @@ r_debug_state(void)
* The symbol's hash value is passed in for efficiency reasons; that
* eliminates many recomputations of the hash value.
*/
static const Elf32_Sym *
const Elf_Sym *
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 != STN_UNDEF) {
const Elf32_Sym *symp;
const Elf_Sym *symp;
const char *strp;
assert(symnum < obj->nchains);
@ -1359,7 +1241,7 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj,
if (strcmp(name, strp) == 0)
return symp->st_shndx != SHN_UNDEF ||
(!in_plt && symp->st_value != 0 &&
ELF32_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL;
ELF_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL;
symnum = obj->chains[symnum];
}

View File

@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: rtld.h,v 1.3 1998/08/21 03:29:40 jb Exp $
* $Id: rtld.h,v 1.4 1998/09/02 02:51:12 jdp Exp $
*/
#ifndef RTLD_H /* { */
@ -88,15 +88,19 @@ typedef struct Struct_Obj_Entry {
Elf_Addr *got; /* GOT table */
const Elf_Rel *rel; /* Relocation entries */
unsigned long relsize; /* Size in bytes of relocation info */
const Elf_Rela *rela; /* Relocation entries with addend */
unsigned long relasize; /* Size in bytes of addend relocation info */
const Elf_Rel *pltrel; /* PLT relocation entries */
unsigned long pltrelsize; /* Size in bytes of PLT relocation info */
const Elf_Rela *pltrela; /* PLT relocation entries with addend */
unsigned long pltrelasize; /* Size in bytes of PLT addend reloc info */
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 */
const Elf_Addr *buckets; /* Hash table buckets array */
unsigned long nbuckets; /* Number of buckets */
const Elf_Word *chains; /* Hash table chain array */
const Elf_Addr *chains; /* Hash table chain array */
unsigned long nchains; /* Number of chains */
const char *rpath; /* Search path specified in object */
@ -122,5 +126,18 @@ extern Obj_Entry *map_object(int);
extern void *xcalloc(size_t);
extern void *xmalloc(size_t);
extern char *xstrdup(const char *);
extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
/*
* Function declarations.
*/
int do_copy_relocations(Obj_Entry *);
int reloc_non_plt(Obj_Entry *, Obj_Entry *);
int reloc_plt(Obj_Entry *, bool);
unsigned long elf_hash(const char *);
const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *,
const Obj_Entry **, bool);
const Elf_Sym *symlook_obj(const char *, unsigned long,
const Obj_Entry *, bool);
#endif /* } */