diff options
Diffstat (limited to 'gnu/usr.bin/ld/rtld')
| -rw-r--r-- | gnu/usr.bin/ld/rtld/Makefile | 25 | ||||
| -rw-r--r-- | gnu/usr.bin/ld/rtld/malloc.c | 481 | ||||
| -rw-r--r-- | gnu/usr.bin/ld/rtld/md-prologue.c | 39 | ||||
| -rw-r--r-- | gnu/usr.bin/ld/rtld/rtld.c | 1237 | ||||
| -rw-r--r-- | gnu/usr.bin/ld/rtld/sbrk.c | 101 |
5 files changed, 1883 insertions, 0 deletions
diff --git a/gnu/usr.bin/ld/rtld/Makefile b/gnu/usr.bin/ld/rtld/Makefile new file mode 100644 index 000000000000..02a4437c2645 --- /dev/null +++ b/gnu/usr.bin/ld/rtld/Makefile @@ -0,0 +1,25 @@ +# $Id: Makefile,v 1.9 1994/02/13 20:42:48 jkh Exp $ + +PROG= ld.so +SRCS= mdprologue.S rtld.c malloc.c shlib.c etc.c md.c +NOMAN= noman +LDDIR?= $(.CURDIR)/.. +#PICFLAG=-pic +PICFLAG=-fpic +CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) $(PICFLAG) -DRTLD +LDFLAGS+=-Bshareable -Bsymbolic -assert nosymbolic +ASFLAGS+=-k +LDADD+= -lc_pic +BINDIR= /usr/libexec + +.SUFFIXES: .S + +.PATH: $(LDDIR) $(LDDIR)/$(MACHINE) + +$(PROG): + $(LD) -o $(PROG) $(LDFLAGS) $(OBJS) $(LDADD) + +.S.o: + ${CPP} ${.IMPSRC} | ${AS} ${ASFLAGS} -o ${.TARGET} - + +.include <bsd.prog.mk> diff --git a/gnu/usr.bin/ld/rtld/malloc.c b/gnu/usr.bin/ld/rtld/malloc.c new file mode 100644 index 000000000000..4a9e7e65e9b3 --- /dev/null +++ b/gnu/usr.bin/ld/rtld/malloc.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";*/ +static char *rcsid = "$Id: malloc.c,v 1.1 1994/02/13 20:44:09 jkh Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * malloc.c (Caltech) 2/21/82 + * Chris Kingsley, kingsley@cit-20. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks that + * don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long. + * This is designed for use in a virtual memory environment. + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/mman.h> +#ifndef BSD +#define MAP_COPY MAP_PRIVATE +#define MAP_FILE 0 +#define MAP_ANON 0 +#endif + +#ifndef BSD /* Need do better than this */ +#define NEED_DEV_ZERO 1 +#endif + +#define NULL 0 + +static void morecore(); +static int findbucket(); + +/* + * Pre-allocate mmap'ed pages + */ +#define getpagesize() NBPG +#define NPOOLPAGES (32*1024/NBPG) +static caddr_t pagepool_start, pagepool_end; +static int morepages(); + +/* + * The overhead on a block is at least 4 bytes. When free, this space + * contains a pointer to the next free block, and the bottom two bits must + * be zero. When in use, the first byte is set to MAGIC, and the second + * byte is the size index. The remaining bytes are for alignment. + * If range checking is enabled then a second word holds the size of the + * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). + * The order of elements is critical: ov_magic must overlay the low order + * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. + */ +union overhead { + union overhead *ov_next; /* when free */ + struct { + u_char ovu_magic; /* magic number */ + u_char ovu_index; /* bucket # */ +#ifdef RCHECK + u_short ovu_rmagic; /* range magic number */ + u_int ovu_size; /* actual block size */ +#endif + } ovu; +#define ov_magic ovu.ovu_magic +#define ov_index ovu.ovu_index +#define ov_rmagic ovu.ovu_rmagic +#define ov_size ovu.ovu_size +}; + +#define MAGIC 0xef /* magic # on accounting info */ +#define RMAGIC 0x5555 /* magic # on range info */ + +#ifdef RCHECK +#define RSLOP sizeof (u_short) +#else +#define RSLOP 0 +#endif + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information + * precedes the data area returned to the user. + */ +#define NBUCKETS 30 +static union overhead *nextf[NBUCKETS]; +extern char *sbrk(); + +static int pagesz; /* page size */ +static int pagebucket; /* page size bucket */ + +#ifdef MSTATS +/* + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. + */ +static u_int nmalloc[NBUCKETS]; +#include <stdio.h> +#endif + +#if defined(DEBUG) || defined(RCHECK) +#define ASSERT(p) if (!(p)) botch("p") +#include <stdio.h> +static +botch(s) + char *s; +{ + fprintf(stderr, "\r\nassertion botched: %s\r\n", s); + (void) fflush(stderr); /* just in case user buffered it */ + abort(); +} +#else +#define ASSERT(p) +#endif + +void * +malloc(nbytes) + size_t nbytes; +{ + register union overhead *op; + register int bucket, n; + register unsigned amt; + + /* + * First time malloc is called, setup page size and + * align break pointer so all data will be page aligned. + */ + if (pagesz == 0) { + pagesz = n = getpagesize(); + if (morepages(NPOOLPAGES) == 0) + return NULL; + op = (union overhead *)(pagepool_start); + n = n - sizeof (*op) - ((int)op & (n - 1)); + if (n < 0) + n += pagesz; + if (n) { + pagepool_start += n; + } + bucket = 0; + amt = 8; + while (pagesz > amt) { + amt <<= 1; + bucket++; + } + pagebucket = bucket; + } + /* + * Convert amount of memory requested into closest block size + * stored in hash buckets which satisfies request. + * Account for space used per block for accounting. + */ + if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) { +#ifndef RCHECK + amt = 8; /* size of first bucket */ + bucket = 0; +#else + amt = 16; /* size of first bucket */ + bucket = 1; +#endif + n = -(sizeof (*op) + RSLOP); + } else { + amt = pagesz; + bucket = pagebucket; + } + while (nbytes > amt + n) { + amt <<= 1; + if (amt == 0) + return (NULL); + bucket++; + } + /* + * If nothing in hash bucket right now, + * request more memory from the system. + */ + if ((op = nextf[bucket]) == NULL) { + morecore(bucket); + if ((op = nextf[bucket]) == NULL) + return (NULL); + } + /* remove from linked list */ + nextf[bucket] = op->ov_next; + op->ov_magic = MAGIC; + op->ov_index = bucket; +#ifdef MSTATS + nmalloc[bucket]++; +#endif +#ifdef RCHECK + /* + * Record allocated size of block and + * bound space with magic numbers. + */ + op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); + op->ov_rmagic = RMAGIC; + *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; +#endif + return ((char *)(op + 1)); +} + +/* + * Allocate more memory to the indicated bucket. + */ +static void +morecore(bucket) + int bucket; +{ + register union overhead *op; + register int sz; /* size of desired block */ + int amt; /* amount to allocate */ + int nblks; /* how many blocks we get */ + + /* + * sbrk_size <= 0 only for big, FLUFFY, requests (about + * 2^30 bytes on a VAX, I think) or for a negative arg. + */ + sz = 1 << (bucket + 3); +#ifdef DEBUG + ASSERT(sz > 0); +#else + if (sz <= 0) + return; +#endif + if (sz < pagesz) { + amt = pagesz; + nblks = amt / sz; + } else { + amt = sz + pagesz; + nblks = 1; + } + if (amt > pagepool_end - pagepool_start) + if (morepages(amt/pagesz + NPOOLPAGES) == 0) + return; + op = (union overhead *)pagepool_start; + pagepool_start += amt; + + /* + * Add new memory allocated to that on + * free list for this hash bucket. + */ + nextf[bucket] = op; + while (--nblks > 0) { + op->ov_next = (union overhead *)((caddr_t)op + sz); + op = (union overhead *)((caddr_t)op + sz); + } +} + +void +free(cp) + void *cp; +{ + register int size; + register union overhead *op; + + if (cp == NULL) + return; + op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); +#ifdef DEBUG + ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */ +#else + if (op->ov_magic != MAGIC) + return; /* sanity */ +#endif +#ifdef RCHECK + ASSERT(op->ov_rmagic == RMAGIC); + ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC); +#endif + size = op->ov_index; + ASSERT(size < NBUCKETS); + op->ov_next = nextf[size]; /* also clobbers ov_magic */ + nextf[size] = op; +#ifdef MSTATS + nmalloc[size]--; +#endif +} + +/* + * When a program attempts "storage compaction" as mentioned in the + * old malloc man page, it realloc's an already freed block. Usually + * this is the last block it freed; occasionally it might be farther + * back. We have to search all the free lists for the block in order + * to determine its bucket: 1st we make one pass thru the lists + * checking only the first block in each; if that fails we search + * ``realloc_srchlen'' blocks in each list for a match (the variable + * is extern so the caller can modify it). If that fails we just copy + * however many bytes was given to realloc() and hope it's not huge. + */ +int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */ + +void * +realloc(cp, nbytes) + void *cp; + size_t nbytes; +{ + register u_int onb; + register int i; + union overhead *op; + char *res; + int was_alloced = 0; + + if (cp == NULL) + return (malloc(nbytes)); + op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); + if (op->ov_magic == MAGIC) { + was_alloced++; + i = op->ov_index; + } else { + /* + * Already free, doing "compaction". + * + * Search for the old block of memory on the + * free list. First, check the most common + * case (last element free'd), then (this failing) + * the last ``realloc_srchlen'' items free'd. + * If all lookups fail, then assume the size of + * the memory block being realloc'd is the + * largest possible (so that all "nbytes" of new + * memory are copied into). Note that this could cause + * a memory fault if the old area was tiny, and the moon + * is gibbous. However, that is very unlikely. + */ + if ((i = findbucket(op, 1)) < 0 && + (i = findbucket(op, realloc_srchlen)) < 0) + i = NBUCKETS; + } + onb = 1 << (i + 3); + if (onb < pagesz) + onb -= sizeof (*op) + RSLOP; + else + onb += pagesz - sizeof (*op) - RSLOP; + /* avoid the copy if same size block */ + if (was_alloced) { + if (i) { + i = 1 << (i + 2); + if (i < pagesz) + i -= sizeof (*op) + RSLOP; + else + i += pagesz - sizeof (*op) - RSLOP; + } + if (nbytes <= onb && nbytes > i) { +#ifdef RCHECK + op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); + *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; +#endif + return(cp); + } else + free(cp); + } + if ((res = malloc(nbytes)) == NULL) + return (NULL); + if (cp != res) /* common optimization if "compacting" */ + bcopy(cp, res, (nbytes < onb) ? nbytes : onb); + return (res); +} + +/* + * Search ``srchlen'' elements of each free list for a block whose + * header starts at ``freep''. If srchlen is -1 search the whole list. + * Return bucket number, or -1 if not found. + */ +static +findbucket(freep, srchlen) + union overhead *freep; + int srchlen; +{ + register union overhead *p; + register int i, j; + + for (i = 0; i < NBUCKETS; i++) { + j = 0; + for (p = nextf[i]; p && j != srchlen; p = p->ov_next) { + if (p == freep) + return (i); + j++; + } + } + return (-1); +} + +#ifdef MSTATS +/* + * mstats - print out statistics about malloc + * + * Prints two lines of numbers, one showing the length of the free list + * for each size category, the second showing the number of mallocs - + * frees for each size category. + */ +mstats(s) + char *s; +{ + register int i, j; + register union overhead *p; + int totfree = 0, + totused = 0; + + fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s); + for (i = 0; i < NBUCKETS; i++) { + for (j = 0, p = nextf[i]; p; p = p->ov_next, j++) + ; + fprintf(stderr, " %d", j); + totfree += j * (1 << (i + 3)); + } + fprintf(stderr, "\nused:\t"); + for (i = 0; i < NBUCKETS; i++) { + fprintf(stderr, " %d", nmalloc[i]); + totused += nmalloc[i] * (1 << (i + 3)); + } + fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n", + totused, totfree); +} +#endif + + +static int +morepages(n) +int n; +{ + int fd = -1; + int offset; + +#ifdef NEED_DEV_ZERO + fd = open("/dev/zero", O_RDWR, 0); + if (fd == -1) + perror("/dev/zero"); +#endif + + if (pagepool_end - pagepool_start > pagesz) { + caddr_t addr = (caddr_t) + (((int)pagepool_start + pagesz - 1) & ~(pagesz - 1)); + if (munmap(addr, pagepool_end - addr) != 0) + perror("munmap"); + } + + offset = (int)pagepool_start - ((int)pagepool_start & ~(pagesz - 1)); + + if ((pagepool_start = mmap(0, n * pagesz, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) { + xprintf("Cannot map anonymous memory"); + return 0; + } + pagepool_end = pagepool_start + n * pagesz; + pagepool_start += offset; + +#ifdef NEED_DEV_ZERO + close(fd); +#endif + return n; +} diff --git a/gnu/usr.bin/ld/rtld/md-prologue.c b/gnu/usr.bin/ld/rtld/md-prologue.c new file mode 100644 index 000000000000..dae455e02375 --- /dev/null +++ b/gnu/usr.bin/ld/rtld/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/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c new file mode 100644 index 000000000000..8ed0f0683ce3 --- /dev/null +++ b/gnu/usr.bin/ld/rtld/rtld.c @@ -0,0 +1,1237 @@ +/* + * 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 without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: rtld.c,v 1.15 1994/02/13 20:42:53 jkh Exp $ + */ + +#include <machine/vmparam.h> +#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/errno.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 <so_map>->som_spd + */ +struct somap_private { + int spd_version; + struct so_map *spd_parent; + int spd_refcount; + int spd_flags; +#define RTLD_MAIN 1 +#define RTLD_RTLD 2 +#define RTLD_DL 4 + +#ifdef SUN_COMPAT + long spd_offset; /* Correction for Sun main programs */ +#endif +}; + +#define LM_PRIVATE(smp) ((struct somap_private *)(smp)->som_spd) + +#ifdef SUN_COMPAT +#define LM_OFFSET(smp) (LM_PRIVATE(smp)->spd_offset) +#else +#define LM_OFFSET(smp) (0) +#endif + +/* Base address for section_dispatch_table entries */ +#define LM_LDBASE(smp) (smp->som_addr + LM_OFFSET(smp)) + +/* Start of text segment */ +#define LM_TXTADDR(smp) (smp->som_addr == (caddr_t)0 ? PAGSIZ : 0) + +/* Start of run-time relocation_info */ +#define LM_REL(smp) ((struct relocation_info *) \ + (smp->som_addr + LM_OFFSET(smp) + LD_REL((smp)->som_dynamic))) + +/* Start of symbols */ +#define LM_SYMBOL(smp, i) ((struct nzlist *) \ + (smp->som_addr + LM_OFFSET(smp) + LD_SYMBOL((smp)->som_dynamic) + \ + i * (LD_VERSION_NZLIST_P(smp->som_dynamic->d_version) ? \ + sizeof(struct nzlist) : sizeof(struct nlist)))) + +/* Start of hash table */ +#define LM_HASH(smp) ((struct rrs_hash *) \ + ((smp)->som_addr + LM_OFFSET(smp) + LD_HASH((smp)->som_dynamic))) + +/* Start of strings */ +#define LM_STRINGS(smp) ((char *) \ + ((smp)->som_addr + LM_OFFSET(smp) + LD_STRINGS((smp)->som_dynamic))) + +/* End of text */ +#define LM_ETEXT(smp) ((char *) \ + ((smp)->som_addr + LM_TXTADDR(smp) + LD_TEXTSZ((smp)->som_dynamic))) + +/* PLT is in data segment, so don't use LM_OFFSET here */ +#define LM_PLT(smp) ((jmpslot_t *) \ + ((smp)->som_addr + LD_PLT((smp)->som_dynamic))) + +/* Parent of link map */ +#define LM_PARENT(smp) (LM_PRIVATE(smp)->spd_parent) + +char **environ; +int errno; +static uid_t uid, euid; +static gid_t gid, egid; +static int careful; +static char *main_progname = "main"; + +struct so_map *link_map_head, *main_map; +struct so_map **link_map_tail = &link_map_head; +struct rt_symbol *rt_symbol_head; + +static void *dlopen __P((char *, int)); +static int dlclose __P((void *)); +static void *dlsym __P((void *, char *)); +static int dlctl __P((void *, int, void *)); + +static struct ld_entry ld_entry = { + dlopen, dlclose, dlsym, dlctl +}; + + void xprintf __P((char *, ...)); +static void init_brk __P((void)); +static void load_objects __P(( struct crt_ldso *, + struct _dynamic *)); +static struct so_map *map_object __P((struct sod *, struct so_map *)); +static struct so_map *alloc_link_map __P(( char *, struct sod *, + struct so_map *, caddr_t, + struct _dynamic *)); +static void inline check_text_reloc __P(( struct relocation_info *, + struct so_map *, + caddr_t)); +static void reloc_map __P((struct so_map *)); +static void reloc_copy __P((struct so_map *)); +static void init_map __P((struct so_map *, char *)); +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 so_map **, int)); +static inline struct rt_symbol *lookup_rts __P((char *)); +static struct rt_symbol *enter_rts __P((char *, long, int, caddr_t, + long, struct so_map *)); + +static inline int +strcmp (register const char *s1, register const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + return (*(unsigned char *)s1 - *(unsigned char *)--s2); +} + +#include "md-static-funcs.c" + +/* + * Called from assembler stub that has set up crtp (passed from crt0) + * and dp (our __DYNAMIC). + */ +int +rtld(version, crtp, dp) +int version; +struct crt_ldso *crtp; +struct _dynamic *dp; +{ + int n; + int nreloc; /* # of ld.so relocations */ + struct relocation_info *reloc; + char **envp; + struct so_debug *ddp; + struct so_map *smp; + + /* Check version */ + if ( version != CRT_VERSION_BSD_2 && + version != CRT_VERSION_BSD_3 && + version != CRT_VERSION_SUN) + return -1; + + /* Fixup __DYNAMIC structure */ + (long)dp->d_un.d_sdt += crtp->crt_ba; + + /* Divide by hand to avoid possible use of library division routine */ + for ( nreloc = 0, n = LD_RELSZ(dp); + n > 0; + n -= sizeof(struct relocation_info) ) nreloc++; + + + /* Relocate ourselves */ + for ( reloc = (struct relocation_info *)(LD_REL(dp) + 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"; + if (version >= CRT_VERSION_BSD_3) + main_progname = crtp->crt_prog; + + /* 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_objects(crtp, dp); + + /* Relocate all loaded objects according to their RRS segments */ + for (smp = link_map_head; smp; smp = smp->som_next) { + if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + continue; + reloc_map(smp); + } + + /* Copy any relocated initialized data. */ + for (smp = link_map_head; smp; smp = smp->som_next) { + if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + continue; + reloc_copy(smp); + } + + /* Call any object initialization routines. */ + for (smp = link_map_head; smp; smp = smp->som_next) { + if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + continue; + init_map(smp, ".init"); + } + + /* Fill in some field in main's __DYNAMIC structure */ + crtp->crt_dp->d_entry = &ld_entry; + crtp->crt_dp->d_un.d_sdt->sdt_loaded = link_map_head->som_next; + + ddp = crtp->crt_dp->d_debug; + ddp->dd_cc = rt_symbol_head; + if (ddp->dd_in_debugger) { + caddr_t addr = (caddr_t)((long)crtp->crt_bp & (~(PAGSIZ - 1))); + + /* Set breakpoint for the benefit of debuggers */ + if (mprotect(addr, PAGSIZ, + PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + perror("mprotect"), + fatal("Cannot set breakpoint (%s)\n", main_progname); + } + md_set_breakpoint(crtp->crt_bp, &ddp->dd_bpt_shadow); + if (mprotect(addr, PAGSIZ, PROT_READ|PROT_EXEC) == -1) { + perror("mprotect"); + } + + ddp->dd_bpt_addr = crtp->crt_bp; + if (link_map_head) + ddp->dd_sym_loaded = 1; + } + + /* Close our file descriptor */ + (void)close(crtp->crt_ldfd); + return 0; +} + + +static void +load_objects(crtp, dp) +struct crt_ldso *crtp; +struct _dynamic *dp; +{ + struct so_map *smp; + int tracing = (int)getenv("LD_TRACE_LOADED_OBJECTS"); + + /* Handle LD_PRELOAD's here */ + + /* Make an entry for the main program */ + smp = alloc_link_map(main_progname, (struct sod *)0, (struct so_map *)0, + (caddr_t)0, crtp->crt_dp); + LM_PRIVATE(smp)->spd_refcount++; + LM_PRIVATE(smp)->spd_flags |= RTLD_MAIN; + + /* Make an entry for ourselves */ + smp = alloc_link_map("/usr/libexec/ld.so", (struct sod *)0, (struct so_map *)0, + (caddr_t)crtp->crt_ba, dp); + LM_PRIVATE(smp)->spd_refcount++; + LM_PRIVATE(smp)->spd_flags |= RTLD_RTLD; + + for (smp = link_map_head; smp; smp = smp->som_next) { + struct sod *sodp; + long next = 0; + + if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + continue; + + if (smp->som_dynamic) + next = LD_NEED(smp->som_dynamic); + + while (next) { + struct so_map *newmap; + + sodp = (struct sod *)(LM_LDBASE(smp) + next); + if ((newmap = map_object(sodp, smp)) == NULL) { + if (!tracing) { + char *name = (char *) + (sodp->sod_name + LM_LDBASE(smp)); + char *fmt = sodp->sod_library ? + "%s: lib%s.so.%d.%d: %s\n" : + "%s: %s: %s\n"; + fatal(fmt, main_progname, name, + sodp->sod_major, + sodp->sod_minor, + strerror(errno)); + } + newmap = alloc_link_map(NULL, sodp, smp, 0, 0); + } + LM_PRIVATE(newmap)->spd_refcount++; + next = sodp->sod_next; + } + } + + if (! tracing) + return; + + for (smp = link_map_head; smp; smp = smp->som_next) { + struct sod *sodp; + char *name, *path; + + if ((sodp = smp->som_sod) == NULL) + continue; + name = sodp->sod_name + LM_LDBASE(LM_PARENT(smp)); + + if ((path = smp->som_path) == NULL) + path = "not found"; + + if (sodp->sod_library) + printf("\t-l%s.%d => %s (%#x)\n", name, + sodp->sod_major, path, smp->som_addr); + else + printf("\t%s => %s (%#x)\n", name, path, smp->som_addr); + } + + 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 struct so_map * +alloc_link_map(path, sodp, parent, addr, dp) + char *path; + struct sod *sodp; + struct so_map *parent; + caddr_t addr; + struct _dynamic *dp; +{ + struct so_map *smp; + struct somap_private *smpp; + + smpp = (struct somap_private *)xmalloc(sizeof(struct somap_private)); + smp = (struct so_map *)xmalloc(sizeof(struct so_map)); + smp->som_next = NULL; + *link_map_tail = smp; + link_map_tail = &smp->som_next; + + smp->som_addr = addr; + smp->som_path = path; + smp->som_sod = sodp; + smp->som_dynamic = dp; + smp->som_spd = (caddr_t)smpp; + +/*XXX*/ if (addr == 0) main_map = smp; + + smpp->spd_refcount = 0; + smpp->spd_flags = 0; + smpp->spd_parent = parent; + +#ifdef SUN_COMPAT + smpp->spd_offset = + (addr==0 && dp && dp->d_version==LD_VERSION_SUN) ? PAGSIZ : 0; +#endif + return smp; +} + +/* + * Map object identified by link object LOP which was found + * in link map LMP. + */ + static struct so_map * +map_object(sodp, smp) + struct sod *sodp; + struct so_map *smp; +{ + struct _dynamic *dp; + char *path, *name = (char *)(sodp->sod_name + LM_LDBASE(smp)); + int fd; + caddr_t addr; + struct exec hdr; + int usehints = 0; + struct so_map *p; + + if (sodp->sod_library) { + usehints = 1; +again: + path = rtfindlib(name, sodp->sod_major, + sodp->sod_minor, &usehints); + if (path == NULL) { + errno = ENOENT; + return NULL; + } + } else { + if (careful && *name != '/') { + errno = EACCES; + return NULL; + } + path = name; + } + + /* Check if already loaded */ + for (p = link_map_head; p; p = p->som_next) + if (p->som_path && strcmp(p->som_path, path) == 0) + break; + + if (p != NULL) + return p; + + if ((fd = open(path, O_RDONLY, 0)) == -1) { + if (usehints) { + usehints = 0; + goto again; + } + return NULL; + } + + if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + (void)close(fd); + /*errno = x;*/ + return NULL; + } + + if (N_BADMAG(hdr)) { + (void)close(fd); + errno = EFTYPE; + return NULL; + } + + if ((addr = mmap(0, hdr.a_text + hdr.a_data, + PROT_READ|PROT_EXEC, + MAP_FILE|MAP_COPY, fd, 0)) == (caddr_t)-1) { + (void)close(fd); + return NULL; + } + + 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) { + (void)close(fd); + return NULL; + } + + (void)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) + return NULL; + +#ifdef NEED_DEV_ZERO + close(fd); +#endif + + /* Assume _DYNAMIC is the first data item */ + dp = (struct _dynamic *)(addr+hdr.a_text); + + /* Fixup __DYNAMIC structure */ + (long)dp->d_un.d_sdt += (long)addr; + + return alloc_link_map(path, sodp, smp, addr, dp); +} + +static void inline +check_text_reloc(r, smp, addr) +struct relocation_info *r; +struct so_map *smp; +caddr_t addr; +{ + char *sym; + + if (addr >= LM_ETEXT(smp)) + return; + + if (RELOC_EXTERN_P(r)) + sym = LM_STRINGS(smp) + + LM_SYMBOL(smp, RELOC_SYMBOL(r))->nz_strx; + else + sym = ""; + + if (getenv("LD_WARN_NON_PURE_CODE") != NULL) + fprintf(stderr, + "ld.so: warning: non pure code in %s at %x (%s)\n", + smp->som_path, r->r_address, sym); + + if (smp->som_write == 0 && + mprotect(smp->som_addr + LM_TXTADDR(smp), + LD_TEXTSZ(smp->som_dynamic), + PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + + perror("mprotect"), + fatal("Cannot enable writes to %s:%s\n", + main_progname, smp->som_path); + } + + smp->som_write = 1; +} + +static void +reloc_map(smp) + struct so_map *smp; +{ + struct _dynamic *dp = smp->som_dynamic; + struct relocation_info *r = LM_REL(smp); + struct relocation_info *rend = r + LD_RELSZ(dp)/sizeof(*r); + long symbolbase = (long)LM_SYMBOL(smp, 0); + char *stringbase = LM_STRINGS(smp); + int symsize = LD_VERSION_NZLIST_P(dp->d_version) ? + sizeof(struct nzlist) : + sizeof(struct nlist); + + if (LD_PLTSZ(dp)) + md_fix_jmpslot(LM_PLT(smp), + (long)LM_PLT(smp), (long)binder_entry); + + for (; r < rend; r++) { + char *sym; + caddr_t addr = smp->som_addr + r->r_address; + + check_text_reloc(r, smp, addr); + + if (RELOC_EXTERN_P(r)) { + struct so_map *src_map = NULL; + struct nzlist *p, *np; + long relocation = md_get_addend(r, addr); + + if (RELOC_LAZY_P(r)) + continue; + + p = (struct nzlist *) + (symbolbase + symsize * RELOC_SYMBOL(r)); + + if (p->nz_type == (N_SETV + N_EXT)) + src_map = smp; + + sym = stringbase + p->nz_strx; + + np = lookup(sym, &src_map, 0/*XXX-jumpslots!*/); + if (np == NULL) + fatal("Undefined symbol \"%s\" in %s:%s\n", + sym, main_progname, smp->som_path); + + /* + * 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->som_addr; + + if (RELOC_PCREL_P(r)) + relocation -= (long)smp->som_addr; + + if (RELOC_COPY_P(r) && src_map) { + (void)enter_rts(sym, + (long)addr, + N_DATA + N_EXT, + src_map->som_addr + np->nz_value, + np->nz_size, src_map); + continue; + } + md_relocate(r, relocation, addr, 0); + + } else { + md_relocate(r, +#ifdef SUN_COMPAT + md_get_rt_segment_addend(r, addr) +#else + md_get_addend(r, addr) +#endif + + (long)smp->som_addr, addr, 0); + } + + } + + if (smp->som_write) { + if (mprotect(smp->som_addr + LM_TXTADDR(smp), + LD_TEXTSZ(smp->som_dynamic), + PROT_READ|PROT_EXEC) == -1) { + + perror("mprotect"), + fatal("Cannot disable writes to %s:%s\n", + main_progname, smp->som_path); + } + smp->som_write = 0; + } +} + +static void +reloc_copy(smp) + struct so_map *smp; +{ + struct rt_symbol *rtsp; + + for (rtsp = rt_symbol_head; rtsp; rtsp = rtsp->rt_next) + if ((rtsp->rt_smp == NULL || rtsp->rt_smp == smp) && + rtsp->rt_sp->nz_type == N_DATA + N_EXT) { + bcopy(rtsp->rt_srcaddr, (caddr_t)rtsp->rt_sp->nz_value, + rtsp->rt_sp->nz_size); + } +} + +static void +init_map(smp, sym) + struct so_map *smp; + char *sym; +{ + struct so_map *src_map = smp; + struct nzlist *np; + + np = lookup(sym, &src_map, 1); + if (np) + (*(void (*)())(src_map->som_addr + np->nz_value))(); +} + +/* + * 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 inline +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 inline 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, smp) + char *name; + long value; + int type; + caddr_t srcaddr; + long size; + struct so_map *smp; +{ + 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_smp = smp; + rtsp->rt_link = NULL; + + /* Link onto linear list as well */ + rtsp->rt_next = rt_symbol_head; + rt_symbol_head = rtsp; + + *rpp = rtsp; + + return rtsp; +} + + +/* + * Lookup NAME in the link maps. The link map producing a definition + * is returned in SRC_MAP. If SRC_MAP is not NULL on entry the search is + * confined to that map. If STRONG is set, the symbol returned must + * have a proper type (used by binder()). + */ + static struct nzlist * +lookup(name, src_map, strong) + char *name; + struct so_map **src_map; /* IN/OUT */ + int strong; +{ + long common_size = 0; + struct so_map *smp; + struct rt_symbol *rtsp; + + if ((rtsp = lookup_rts(name)) != NULL) + return rtsp->rt_sp; + + /* + * Search all maps for a definition of NAME + */ + for (smp = link_map_head; smp; smp = smp->som_next) { + int buckets = LD_BUCKETS(smp->som_dynamic); + long hashval = 0; + struct rrs_hash *hp; + char *cp; + struct nzlist *np; + + /* Some local caching */ + long symbolbase; + struct rrs_hash *hashbase; + char *stringbase; + int symsize; + + if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + continue; + + if (*src_map && smp != *src_map) + continue; + + /* + * Compute bucket in which the symbol might be found. + */ + for (cp = name; *cp; cp++) + hashval = (hashval << 1) + *cp; + + hashval = (hashval & 0x7fffffff) % buckets; + + hashbase = LM_HASH(smp); + hp = hashbase + hashval; + if (hp->rh_symbolnum == -1) + /* Nothing in this bucket */ + continue; + + symbolbase = (long)LM_SYMBOL(smp, 0); + stringbase = LM_STRINGS(smp); + symsize = LD_VERSION_NZLIST_P(smp->som_dynamic->d_version)? + sizeof(struct nzlist) : + sizeof(struct nlist); + while (hp) { + np = (struct nzlist *) + (symbolbase + hp->rh_symbolnum * symsize); + cp = stringbase + np->nz_strx; + if (strcmp(cp, name) == 0) + break; + if (hp->rh_next == 0) + hp = NULL; + else + hp = hashbase + 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) { + if (np->nz_other == AUX_FUNC) { + /* It's a weak function definition */ + if (strong) + continue; + } else { + /* It's a common, note value and continue search */ + if (common_size < np->nz_value) + common_size = np->nz_value; + continue; + } + } + + *src_map = smp; + 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, NULL); + +#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 so_map *smp, *src_map = NULL; + long addr; + char *sym; + struct nzlist *np; + int index; + + /* + * Find the PLT map that contains JSP. + */ + for (smp = link_map_head; smp; smp = smp->som_next) { + if (LM_PLT(smp) < jsp && + jsp < LM_PLT(smp) + LD_PLTSZ(smp->som_dynamic)/sizeof(*jsp)) + break; + } + + if (smp == 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(smp) + + LM_SYMBOL(smp,RELOC_SYMBOL(&LM_REL(smp)[index]))->nz_strx; + + np = lookup(sym, &src_map, 1); + if (np == NULL) + fatal("Undefined symbol \"%s\" called from %s:%s at %#x", + sym, main_progname, smp->som_path, jsp); + + /* Fixup jmpslot so future calls transfer directly to target */ + addr = np->nz_value; + if (src_map) + addr += (long)src_map->som_addr; + + md_fix_jmpslot(jsp, (long)jsp, addr); + +#if DEBUG +xprintf(" BINDER: %s located at = %#x in %s\n", sym, addr, src_map->som_path); +#endif + return addr; +} + + +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, 0); + } + + if (ld_path != NULL) { + /* Prefer paths from LD_LIBRARY_PATH */ + while ((cp = strsep(&ld_path, ":")) != NULL) { + + hint = findhint(name, major, minor, cp); + if (ld_path) + *(ld_path-1) = ':'; + 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, 0); +} + +static struct somap_private dlmap_private = { + 0, + (struct so_map *)0, + 0, +#ifdef SUN_COMPAT + 0, +#endif +}; + +static struct so_map dlmap = { + (caddr_t)0, + "internal", + (struct so_map *)0, + (struct sod *)0, + (caddr_t)0, + (u_int)0, + (struct _dynamic *)0, + (caddr_t)&dlmap_private +}; +static int dlerrno; + + static void * +dlopen(name, mode) + char *name; + int mode; +{ + struct sod *sodp; + struct so_map *smp; + + /* + * A NULL argument returns the current set of mapped objects. + */ + if (name == NULL) + return link_map_head; + + if ((sodp = (struct sod *)malloc(sizeof(struct sod))) == NULL) { + dlerrno = ENOMEM; + return NULL; + } + + sodp->sod_name = (long)name; + sodp->sod_library = 0; + sodp->sod_major = sodp->sod_minor = 0; + + if ((smp = map_object(sodp, &dlmap)) == NULL) { +#ifdef DEBUG +xprintf("%s: %s\n", name, strerror(errno)); +#endif + dlerrno = errno; + return NULL; + } + if (LM_PRIVATE(smp)->spd_refcount++ == 0) { + LM_PRIVATE(smp)->spd_flags |= RTLD_DL; + reloc_map(smp); + reloc_copy(smp); + init_map(smp, ".init"); + init_map(smp, "_init"); + } + + return smp; +} + + static int +dlclose(fd) + void *fd; +{ + struct so_map *smp = (struct so_map *)fd; + +#ifdef DEBUG +xprintf("dlclose(%s): refcount = %d\n", smp->som_path, LM_PRIVATE(smp)->spd_refcount); +#endif + if (--LM_PRIVATE(smp)->spd_refcount != 0) + return 0; + + /* Dismantle shared object map and descriptor */ + init_map(smp, "_fini"); +#if 0 + unmap_object(smp); + free(smp->som_sod); + free(smp); +#endif + + return 0; +} + + static void * +dlsym(fd, sym) + void *fd; + char *sym; +{ + struct so_map *smp = (struct so_map *)fd, *src_map = NULL; + struct nzlist *np; + long addr; + + /* + * Restrict search to passed map if dlopen()ed. + */ + if (LM_PRIVATE(smp)->spd_flags & RTLD_DL) + src_map = smp; + + np = lookup(sym, &src_map, 1); + if (np == NULL) + return NULL; + + /* Fixup jmpslot so future calls transfer directly to target */ + addr = np->nz_value; + if (src_map) + addr += (long)src_map->som_addr; + + return (void *)addr; +} + + static int +dlctl(fd, cmd, arg) + void *fd, *arg; + int cmd; +{ + switch (cmd) { + case DL_GETERRNO: + *(int *)arg = dlerrno; + return 0; + default: + dlerrno = EOPNOTSUPP; + return -1; + } + return 0; +} + +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); +} + diff --git a/gnu/usr.bin/ld/rtld/sbrk.c b/gnu/usr.bin/ld/rtld/sbrk.c new file mode 100644 index 000000000000..aee02e065e02 --- /dev/null +++ b/gnu/usr.bin/ld/rtld/sbrk.c @@ -0,0 +1,101 @@ +/* + * 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: sbrk.c,v 1.1 1993/12/11 21:06:36 jkh Exp $ + */ + +#include <machine/vmparam.h> +#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 + +caddr_t +sbrk(incr) +int incr; +{ + int fd = -1; + caddr_t curbrk; + + /* Round-up increment to page size */ + incr = ((incr + PAGSIZ - 1) & ~(PAGSIZ - 1)); + +#if DEBUG +xprintf("sbrk: incr = %#x\n", incr); +#endif + +#ifdef NEED_DEV_ZERO + fd = open("/dev/zero", O_RDWR, 0); + if (fd == -1) + perror("/dev/zero"); +#endif + + if ((curbrk = mmap(0, incr, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) { + xprintf("Cannot map anonymous memory"); + _exit(1); + } + +#ifdef DEBUG +xprintf("sbrk: curbrk = %#x\n", curbrk); +#endif + +#ifdef NEED_DEV_ZERO + close(fd); +#endif + + return(curbrk); +} + |
