diff options
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/rtld-aout/Makefile | 24 | ||||
-rw-r--r-- | libexec/rtld-aout/i386/md-static-funcs.c | 15 | ||||
-rw-r--r-- | libexec/rtld-aout/i386/md.c | 329 | ||||
-rw-r--r-- | libexec/rtld-aout/i386/md.h | 198 | ||||
-rw-r--r-- | libexec/rtld-aout/i386/mdprologue.S | 124 | ||||
-rw-r--r-- | libexec/rtld-aout/md-prologue.c | 39 | ||||
-rw-r--r-- | libexec/rtld-aout/rtld.c | 1026 | ||||
-rw-r--r-- | libexec/rtld-aout/shlib.c | 203 |
8 files changed, 1958 insertions, 0 deletions
diff --git a/libexec/rtld-aout/Makefile b/libexec/rtld-aout/Makefile new file mode 100644 index 0000000..ea02608 --- /dev/null +++ b/libexec/rtld-aout/Makefile @@ -0,0 +1,24 @@ +# $Id: Makefile,v 1.2 1993/10/27 00:55:24 pk Exp $ + +PROG= ld.so +SRCS= mdprologue.S rtld.c shlib.c etc.c md.c +NOMAN= noman +LDDIR?= $(.CURDIR)/.. +#PICFLAG=-pic +PICFLAG=-fpic +CFLAGS += -I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) -O $(PICFLAG) -DRTLD +LDFLAGS = -Bshareable -Bsymbolic -assert nosymbolic +LIBS = -lc_pic +BINDIR= /usr/libexec + +.PATH: $(LDDIR) $(LDDIR)/$(MACHINE) + +.SUFFIXES: .S + +$(PROG): + $(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIBS) + +.S.o: + $(CPP) $(.IMPSRC) | $(AS) -k -o $(.TARGET) - + +.include <bsd.prog.mk> diff --git a/libexec/rtld-aout/i386/md-static-funcs.c b/libexec/rtld-aout/i386/md-static-funcs.c new file mode 100644 index 0000000..2cd0768 --- /dev/null +++ b/libexec/rtld-aout/i386/md-static-funcs.c @@ -0,0 +1,15 @@ + +/* + * Called by ld.so when onanating. + * This *must* be a static function, so it is not called through a jmpslot. + */ +static void +md_relocate_simple(r, relocation, addr) +struct relocation_info *r; +long relocation; +char *addr; +{ +if (r->r_relative) + *(long *)addr += relocation; +} + diff --git a/libexec/rtld-aout/i386/md.c b/libexec/rtld-aout/i386/md.c new file mode 100644 index 0000000..bfe12e9 --- /dev/null +++ b/libexec/rtld-aout/i386/md.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 1993 Paul Kranenburg + * 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 Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: md.c,v 1.2 1993/10/27 00:54:58 pk Exp $ + */ + +#include <sys/param.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> +#include <a.out.h> +#include <stab.h> +#include <string.h> + +#include "ld.h" + +/* + * Get relocation addend corresponding to relocation record RP + * from address ADDR + */ +long +md_get_addend(rp, addr) +struct relocation_info *rp; +unsigned char *addr; +{ + switch (RELOC_TARGET_SIZE(rp)) { + case 0: + return get_byte(addr); + break; + case 1: + return get_short(addr); + break; + case 2: + return get_long(addr); + break; + } +} + +/* + * Put RELOCATION at ADDR according to relocation record RP. + */ +void +md_relocate(rp, relocation, addr, relocatable_output) +struct relocation_info *rp; +long relocation; +unsigned char *addr; +{ + switch (RELOC_TARGET_SIZE(rp)) { + case 0: + put_byte(addr, relocation); + break; + case 1: + put_short(addr, relocation); + break; + case 2: + put_long(addr, relocation); + break; + default: + fatal("Unsupported relocation size: %x", RELOC_TARGET_SIZE(rp)); + } +} + +/* + * Initialize (output) exec header such that useful values are + * obtained from subsequent N_*() macro evaluations. + */ +void +md_init_header(hp, magic, flags) +struct exec *hp; +int magic, flags; +{ + N_SETMAGIC((*hp), magic, MID_I386, flags); + + /* TEXT_START depends on the value of outheader.a_entry. */ + if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */ + hp->a_entry = PAGSIZ; +} + +/* + * Machine dependent part of claim_rrs_reloc(). + * Set RRS relocation type. + */ +int +md_make_reloc(rp, r, type) +struct relocation_info *rp, *r; +int type; +{ + /* Relocation size */ + r->r_length = rp->r_length; + + if (RELOC_PCREL_P(rp)) + r->r_pcrel = 1; + + if (type & RELTYPE_RELATIVE) + r->r_relative = 1; + + if (type & RELTYPE_COPY) + r->r_copy = 1; + + return 0; +} + +/* + * Set up a transfer from jmpslot at OFFSET (relative to the PLT table) + * to the binder slot (which is at offset 0 of the PLT). + */ +void +md_make_jmpslot(sp, offset, index) +jmpslot_t *sp; +long offset; +long index; +{ + /* + * i386 PC-relative "fixed point" is located right after the + * instruction it pertains to. + */ + u_long fudge = - (sizeof(sp->opcode) + sizeof(sp->addr) + offset); + + sp->opcode = CALL; +#if 0 + sp->addr = fudge; +#else + sp->addr[0] = fudge & 0xffff; + sp->addr[1] = fudge >> 16; +#endif + sp->reloc_index = index; +} + +/* + * Set up a "direct" transfer (ie. not through the run-time binder) from + * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on, + * and by `ld.so' after resolving the symbol. + * On the i386, we use the JMP instruction which is PC relative, so no + * further RRS relocations will be necessary for such a jmpslot. + */ +void +md_fix_jmpslot(sp, offset, addr) +jmpslot_t *sp; +long offset; +u_long addr; +{ + u_long fudge = addr - (sizeof(sp->opcode) + sizeof(sp->addr) + offset); + + sp->opcode = JUMP; +#if 0 + sp->addr = fudge; +#else + sp->addr[0] = fudge & 0xffff; + sp->addr[1] = fudge >> 16; +#endif + sp->reloc_index = 0; +} + +/* + * Update the relocation record for a RRS jmpslot. + */ +void +md_make_jmpreloc(rp, r, type) +struct relocation_info *rp, *r; +int type; +{ + jmpslot_t *sp; + + /* + * Fix relocation address to point to the correct + * location within this jmpslot. + */ + r->r_address += sizeof(sp->opcode); + + /* Relocation size */ + r->r_length = 2; + + /* Set relocation type */ + r->r_jmptable = 1; + if (type & RELTYPE_RELATIVE) + r->r_relative = 1; + +} + +/* + * Set relocation type for a RRS GOT relocation. + */ +void +md_make_gotreloc(rp, r, type) +struct relocation_info *rp, *r; +int type; +{ + r->r_baserel = 1; + if (type & RELTYPE_RELATIVE) + r->r_relative = 1; + + /* Relocation size */ + r->r_length = 2; +} + +/* + * Set relocation type for a RRS copy operation. + */ +void +md_make_cpyreloc(rp, r) +struct relocation_info *rp, *r; +{ + /* Relocation size */ + r->r_length = 2; + + r->r_copy = 1; +} + + +#ifdef NEED_SWAP + +/* + * Byte swap routines for cross-linking. + */ + +void +md_swapin_exec_hdr(h) +struct exec *h; +{ + int skip = 0; + + if (!N_BADMAG(*h)) + skip = 1; + + swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip); +} + +void +md_swapout_exec_hdr(h) +struct exec *h; +{ + /* NetBSD: Always leave magic alone */ + int skip = 1; +#if 0 + if (N_GETMAGIC(*h) == OMAGIC) + skip = 0; +#endif + + swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip); +} + + +void +md_swapin_reloc(r, n) +struct relocation_info *r; +int n; +{ + int bits; + + for (; n; n--, r++) { + r->r_address = md_swap_long(r->r_address); + bits = ((int *)r)[1]; + r->r_symbolnum = md_swap_long(bits & 0xffffff00); + r->r_pcrel = (bits & 1); + r->r_length = ((bits >> 1) & 3); + r->r_extern = ((bits >> 3) & 1); + r->r_baserel = ((bits >> 4) & 1); + r->r_jmptable = ((bits >> 5) & 1); + r->r_relative = ((bits >> 6) & 1); +#ifdef N_SIZE + r->r_copy = ((bits >> 7) & 1); +#endif + } +} + +void +md_swapout_reloc(r, n) +struct relocation_info *r; +int n; +{ + int bits; + + for (; n; n--, r++) { + r->r_address = md_swap_long(r->r_address); + bits = (md_swap_long(r->r_symbolnum) & 0xffffff00); + bits |= (r->r_pcrel & 1); + bits |= ((r->r_length << 1) & 6); + bits |= ((r->r_extern << 3) & 8); + bits |= ((r->r_baserel << 4) & 0x10); + bits |= ((r->r_jmptable << 5) & 0x20); + bits |= ((r->r_relative << 6) & 0x40); +#ifdef N_SIZE + bits |= ((r->r_copy << 7) & 0x80); +#endif + ((int *)r)[1] = bits; + } +} + +void +md_swapout_jmpslot(j, n) +jmpslot_t *j; +int n; +{ + for (; n; n--, j++) { + j->opcode = md_swap_short(j->opcode); + j->addr[0] = md_swap_short(j->addr[0]); + j->addr[1] = md_swap_short(j->addr[1]); + j->reloc_index = md_swap_short(j->reloc_index); + } +} + +#endif /* NEED_SWAP */ diff --git a/libexec/rtld-aout/i386/md.h b/libexec/rtld-aout/i386/md.h new file mode 100644 index 0000000..ecd1815 --- /dev/null +++ b/libexec/rtld-aout/i386/md.h @@ -0,0 +1,198 @@ +/* + * $Id: md.h,v 1.3 1993/10/24 00:52:40 pk Exp $ - I386 dependent definitions + */ + + +#if defined(CROSS_LINKER) && defined(XHOST) && XHOST==sparc + +#define NEED_SWAP + +#endif + +#define MAX_ALIGNMENT (sizeof (long)) + +#ifdef NetBSD +#define PAGSIZ __LDPGSZ +#else +#define PAGSIZ 4096 +#endif + +#define N_SET_FLAG(ex,f) N_SETMAGIC(ex,N_GETMAGIC(ex), MID_MACHINE, \ + N_GETFLAG(ex)|(f)) + +#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC)) + +/* + * Should be handled by a.out.h ? + */ +#define N_ADJUST(ex) (((ex).a_entry < PAGSIZ) ? -PAGSIZ : 0) +#define TEXT_START(ex) (N_TXTADDR(ex) + N_ADJUST(ex)) +#define DATA_START(ex) (N_DATADDR(ex) + N_ADJUST(ex)) + +#define RELOC_STATICS_THROUGH_GOT_P(r) (0) +#define JMPSLOT_NEEDS_RELOC (0) + +#define md_got_reloc(r) (0) + +#define md_get_rt_segment_addend(r,a) md_get_addend(r,a) + +/* Width of a Global Offset Table entry */ +#define GOT_ENTRY_SIZE 4 +typedef long got_t; + +typedef struct jmpslot { + u_short opcode; + u_short addr[2]; + u_short reloc_index; +#define JMPSLOT_RELOC_MASK 0xffff +} jmpslot_t; + +#define NOP 0x90 +#define CALL 0xe890 /* NOP + CALL opcode */ +#define JUMP 0xe990 /* NOP + JMP opcode */ +#define TRAP 0xcc /* INT 3 */ + +/* + * Byte swap defs for cross linking + */ + +#if !defined(NEED_SWAP) + +#define md_swapin_exec_hdr(h) +#define md_swapout_exec_hdr(h) +#define md_swapin_symbols(s,n) +#define md_swapout_symbols(s,n) +#define md_swapin_zsymbols(s,n) +#define md_swapout_zsymbols(s,n) +#define md_swapin_reloc(r,n) +#define md_swapout_reloc(r,n) +#define md_swapin_link_dynamic(l) +#define md_swapout_link_dynamic(l) +#define md_swapin_link_dynamic_2(l) +#define md_swapout_link_dynamic_2(l) +#define md_swapin_ld_debug(d) +#define md_swapout_ld_debug(d) +#define md_swapin_rrs_hash(f,n) +#define md_swapout_rrs_hash(f,n) +#define md_swapin_link_object(l,n) +#define md_swapout_link_object(l,n) +#define md_swapout_jmpslot(j,n) +#define md_swapout_got(g,n) +#define md_swapin_ranlib_hdr(h,n) +#define md_swapout_ranlib_hdr(h,n) + +#endif /* NEED_SWAP */ + +#ifdef CROSS_LINKER + +#ifdef NEED_SWAP + +/* Define IO byte swapping routines */ + +void md_swapin_exec_hdr __P((struct exec *)); +void md_swapout_exec_hdr __P((struct exec *)); +void md_swapin_reloc __P((struct relocation_info *, int)); +void md_swapout_reloc __P((struct relocation_info *, int)); +void md_swapout_jmpslot __P((jmpslot_t *, int)); + +#define md_swapin_symbols(s,n) swap_symbols(s,n) +#define md_swapout_symbols(s,n) swap_symbols(s,n) +#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n) +#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n) +#define md_swapin_link_dynamic(l) swap_link_dynamic(l) +#define md_swapout_link_dynamic(l) swap_link_dynamic(l) +#define md_swapin_link_dynamic_2(l) swap_link_dynamic_2(l) +#define md_swapout_link_dynamic_2(l) swap_link_dynamic_2(l) +#define md_swapin_ld_debug(d) swap_ld_debug(d) +#define md_swapout_ld_debug(d) swap_ld_debug(d) +#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n) +#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n) +#define md_swapin_link_object(l,n) swapin_link_object(l,n) +#define md_swapout_link_object(l,n) swapout_link_object(l,n) +#define md_swapout_got(g,n) swap_longs((long*)(g),n) +#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n) +#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n) + +#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) ) + +#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \ + (((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000)) + +#define get_byte(p) ( ((unsigned char *)(p))[0] ) + +#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \ + ( ((unsigned char *)(p))[0] ) \ + ) +#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \ + ( ((unsigned char *)(p))[2] << 16) | \ + ( ((unsigned char *)(p))[1] << 8 ) | \ + ( ((unsigned char *)(p))[0] ) \ + ) + +#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); } + +#define put_short(p, v) { ((unsigned char *)(p))[1] = \ + ((((unsigned long)(v)) >> 8) & 0xff); \ + ((unsigned char *)(p))[0] = \ + ((((unsigned long)(v)) ) & 0xff); } + +#define put_long(p, v) { ((unsigned char *)(p))[3] = \ + ((((unsigned long)(v)) >> 24) & 0xff); \ + ((unsigned char *)(p))[2] = \ + ((((unsigned long)(v)) >> 16) & 0xff); \ + ((unsigned char *)(p))[1] = \ + ((((unsigned long)(v)) >> 8) & 0xff); \ + ((unsigned char *)(p))[0] = \ + ((((unsigned long)(v)) ) & 0xff); } + +#else /* We need not swap, but must pay attention to alignment: */ + +#define md_swap_short(x) (x) +#define md_swap_long(x) (x) + +#define get_byte(p) ( ((unsigned char *)(p))[0] ) + +#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \ + ( ((unsigned char *)(p))[1] ) \ + ) + +#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \ + ( ((unsigned char *)(p))[1] << 16) | \ + ( ((unsigned char *)(p))[2] << 8 ) | \ + ( ((unsigned char *)(p))[3] ) \ + ) + + +#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); } + +#define put_short(p, v) { ((unsigned char *)(p))[0] = \ + ((((unsigned long)(v)) >> 8) & 0xff); \ + ((unsigned char *)(p))[1] = \ + ((((unsigned long)(v)) ) & 0xff); } + +#define put_long(p, v) { ((unsigned char *)(p))[0] = \ + ((((unsigned long)(v)) >> 24) & 0xff); \ + ((unsigned char *)(p))[1] = \ + ((((unsigned long)(v)) >> 16) & 0xff); \ + ((unsigned char *)(p))[2] = \ + ((((unsigned long)(v)) >> 8) & 0xff); \ + ((unsigned char *)(p))[3] = \ + ((((unsigned long)(v)) ) & 0xff); } + +#endif /* NEED_SWAP */ + +#else /* Not a cross linker: use native */ + +#define md_swap_short(x) (x) +#define md_swap_long(x) (x) + +#define get_byte(where) (*(char *)(where)) +#define get_short(where) (*(short *)(where)) +#define get_long(where) (*(long *)(where)) + +#define put_byte(where,what) (*(char *)(where) = (what)) +#define put_short(where,what) (*(short *)(where) = (what)) +#define put_long(where,what) (*(long *)(where) = (what)) + +#endif /* CROSS_LINKER */ + diff --git a/libexec/rtld-aout/i386/mdprologue.S b/libexec/rtld-aout/i386/mdprologue.S new file mode 100644 index 0000000..3b7a6da --- /dev/null +++ b/libexec/rtld-aout/i386/mdprologue.S @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1993 Paul Kranenburg + * 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 Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: mdprologue.S,v 1.1 1993/10/16 21:53:16 pk Exp $ + */ + +/* + * i386 run-time link editor entry points. + */ + +#include <sys/syscall.h> +#define LCALL(x,y) .byte 0x9a ; .long y; .word x + + .text + .globl _binder, _binder_entry + +/* + * _rtl(int version, struct crt_ldso *crtp) + */ +#define FRAME 12 /* Size of stack frame */ + + +_rtl: # crt0 calls us here + pushl %ebp # Allocate stack frame + movl %esp, %ebp + subl $FRAME, %esp + pushl %ebx + call 1f # PIC function prologue +1: + popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + + movl 12(%ebp), %eax # Extract data from interface structure + movl (%eax),%eax # base address of ld.so (first field) + # setup arguments for rtld() + movl (%ebx), %ecx # 1st entry in GOT is our __DYNAMIC + addl %eax, %ecx # add load address + pushl %ecx # 3rd arg + pushl 12(%ebp) # 2nd arg == &crt. + pushl 8(%ebp) # 1st arg == version + addl _rtld@GOT(%ebx), %eax # relocate address of function + call %eax # _rtld(version, crtp, DYNAMIC) + addl $12,%esp # pop arguments + + movl (-FRAME-4)(%ebp), %ebx # restore %ebx + leave # remove stack frame, + ret # let's rock + + # First call to a procedure generally comes through here for + # binding. + +_binder_entry: + pushl %ebp # setup a stack frame + movl %esp, %ebp + pusha # save all regs + + movl $0, %eax # clear + movl 4(%ebp), %esi # return address in PLT + movw (%esi), %ax # get hold of relocation number + subl $6, %esi # make it point to the jmpslot + + pushl %eax # pushd arguments + pushl %esi # + call _binder@PLT # _binder(rpc, index) + addl $8, %esp # pop arguments + movl %eax, 4(%ebp) # return value from _binder() == actual + # address of function + popa # restore regs + leave # remove our stack frame + ret + + # Special system call stubs which return real and effective user and group + # id's. Saves overhead of making separate calls for each. + # !! Relies on compatability option in BSD 4.three-and-a-half + + .globl _getreuid, _getregid +_getreuid: + lea SYS_getuid, %eax + LCALL(7,0) + jc out + movl 4(%esp), %ecx # get 1st arg + movl %eax, (%ecx) # put value in it + movl 8(%esp), %ecx # same for 2nd arg + movl %edx, (%ecx) # + ret # done + +_getregid: + lea SYS_getgid, %eax + LCALL(7,0) + jc out + movl 4(%esp), %ecx # get 1st arg + movl %eax, (%ecx) # put value in it + movl 8(%esp), %ecx # same for 2nd arg + movl %edx, (%ecx) # + ret # done + +out: jmp cerror@PLT # Call common error routine + diff --git a/libexec/rtld-aout/md-prologue.c b/libexec/rtld-aout/md-prologue.c new file mode 100644 index 0000000..dae455e --- /dev/null +++ b/libexec/rtld-aout/md-prologue.c @@ -0,0 +1,39 @@ +/* + * rtld entry pseudo code - turn into assembler and tweak it + */ + +#include <sys/types.h> +#include <sys/types.h> +#include <a.out.h> +#include "link.h" +#include "md.h" + +extern long _GOT_[]; +extern void (*rtld)(); +extern void (*binder())(); + +void +rtld_entry(version, crtp) +int version; +struct crt *crtp; +{ + register struct link_dynamic *dp; + register void (*f)(); + + /* __DYNAMIC is first entry in GOT */ + dp = (struct link_dynamic *) (_GOT_[0]+crtp->crt_ba); + + f = (void (*)())((long)rtld + crtp->crt_ba); + (*f)(version, crtp, dp); +} + +void +binder_entry() +{ + extern int PC; + struct jmpslot *sp; + void (*func)(); + + func = binder(PC, sp->reloc_index & 0x003fffff); + (*func)(); +} diff --git a/libexec/rtld-aout/rtld.c b/libexec/rtld-aout/rtld.c new file mode 100644 index 0000000..433820a --- /dev/null +++ b/libexec/rtld-aout/rtld.c @@ -0,0 +1,1026 @@ +/* + * Copyright (c) 1993 Paul Kranenburg + * 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 Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: rtld.c,v 1.7 1993/11/03 21:35:54 pk Exp $ + */ + +#include <sys/param.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/mman.h> +#ifndef BSD +#define MAP_COPY MAP_PRIVATE +#define MAP_FILE 0 +#define MAP_ANON 0 +#endif +#include <fcntl.h> +#include <a.out.h> +#include <stab.h> +#include <string.h> +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#include "ld.h" + +#ifndef BSD /* Need do better than this */ +#define NEED_DEV_ZERO 1 +#endif + +/* + * Loader private data, hung off link_map->lm_lpd + */ +struct lm_private { + int lpd_version; + struct link_map *lpd_parent; +#ifdef SUN_COMPAT + long lpd_offset; /* Correction for Sun main programs */ +#endif +}; + +#ifdef SUN_COMPAT +#define LM_OFFSET(lmp) (((struct lm_private *)((lmp)->lm_lpd))->lpd_offset) +#else +#define LM_OFFSET(lmp) (0) +#endif + +/* Base address for link_dynamic_2 entries */ +#define LM_LDBASE(lmp) (lmp->lm_addr + LM_OFFSET(lmp)) + +/* Start of text segment */ +#define LM_TXTADDR(lmp) (lmp->lm_addr == (caddr_t)0 ? PAGSIZ : 0) + +/* Start of run-time relocation_info */ +#define LM_REL(lmp) ((struct relocation_info *) \ + (lmp->lm_addr + LM_OFFSET(lmp) + LD_REL((lmp)->lm_ld))) + +/* Start of symbols */ +#define LM_SYMBOL(lmp, i) ((struct nzlist *) \ + (lmp->lm_addr + LM_OFFSET(lmp) + LD_SYMBOL((lmp)->lm_ld) + \ + i * (LD_VERSION_NZLIST_P(lmp->lm_ld->ld_version) ? \ + sizeof(struct nzlist) : sizeof(struct nlist)))) + +/* Start of hash table */ +#define LM_HASH(lmp) ((struct rrs_hash *) \ + (lmp->lm_addr + LM_OFFSET(lmp) + LD_HASH((lmp)->lm_ld))) + +/* Start of strings */ +#define LM_STRINGS(lmp) ((char *) \ + (lmp->lm_addr + LM_OFFSET(lmp) + LD_STRINGS((lmp)->lm_ld))) + +/* End of text */ +#define LM_ETEXT(lmp) ((char *) \ + (lmp->lm_addr + LM_TXTADDR(lmp) + LD_TEXTSZ((lmp)->lm_ld))) + +/* PLT is in data segment, so don't use LM_OFFSET here */ +#define LM_PLT(lmp) ((jmpslot_t *) \ + (lmp->lm_addr + LD_PLT((lmp)->lm_ld))) + +/* Parent of link map */ +#define LM_PARENT(lmp) (((struct lm_private *)((lmp)->lm_lpd))->lpd_parent) + +char **environ; +int errno; +uid_t uid, euid; +gid_t gid, egid; +int careful; + +struct link_map *link_map_head, *main_map; +struct link_map **link_map_tail = &link_map_head; +struct rt_symbol *rt_symbol_head; + +static int dlopen(), dlclose(), dlsym(); + +static struct ld_entry ld_entry = { + dlopen, dlclose, dlsym +}; + +static void xprintf __P((char *, ...)); +static void init_brk __P((void)); +static void load_maps __P((struct crt_ldso *)); +static void map_object __P((struct link_object *, struct link_map *)); +static void alloc_link_map __P(( char *, struct link_object *, + struct link_map *, caddr_t, + struct link_dynamic *)); +static void check_text_reloc __P(( struct relocation_info *, + struct link_map *, + caddr_t)); +static void reloc_maps __P((void)); +static void reloc_copy __P((void)); +static char *rtfindlib __P((char *, int, int, int *)); +void binder_entry __P((void)); +long binder __P((jmpslot_t *)); +static struct nzlist *lookup __P((char *, struct link_map **)); +static struct rt_symbol *lookup_rts __P((char *)); +static struct rt_symbol *enter_rts __P((char *, long, int, caddr_t, long)); + +#include "md-static-funcs.c" + +/* + * Called from assembler stub that has set up crtp (passed from crt0) + * and dp (our __DYNAMIC). + */ +void +rtld(version, crtp, dp) +int version; +struct crt_ldso *crtp; +struct link_dynamic *dp; +{ + int n; + int nreloc; /* # of ld.so relocations */ + struct relocation_info *reloc; + char **envp; + + /* Check version */ + if (version != CRT_VERSION_BSD && version != CRT_VERSION_SUN) + return; + + /* Fixup __DYNAMIC structure */ + (long)dp->ld_un.ld_2 += crtp->crt_ba; + + /* Be careful not to use .div routine from library */ + for ( nreloc = 0, n = LD_RELSZ(dp); + n > 0; + n -= sizeof(struct relocation_info) ) nreloc++; + + + /* Relocate ourselves */ + for ( reloc = (struct relocation_info *) + (dp->ld_un.ld_2->ld_rel + crtp->crt_ba); + nreloc; + nreloc--, reloc++) { + + register long addr = reloc->r_address + crtp->crt_ba; + + md_relocate_simple(reloc, crtp->crt_ba, addr); + } + + progname = "ld.so"; + + /* Setup out (private) environ variable */ + environ = crtp->crt_ep; + + /* Get user and group identifiers */ + uid = getuid(); euid = geteuid(); + gid = getgid(); egid = getegid(); + + careful = (uid != euid) || (gid != egid); + + if (careful) { + unsetenv("LD_LIBRARY_PATH"); + unsetenv("LD_PRELOAD"); + unsetenv("LD_RUN_PATH"); /* In case we ever implement this */ + } + + /* Setup directory search */ + std_search_dirs(getenv("LD_LIBRARY_PATH")); + + /* Load required objects into the process address space */ + load_maps(crtp); + + /* Relocate all loaded objects according to their RRS segments */ + reloc_maps(); + reloc_copy(); + + /* Fill in some field in main's __DYNAMIC structure */ + crtp->crt_dp->ld_entry = &ld_entry; + crtp->crt_dp->ldd->ldd_cp = rt_symbol_head; +} + + +static void +load_maps(crtp) +struct crt_ldso *crtp; +{ + struct link_map *lmp; + int tracing = (int)getenv("LD_TRACE_LOADED_OBJECTS"); + + /* Handle LD_PRELOAD's here */ + + /* Make an entry for the main program */ + alloc_link_map("main", (struct link_object *)0, (struct link_map *)0, + (caddr_t)0, crtp->crt_dp); + + for (lmp = link_map_head; lmp; lmp = lmp->lm_next) { + struct link_object *lop; + long next = 0; + + if (lmp->lm_ld) + next = LD_NEED(lmp->lm_ld); + + while (next) { + lop = (struct link_object *) (LM_LDBASE(lmp) + next); + map_object(lop, lmp); + next = lop->lo_next; + } + } + + if (! tracing) + return; + + for (lmp = link_map_head; lmp; lmp = lmp->lm_next) { + struct link_object *lop; + char *name, *path; + + if ((lop = lmp->lm_lop) == NULL) + continue; + + name = lop->lo_name + LM_LDBASE(LM_PARENT(lmp)); + + if ((path = lmp->lm_name) == NULL) + path = "not found"; + + if (lop->lo_library) + printf("\t-l%s.%d => %s\n", name, lop->lo_major, path); + else + printf("\t%s => %s\n", name, path); + } + + _exit(0); +} + +/* + * Allocate a new link map for an shared object NAME loaded at ADDR as a + * result of the presence of link object LOP in the link map PARENT. + */ +static void +alloc_link_map(name, lop, parent, addr, dp) +char *name; +struct link_map *parent; +struct link_object *lop; +caddr_t addr; +struct link_dynamic *dp; +{ + struct link_map *lmp; + struct lm_private *lmpp; + + lmpp = (struct lm_private *)xmalloc(sizeof(struct lm_private)); + lmp = (struct link_map *)xmalloc(sizeof(struct link_map)); + lmp->lm_next = NULL; + *link_map_tail = lmp; + link_map_tail = &lmp->lm_next; + + lmp->lm_addr = addr; + lmp->lm_name = name; + lmp->lm_lop = lop; + lmp->lm_ld = dp; + lmp->lm_lpd = (caddr_t)lmpp; + +/*XXX*/ if (addr == 0) main_map = lmp; + + lmpp->lpd_parent = parent; + +#ifdef SUN_COMPAT + lmpp->lpd_offset = + (addr == 0 && dp->ld_version == LD_VERSION_SUN) ? PAGSIZ : 0; +#endif +} + +/* + * Map object identified by link object LOP which was found + * in link map LMP. + */ +static void +map_object(lop, lmp) +struct link_object *lop; +struct link_map *lmp; +{ + struct link_dynamic *dp; + char *path, *name = (char *)(lop->lo_name + LM_LDBASE(lmp)); + int fd; + caddr_t addr; + struct exec hdr; + int usehints = 0; + + if (lop->lo_library) { + usehints = 1; +again: + path = rtfindlib(name, lop->lo_major, lop->lo_minor, &usehints); + if (path == NULL) + fatal("Cannot find lib%s.so.%d.%d\n", + name, lop->lo_major, lop->lo_minor); + } else { + path = name; + } + + fd = open(path, O_RDONLY, 0); + if (fd == -1) { + if (usehints) { + usehints = 0; + goto again; + } + fatal("%s not found", path); + } + + if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + fatal("%s: Cannot read exec header", path); + } + + if (N_BADMAG(hdr)) + fatal("%s: Incorrect format", path); + + if ((addr = mmap(0, hdr.a_text + hdr.a_data, + PROT_READ|PROT_EXEC, + MAP_FILE|MAP_COPY, fd, 0)) == (caddr_t)-1) + fatal("Cannot map %s text\n", path); + + if (mmap(addr + hdr.a_text, hdr.a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FILE|MAP_FIXED|MAP_COPY, + fd, hdr.a_text) == (caddr_t)-1) + fatal("Cannot map %s data", path); + + close(fd); + + fd = -1; +#ifdef NEED_DEV_ZERO + if ((fd = open("/dev/zero", O_RDWR, 0)) == -1) + perror("/dev/zero"); +#endif + if (hdr.a_bss && mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_ANON|MAP_FIXED|MAP_COPY, + fd, hdr.a_text + hdr.a_data) == (caddr_t)-1) + fatal("Cannot map %s bss", path); + +#ifdef NEED_DEV_ZERO + close(fd); +#endif + + /* Assume _DYNAMIC is the first data item */ + dp = (struct link_dynamic *)(addr+hdr.a_text); + + /* Fixup __DYNAMIC structure */ + (long)dp->ld_un.ld_2 += (long)addr; + + alloc_link_map(path, lop, lmp, addr, dp); + +} + +static void +reloc_maps() +{ + struct link_map *lmp; + + for (lmp = link_map_head; lmp; lmp = lmp->lm_next) { + + struct link_dynamic *dp = lmp->lm_ld; + struct relocation_info *r = LM_REL(lmp); + struct relocation_info *rend = r + LD_RELSZ(dp)/sizeof(*r); + + if (LD_PLTSZ(dp)) + md_fix_jmpslot(LM_PLT(lmp), + (long)LM_PLT(lmp), (long)binder_entry); + + for (; r < rend; r++) { + char *sym; + caddr_t addr = lmp->lm_addr + r->r_address; + + check_text_reloc(r, lmp, addr); + + if (RELOC_EXTERN_P(r)) { + struct link_map *src_map; + struct nzlist *np; + long relocation = md_get_addend(r, addr); + + if (RELOC_LAZY_P(r)) + continue; + + sym = LM_STRINGS(lmp) + + LM_SYMBOL(lmp,RELOC_SYMBOL(r))->nz_strx; + + np = lookup(sym, &src_map); + if (np == NULL) + fatal("Undefined symbol in %s: %s\n", + lmp->lm_name, sym); + + /* + * Found symbol definition. + * If it's in a link map, adjust value + * according to the load address of that map. + * Otherwise it's a run-time allocated common + * whose value is already up-to-date. + */ + relocation += np->nz_value; + if (src_map) + relocation += (long)src_map->lm_addr; + + if (RELOC_PCREL_P(r)) + relocation -= (long)lmp->lm_addr; + + if (RELOC_COPY_P(r) && src_map) { +#if DEBUG +xprintf("RELOCATE(%s) copy: from %s at %#x(%#x+%#x) to %s at %#x, reloc = %#x, size %d\n", +lmp->lm_name, src_map->lm_name, src_map->lm_addr + np->nz_value, +src_map->lm_addr, np->nz_value, sym, addr, relocation, np->nz_size); +#endif + (void)enter_rts(sym, + (long)addr, + N_DATA + N_EXT, + src_map->lm_addr + np->nz_value, + np->nz_size); + continue; + } +#if DEBUG +xprintf("RELOCATE(%s) external: %s at %#x, reloc = %#x\n", lmp->lm_name, sym, addr, relocation); +#endif + md_relocate(r, relocation, addr, 0); + + } else { +#if DEBUG +xprintf("RELOCATE(%s) internal at %#x, reloc = %#x\n", lmp->lm_name, addr, md_get_rt_segment_addend(r,addr)); +#endif + md_relocate(r, +#ifdef SUN_COMPAT + md_get_rt_segment_addend(r, addr) +#else + md_get_addend(r, addr) +#endif + + (long)lmp->lm_addr, addr, 0); + } + + } + + } +} + +static void +reloc_copy() +{ + struct rt_symbol *rtsp; + + for (rtsp = rt_symbol_head; rtsp; rtsp = rtsp->rt_next) + if (rtsp->rt_sp->nz_type == N_DATA + N_EXT) { +#ifdef DEBUG +xprintf("reloc_copy: from %#x to %#x, size %d\n", +rtsp->rt_srcaddr, rtsp->rt_sp->nz_value, rtsp->rt_sp->nz_size); +#endif + bcopy(rtsp->rt_srcaddr, (caddr_t)rtsp->rt_sp->nz_value, + rtsp->rt_sp->nz_size); + } +} + +static void +check_text_reloc(r, lmp, addr) +struct relocation_info *r; +struct link_map *lmp; +caddr_t addr; +{ + char *sym; + + if (addr >= LM_ETEXT(lmp)) + return; + + if (RELOC_EXTERN_P(r)) + sym = LM_STRINGS(lmp) + + LM_SYMBOL(lmp, RELOC_SYMBOL(r))->nz_strx; + else + sym = ""; + +#ifdef DEBUG + fprintf(stderr, "ld.so: warning: non pure code in %s at %x (%s)\n", + lmp->lm_name, r->r_address, sym); +#endif + + if (mprotect( lmp->lm_addr + LM_TXTADDR(lmp), + LD_TEXTSZ(lmp->lm_ld), + PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + + perror("mprotect"), + fatal("Cannot enable writes to %s\n", lmp->lm_name); + } + + lmp->lm_rwt = 1; +} + +static struct nzlist * +lookup(name, src_map) +char *name; +struct link_map **src_map; +{ + long common_size = 0; + struct link_map *lmp; + struct rt_symbol *rtsp; + + *src_map = NULL; + + if ((rtsp = lookup_rts(name)) != NULL) + return rtsp->rt_sp; + + /* + * Search all maps for a definition of NAME + */ + for (lmp = link_map_head; lmp; lmp = lmp->lm_next) { + int buckets = LD_BUCKETS(lmp->lm_ld); + long hashval = 0; + struct rrs_hash *hp; + char *cp; + struct nzlist *np; + + /* + * Compute bucket in which the symbol might be found. + */ + for (cp = name; *cp; cp++) + hashval = (hashval << 1) + *cp; + + hashval = (hashval & 0x7fffffff) % buckets; + + hp = LM_HASH(lmp) + hashval; + if (hp->rh_symbolnum == -1) + /* Nothing in this bucket */ + continue; + + while (hp) { + np = LM_SYMBOL(lmp, hp->rh_symbolnum); + cp = LM_STRINGS(lmp) + np->nz_strx; + if (strcmp(cp, name) == 0) + break; + if (hp->rh_next == 0) + hp = NULL; + else + hp = LM_HASH(lmp) + hp->rh_next; + } + if (hp == NULL) + /* Nothing in this bucket */ + continue; + + /* + * We have a symbol with the name we're looking for. + */ + + if (np->nz_value == 0) + /* It's not a definition */ + continue; + + if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) { + /* It's a common, note value and continue search */ + if (common_size < np->nz_value) + common_size = np->nz_value; + continue; + } + + *src_map = lmp; + return np; + } + + if (common_size == 0) + /* Not found */ + return NULL; + + /* + * It's a common, enter into run-time common symbol table. + */ + rtsp = enter_rts(name, (long)calloc(1, common_size), + N_UNDF + N_EXT, 0, common_size); + +#if DEBUG +xprintf("Allocating common: %s size %d at %#x\n", name, common_size, rtsp->rt_sp->nz_value); +#endif + + return rtsp->rt_sp; +} + + +/* + * This routine is called from the jumptable to resolve + * procedure calls to shared objects. + */ +long +binder(jsp) +jmpslot_t *jsp; +{ + struct link_map *lmp, *src_map; + long addr; + char *sym; + struct nzlist *np; + int index; + + /* + * Find the PLT map that contains JSP. + */ + for (lmp = link_map_head; lmp; lmp = lmp->lm_next) { + if (LM_PLT(lmp) < jsp && + jsp < LM_PLT(lmp) + LD_PLTSZ(lmp->lm_ld)/sizeof(*jsp)) + break; + } + + if (lmp == NULL) + fatal("Call to binder from unknown location: %#x\n", jsp); + + index = jsp->reloc_index & JMPSLOT_RELOC_MASK; + + /* Get the local symbol this jmpslot refers to */ + sym = LM_STRINGS(lmp) + + LM_SYMBOL(lmp,RELOC_SYMBOL(&LM_REL(lmp)[index]))->nz_strx; + + np = lookup(sym, &src_map); + if (np == NULL) + fatal("Undefined symbol \"%s\" called from %s at %#x", sym, + lmp->lm_name, jsp); + + /* Fixup jmpslot so future calls transfer directly to target */ + addr = np->nz_value; + if (src_map) + addr += (long)src_map->lm_addr; + + md_fix_jmpslot(jsp, (long)jsp, addr); + +#if DEBUG +xprintf(" BINDER: %s located at = %#x in %s\n", sym, addr, src_map->lm_name); +#endif + return addr; +} + + +/* + * Run-time common symbol table. + */ + +#define RTC_TABSIZE 57 +static struct rt_symbol *rt_symtab[RTC_TABSIZE]; + +/* + * Compute hash value for run-time symbol table + */ +static int +hash_string(key) + char *key; +{ + register char *cp; + register int k; + + cp = key; + k = 0; + while (*cp) + k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; + + return k; +} + +/* + * Lookup KEY in the run-time common symbol table. + */ + +static struct rt_symbol * +lookup_rts(key) + char *key; +{ + register int hashval; + register struct rt_symbol *rtsp; + + /* Determine which bucket. */ + + hashval = hash_string(key) % RTC_TABSIZE; + + /* Search the bucket. */ + + for (rtsp = rt_symtab[hashval]; rtsp; rtsp = rtsp->rt_link) + if (strcmp(key, rtsp->rt_sp->nz_name) == 0) + return rtsp; + + return NULL; +} + +static struct rt_symbol * +enter_rts(name, value, type, srcaddr, size) + char *name; + long value; + int type; + caddr_t srcaddr; + long size; +{ + register int hashval; + register struct rt_symbol *rtsp, **rpp; + + /* Determine which bucket */ + hashval = hash_string(name) % RTC_TABSIZE; + + /* Find end of bucket */ + for (rpp = &rt_symtab[hashval]; *rpp; rpp = &(*rpp)->rt_link) + ; + + /* Allocate new common symbol */ + rtsp = (struct rt_symbol *)malloc(sizeof(struct rt_symbol)); + rtsp->rt_sp = (struct nzlist *)malloc(sizeof(struct nzlist)); + rtsp->rt_sp->nz_name = strdup(name); + rtsp->rt_sp->nz_value = value; + rtsp->rt_sp->nz_type = type; + rtsp->rt_sp->nz_size = size; + rtsp->rt_srcaddr = srcaddr; + rtsp->rt_link = NULL; + + /* Link onto linear list as well */ + rtsp->rt_next = rt_symbol_head; + rt_symbol_head = rtsp; + + *rpp = rtsp; + + return rtsp; +} + +static struct hints_header *hheader; +static struct hints_bucket *hbuckets; +static char *hstrtab; + +#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1) + +static void +maphints() +{ + caddr_t addr; + long msize; + int fd; + + if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) { + hheader = (struct hints_header *)-1; + return; + } + + msize = PAGSIZ; + addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0); + + if (addr == (caddr_t)-1) { + hheader = (struct hints_header *)-1; + return; + } + + hheader = (struct hints_header *)addr; + if (HH_BADMAG(*hheader)) { + munmap(addr, msize); + hheader = (struct hints_header *)-1; + return; + } + + if (hheader->hh_version != LD_HINTS_VERSION_1) { + munmap(addr, msize); + hheader = (struct hints_header *)-1; + return; + } + + if (hheader->hh_ehints > msize) { + if (mmap(addr+msize, hheader->hh_ehints - msize, + PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED, + fd, msize) != (caddr_t)(addr+msize)) { + + munmap((caddr_t)hheader, msize); + hheader = (struct hints_header *)-1; + return; + } + } + close(fd); + + hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab); + hstrtab = (char *)(addr + hheader->hh_strtab); +} + +int +hinthash(cp, vmajor, vminor) +char *cp; +int vmajor, vminor; +{ + int k = 0; + + while (*cp) + k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; + + k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff; + k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff; + + return k; +} + +#undef major +#undef minor + +static char * +findhint(name, major, minor, preferred_path) +char *name; +int major, minor; +char *preferred_path; +{ + struct hints_bucket *bp; + + bp = hbuckets + (hinthash(name, major, minor) % hheader->hh_nbucket); + + while (1) { + /* Sanity check */ + if (bp->hi_namex >= hheader->hh_strtab_sz) { + fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex); + break; + } + if (bp->hi_pathx >= hheader->hh_strtab_sz) { + fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx); + break; + } + + if (strcmp(name, hstrtab + bp->hi_namex) == 0) { + /* It's `name', check version numbers */ + if (bp->hi_major == major && + (bp->hi_ndewey < 2 || bp->hi_minor == minor)) { + if (preferred_path == NULL || + strcmp(preferred_path, + hstrtab + bp->hi_pathx) == 0) { + return hstrtab + bp->hi_pathx; + } + } + } + + if (bp->hi_next == -1) + break; + + /* Move on to next in bucket */ + bp = &hbuckets[bp->hi_next]; + } + + /* No hints available for name */ + return NULL; +} + +static char * +rtfindlib(name, major, minor, usehints) +char *name; +int major, minor; +int *usehints; +{ + char *hint; + char *cp, *ld_path = getenv("LD_LIBRARY_PATH"); + + if (hheader == NULL) + maphints(); + + if (!HINTS_VALID || !(*usehints)) { + *usehints = 0; + return (char *)findshlib(name, &major, &minor); + } + + if (ld_path != NULL) { + /* Prefer paths from LD_LIBRARY_PATH */ + while ((cp = strtok(ld_path, ":")) != NULL) { + + ld_path = NULL; + hint = findhint(name, major, minor, cp); + if (hint) + return hint; + } + } else { + /* No LD_LIBRARY_PATH, check default */ + hint = findhint(name, major, minor, NULL); + if (hint) + return hint; + } + + /* No hints available for name */ + *usehints = 0; + return (char *)findshlib(name, &major, &minor); +} + +static int +dlopen(name, mode) +char *name; +int mode; +{ + xprintf("dlopen(%s, %x)\n", name, mode); + return -1; +} + +static int +dlclose(fd) +int fd; +{ + xprintf("dlclose(%d)\n", fd); + return -1; +} + +static int +dlsym(fd, sym) +int fd; +char *sym; +{ + xprintf("dlsym(%d, %s)\n", fd, sym); + return 0; +} + +/* + * Private heap functions. + */ + +static caddr_t curbrk; + +static void +init_brk() +{ + struct rlimit rlim; + char *cp, **cpp = environ; + + if (getrlimit(RLIMIT_STACK, &rlim) < 0) { + xprintf("ld.so: brk: getrlimit failure\n"); + _exit(1); + } + + /* + * Walk to the top of stack + */ + if (*cpp) { + while (*cpp) cpp++; + cp = *--cpp; + while (*cp) cp++; + } else + cp = (char *)&cp; + + curbrk = (caddr_t) + (((long)(cp - 1 - rlim.rlim_cur) + PAGSIZ) & ~(PAGSIZ - 1)); +} + +void +#if __STDC__ +xprintf(char *fmt, ...) +#else +xprintf(fmt, va_alist) +char *fmt; +#endif +{ + char buf[256]; + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + vsprintf(buf, fmt, ap); + (void)write(1, buf, strlen(buf)); + va_end(ap); +} + +caddr_t +sbrk(incr) +int incr; +{ + int fd = -1; + caddr_t oldbrk; + + if (curbrk == 0) + init_brk(); + +#if DEBUG +xprintf("sbrk: incr = %#x, curbrk = %#x\n", incr, curbrk); +#endif + if (incr == 0) + return curbrk; + + incr = (incr + PAGSIZ - 1) & ~(PAGSIZ - 1); + +#ifdef NEED_DEV_ZERO + fd = open("/dev/zero", O_RDWR, 0); + if (fd == -1) + perror("/dev/zero"); +#endif + + if (mmap(curbrk, incr, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_FIXED|MAP_COPY, fd, 0) == (caddr_t)-1) { + perror("Cannot map anonymous memory"); + } + +#ifdef NEED_DEV_ZERO + close(fd); +#endif + + oldbrk = curbrk; + curbrk += incr; + + return oldbrk; +} diff --git a/libexec/rtld-aout/shlib.c b/libexec/rtld-aout/shlib.c new file mode 100644 index 0000000..4be8354 --- /dev/null +++ b/libexec/rtld-aout/shlib.c @@ -0,0 +1,203 @@ +/* + * $Id: shlib.c,v 1.3 1993/10/23 00:34:26 pk Exp $ + */ + +#include <sys/param.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/time.h> +#include <fcntl.h> +#include <string.h> +#include <dirent.h> +#include <a.out.h> + +#include "ld.h" + +/* + * Standard directories to search for files specified by -l. + */ +#ifndef STANDARD_SEARCH_DIRS +#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/local/lib" +#endif + +char *standard_search_dirs[] = { + STANDARD_SEARCH_DIRS +}; + +int n_search_dirs; + +void +add_search_dir(name) + char *name; +{ + n_search_dirs++; + search_dirs = (char **)xrealloc(search_dirs, + n_search_dirs * sizeof(char *)); + search_dirs[n_search_dirs - 1] = strdup(name); +} + +void +std_search_dirs(paths) +char *paths; +{ + char *cp; + int i, n; + + if (paths != NULL) + /* Add search directories from `paths' */ + while ((cp = strtok(paths, ":")) != NULL) { + paths = NULL; + add_search_dir(cp); + } + + /* Append standard search directories */ + n = sizeof standard_search_dirs / sizeof standard_search_dirs[0]; + for (i = 0; i < n; i++) + add_search_dir(standard_search_dirs[i]); +} + +/* + * Return true if CP points to a valid dewey number. + * Decode and leave the result in the array DEWEY. + * Return the number of decoded entries in DEWEY. + */ + +int +getdewey(dewey, cp) +int dewey[]; +char *cp; +{ + int i, n; + + for (n = 0, i = 0; i < MAXDEWEY; i++) { + if (*cp == '\0') + break; + + if (*cp == '.') cp++; + if (!isdigit(*cp)) + return 0; + + dewey[n++] = strtol(cp, &cp, 10); + } + + return n; +} + +/* + * Compare two dewey arrays. + * Return -1 if `d1' represents a smaller value than `d2'. + * Return 1 if `d1' represents a greater value than `d2'. + * Return 0 if equal. + */ +int +cmpndewey(d1, n1, d2, n2) +int d1[], d2[]; +int n1, n2; +{ + int i; + + for (i = 0; i < n1 && i < n2; i++) { + if (d1[i] < d2[i]) + return -1; + if (d1[i] > d2[i]) + return 1; + } + + if (n1 == n2) + return 0; + + if (i == n1) + return -1; + + if (i == n2) + return 1; +} + +/* + * Search directories for a shared library matching the given + * major and minor version numbers. + * + * MAJOR == -1 && MINOR == -1 --> find highest version + * MAJOR != -1 && MINOR == -1 --> find highest minor version + * MAJOR == -1 && MINOR != -1 --> invalid + * MAJOR != -1 && MINOR != -1 --> find highest micro version + */ + +/* Not interested in devices right now... */ +#undef major +#undef minor + +char * +findshlib(name, majorp, minorp) +char *name; +int *majorp, *minorp; +{ + int dewey[MAXDEWEY]; + int ndewey; + int tmp[MAXDEWEY]; + int i; + int len; + char *lname, *path = NULL; + int major = *majorp, minor = *minorp; + + len = strlen(name); + lname = (char *)alloca(len + sizeof("lib")); + sprintf(lname, "lib%s", name); + len += 3; + + ndewey = 0; + + for (i = 0; i < n_search_dirs; i++) { + DIR *dd = opendir(search_dirs[i]); + struct dirent *dp; + + if (dd == NULL) + continue; + + while ((dp = readdir(dd)) != NULL) { + int n, j, might_take_it = 0; + + if (dp->d_namlen < len + 4) + continue; + if (strncmp(dp->d_name, lname, len) != 0) + continue; + if (strncmp(dp->d_name+len, ".so.", 4) != 0) + continue; + + if ((n = getdewey(tmp, dp->d_name+len+4)) == 0) + continue; + + if (major == -1 && minor == -1) { + might_take_it = 1; + } else if (major != -1 && minor == -1) { + if (tmp[0] == major) + might_take_it = 1; + } else if (major != -1 && minor != -1) { + if (tmp[0] == major) + if (n == 1 || tmp[1] >= minor) + might_take_it = 1; + } + + if (!might_take_it) + continue; + + if (cmpndewey(tmp, n, dewey, ndewey) <= 0) + continue; + + /* We have a better version */ + if (path) + free(path); + path = concat(search_dirs[i], "/", dp->d_name); + bcopy(tmp, dewey, sizeof(dewey)); + ndewey = n; + *majorp = dewey[0]; + *minorp = dewey[1]; + } + closedir(dd); + } + + return path; +} |