summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-aout
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/rtld-aout')
-rw-r--r--libexec/rtld-aout/Makefile20
-rw-r--r--libexec/rtld-aout/dynamic.h380
-rw-r--r--libexec/rtld-aout/i386/md-static-funcs.c17
-rw-r--r--libexec/rtld-aout/i386/md.c384
-rw-r--r--libexec/rtld-aout/i386/md.h245
-rw-r--r--libexec/rtld-aout/i386/mdprologue.S93
-rw-r--r--libexec/rtld-aout/md-prologue.c39
-rw-r--r--libexec/rtld-aout/rtld.1224
-rw-r--r--libexec/rtld-aout/rtld.1aout224
-rw-r--r--libexec/rtld-aout/rtld.c2120
-rw-r--r--libexec/rtld-aout/shlib.c342
-rw-r--r--libexec/rtld-aout/shlib.h43
-rw-r--r--libexec/rtld-aout/support.c86
-rw-r--r--libexec/rtld-aout/support.h35
14 files changed, 4252 insertions, 0 deletions
diff --git a/libexec/rtld-aout/Makefile b/libexec/rtld-aout/Makefile
new file mode 100644
index 0000000..4177f6b
--- /dev/null
+++ b/libexec/rtld-aout/Makefile
@@ -0,0 +1,20 @@
+# $Id: Makefile,v 1.23 1997/02/22 15:46:46 peter Exp $
+
+PROG= ld.so
+SRCS= mdprologue.S rtld.c malloc.c shlib.c md.c support.c sbrk.c
+MAN1= rtld.1
+LDDIR?= $(.CURDIR)/..
+# As there is relocation going on behind GCC's back, don't cache function addresses.
+PICFLAG=-fpic -fno-function-cse
+CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE) $(PICFLAG) -DRTLD
+LDFLAGS+=-nostdlib -Wl,-Bshareable -Wl,-Bsymbolic -Wl,-assert -Wl,nosymbolic
+ASFLAGS+=-k
+DPADD+= ${LIBC:S/c.a/c_pic.a/} ${LIBC:S/c.a/gcc_pic.a/}
+LDADD+= -lc_pic -lgcc_pic
+BINDIR= /usr/libexec
+INSTALLFLAGS+= -fschg -C # -C to install as atomically as possible
+MLINKS= rtld.1 ld.so.1
+
+.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
+
+.include <bsd.prog.mk>
diff --git a/libexec/rtld-aout/dynamic.h b/libexec/rtld-aout/dynamic.h
new file mode 100644
index 0000000..c1890db
--- /dev/null
+++ b/libexec/rtld-aout/dynamic.h
@@ -0,0 +1,380 @@
+/*
+ * 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: dynamic.h,v 1.3 1997/02/22 15:46:18 peter Exp $
+ */
+
+#ifndef __DYNAMIC_H__
+#define __DYNAMIC_H__
+
+#define SUN_COMPAT
+
+#include "md.h"
+#include "link.h"
+
+#ifndef RELOC_JMPTAB_P
+
+#define RELOC_JMPTAB_P(r) ((r)->r_jmptable)
+#define RELOC_BASEREL_P(r) ((r)->r_baserel)
+#define RELOC_RELATIVE_P(r) ((r)->r_relative)
+#define RELOC_COPY_P(r) ((r)->r_copy)
+#define RELOC_LAZY_P(r) ((r)->r_jmptable)
+
+#define CHECK_GOT_RELOC(r) ((r)->r_pcrel)
+#define RELOC_PIC_TYPE(r) ((r)->r_baserel? \
+ PIC_TYPE_LARGE:PIC_TYPE_NONE)
+#endif
+
+#ifndef RELOC_INIT_SEGMENT_RELOC
+#define RELOC_INIT_SEGMENT_RELOC(r)
+#endif
+
+#ifndef MAX_GOTOFF
+#define MAX_GOTOFF(x) (LONG_MAX)
+#endif
+
+#ifndef MIN_GOTOFF
+#define MIN_GOTOFF(x) (LONG_MIN)
+#endif
+
+/*
+ * Internal representation of relocation types
+ */
+#define RELTYPE_EXTERN 1
+#define RELTYPE_JMPSLOT 2
+#define RELTYPE_BASEREL 4
+#define RELTYPE_RELATIVE 8
+#define RELTYPE_COPY 16
+
+#define N_ISWEAK(p) (N_BIND(p) & BIND_WEAK)
+
+typedef struct localsymbol {
+ struct nzlist nzlist; /* n[z]list from file */
+ struct glosym *symbol; /* Corresponding global symbol,
+ if any */
+ struct localsymbol *next; /* List of definitions */
+ struct file_entry *entry; /* Backpointer to file */
+ long gotslot_offset; /* Position in GOT, if any */
+ int symbolnum; /* Position in output nlist */
+ int flags;
+#define LS_L_SYMBOL 1 /* Local symbol starts with an `L' */
+#define LS_WRITE 2 /* Symbol goes in output symtable */
+#define LS_RENAME 4 /* xlat name to `<file>.<name>' */
+#define LS_HASGOTSLOT 8 /* This symbol has a GOT entry */
+#define LS_WARNING 16 /* Second part of a N_WARNING duo */
+} localsymbol_t;
+
+/*
+ * Global symbol data is recorded in these structures, one for each global
+ * symbol. They are found via hashing in 'symtab', which points to a vector
+ * of buckets. Each bucket is a chain of these structures through the link
+ * field.
+ *
+ * Rewritten version to support extra info for dynamic linking.
+ */
+
+struct glosym {
+ struct glosym *link; /* Next symbol hash bucket. */
+ char *name; /* Name of this symbol. */
+ long value; /* Value of this symbol */
+ localsymbol_t *refs; /* Chain of local symbols from object
+ files pertaining to this global
+ symbol */
+ localsymbol_t *sorefs;/* Same for local symbols from shared
+ object files. */
+
+ char *warning; /* message, from N_WARNING nlists */
+ int common_size; /* Common size */
+ int symbolnum; /* Symbol index in output symbol table */
+ int rrs_symbolnum; /* Symbol index in RRS symbol table */
+
+ localsymbol_t *def_lsp; /* The local symbol that gave this
+ global symbol its definition */
+
+ char defined; /* Definition of this symbol */
+ char so_defined; /* Definition of this symbol in a shared
+ object. These go into the RRS symbol table */
+ u_char undef_refs; /* Count of number of "undefined"
+ messages printed for this symbol */
+ u_char mult_defs; /* Same for "multiply defined" symbols */
+ struct glosym *alias; /* For symbols of type N_INDR, this
+ points at the real symbol. */
+ int setv_count; /* Number of elements in N_SETV symbols */
+ int size; /* Size of this symbol (either from N_SIZE
+ symbols or a from shared object's RRS */
+ int aux; /* Auxiliary type information conveyed in
+ the `n_other' field of nlists */
+
+ /* The offset into one of the RRS tables, -1 if not used */
+ long jmpslot_offset;
+ long gotslot_offset;
+
+ long flags;
+
+#define GS_DEFINED 0x1 /* Symbol has definition (notyetused)*/
+#define GS_REFERENCED 0x2 /* Symbol is referred to by something
+ interesting */
+#define GS_TRACE 0x4 /* Symbol will be traced */
+#define GS_HASJMPSLOT 0x8 /* */
+#define GS_HASGOTSLOT 0x10 /* Some state bits concerning */
+#define GS_CPYRELOCRESERVED 0x20 /* entries in GOT and PLT tables */
+#define GS_CPYRELOCCLAIMED 0x40 /* */
+#define GS_WEAK 0x80 /* Symbol is weakly defined */
+
+};
+#ifndef __symbol_defined__
+#define __symbol_defined__
+typedef struct glosym symbol;
+#endif
+
+/* The symbol hash table: a vector of SYMTABSIZE pointers to struct glosym. */
+extern symbol *symtab[];
+#define FOR_EACH_SYMBOL(i,sp) { \
+ int i; \
+ for (i = 0; i < SYMTABSIZE; i++) { \
+ register symbol *sp; \
+ for (sp = symtab[i]; sp; sp = sp->link)
+
+#define END_EACH_SYMBOL }}
+
+extern symbol *got_symbol; /* the symbol __GLOBAL_OFFSET_TABLE_ */
+extern symbol *dynamic_symbol; /* the symbol __DYNAMIC */
+
+/*
+ * Each input file, and each library member ("subfile") being loaded, has a
+ * `file_entry' structure for it.
+ *
+ * For files specified by command args, these are contained in the vector which
+ * `file_table' points to.
+ *
+ * For library members, they are dynamically allocated, and chained through the
+ * `chain' field. The chain is found in the `subfiles' field of the
+ * `file_entry'. The `file_entry' objects for the members have `superfile'
+ * fields pointing to the one for the library.
+ *
+ * Rewritten version to support extra info for dynamic linking.
+ */
+
+struct file_entry {
+ char *filename; /* Name of this file. */
+ /*
+ * Name to use for the symbol giving address of text start Usually
+ * the same as filename, but for a file spec'd with -l this is the -l
+ * switch itself rather than the filename.
+ */
+ char *local_sym_name;
+ struct exec header; /* The file's a.out header. */
+ localsymbol_t *symbols; /* Symbol table of the file. */
+ int nsymbols; /* Number of symbols in above array. */
+ int string_size; /* Size in bytes of string table. */
+ char *strings; /* Pointer to the string table when
+ in core, NULL otherwise */
+ int strings_offset; /* Offset of string table,
+ (normally N_STROFF() + 4) */
+ /*
+ * Next two used only if `relocatable_output' or if needed for
+ * output of undefined reference line numbers.
+ */
+ struct relocation_info *textrel; /* Text relocations */
+ int ntextrel; /* # of text relocations */
+ struct relocation_info *datarel; /* Data relocations */
+ int ndatarel; /* # of data relocations */
+
+ /*
+ * Relation of this file's segments to the output file.
+ */
+ int text_start_address; /* Start of this file's text segment
+ in the output file core image. */
+ int data_start_address; /* Start of this file's data segment
+ in the output file core image. */
+ int bss_start_address; /* Start of this file's bss segment
+ in the output file core image. */
+ struct file_entry *subfiles; /* For a library, points to chain of
+ entries for the library members. */
+ struct file_entry *superfile; /* For library member, points to the
+ library's own entry. */
+ struct file_entry *chain; /* For library member, points to next
+ entry for next member. */
+ int starting_offset; /* For a library member, offset of the
+ member within the archive. Zero for
+ files that are not library members.*/
+ int total_size; /* Size of contents of this file,
+ if library member. */
+#ifdef SUN_COMPAT
+ struct file_entry *silly_archive;/* For shared libraries which have
+ a .sa companion */
+#endif
+ int lib_major, lib_minor; /* Version numbers of a shared object */
+
+ int flags;
+#define E_IS_LIBRARY 1 /* File is a an archive */
+#define E_HEADER_VALID 2 /* File's header has been read */
+#define E_SEARCH_DIRS 4 /* Search directories for file */
+#define E_SEARCH_DYNAMIC 8 /* Search for shared libs allowed */
+#define E_JUST_SYMS 0x10 /* File is used for incremental load */
+#define E_DYNAMIC 0x20 /* File is a shared object */
+#define E_SCRAPPED 0x40 /* Ignore this file */
+#define E_SYMBOLS_USED 0x80 /* Symbols from this entry were used */
+#define E_SECONDCLASS 0x100 /* Shared object is a subsidiary */
+};
+
+/*
+ * Runtime Relocation Section (RRS).
+ * This describes the data structures that go into the output text and data
+ * segments to support the run-time linker. The RRS can be empty (plain old
+ * static linking), or can just exist of GOT and PLT entries (in case of
+ * statically linked PIC code).
+ */
+extern int rrs_section_type; /* What's in the RRS section */
+#define RRS_NONE 0
+#define RRS_PARTIAL 1
+#define RRS_FULL 2
+extern int rrs_text_size; /* Size of RRS text additions */
+extern int rrs_text_start; /* Location of above */
+extern int rrs_data_size; /* Size of RRS data additions */
+extern int rrs_data_start; /* Location of above */
+extern char *rrs_search_paths; /* `-L' RT paths */
+
+/* Version number to put in __DYNAMIC (set by -V) */
+extern int soversion;
+#ifndef DEFAULT_SOVERSION
+#define DEFAULT_SOVERSION LD_VERSION_BSD
+#endif
+
+extern int pc_relocation; /* Current PC reloc value */
+
+extern int number_of_shobjs; /* # of shared objects linked in */
+
+/* Current link mode */
+extern int link_mode;
+#define DYNAMIC 1 /* Consider shared libraries */
+#define SYMBOLIC 2 /* Force symbolic resolution */
+#define FORCEARCHIVE 4 /* Force inclusion of all members
+ of archives */
+#define SHAREABLE 8 /* Build a shared object */
+#define SILLYARCHIVE 16 /* Process .sa companions, if any */
+#define FORCEDYNAMIC 32 /* Force dynamic output even if no
+ shared libraries included */
+#define WARNRRSTEXT 64 /* Warn about rrs in text */
+
+extern FILE *outstream; /* Output file. */
+extern struct exec outheader; /* Output file header. */
+extern int magic; /* Output file magic. */
+extern int oldmagic;
+extern int relocatable_output;
+extern int pic_type;
+#define PIC_TYPE_NONE 0
+#define PIC_TYPE_SMALL 1
+#define PIC_TYPE_LARGE 2
+
+void read_header __P((int, struct file_entry *));
+void read_entry_symbols __P((int, struct file_entry *));
+void read_entry_strings __P((int, struct file_entry *));
+void read_entry_relocation __P((int, struct file_entry *));
+void enter_file_symbols __P((struct file_entry *));
+void read_file_symbols __P((struct file_entry *));
+int set_element_prefixed_p __P((char *));
+int text_offset __P((struct file_entry *));
+int file_open __P((struct file_entry *));
+void each_file __P((void (*)(), void *));
+void each_full_file __P((void (*)(), void *));
+unsigned long check_each_file __P((unsigned long (*)(), void *));
+void mywrite __P((void *, int, int, FILE *));
+void padfile __P((int, FILE *));
+
+/* In warnings.c: */
+void perror_name __P((char *));
+void perror_file __P((struct file_entry *));
+void print_symbols __P((FILE *));
+char *get_file_name __P((struct file_entry *));
+void print_file_name __P((struct file_entry *, FILE *));
+void prline_file_name __P((struct file_entry *, FILE *));
+int do_warnings __P((FILE *));
+
+/* In etc.c: */
+#include "support.h"
+
+/* In symbol.c: */
+void symtab_init __P((int));
+symbol *getsym __P((char *)), *getsym_soft __P((char *));
+
+/* In lib.c: */
+void search_library __P((int, struct file_entry *));
+void read_shared_object __P((int, struct file_entry *));
+int findlib __P((struct file_entry *));
+
+/* In shlib.c: */
+#include "shlib.h"
+
+/* In rrs.c: */
+void init_rrs __P((void));
+int rrs_add_shobj __P((struct file_entry *));
+void alloc_rrs_reloc __P((struct file_entry *, symbol *));
+void alloc_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
+void alloc_rrs_jmpslot __P((struct file_entry *, symbol *));
+void alloc_rrs_gotslot __P((struct file_entry *, struct relocation_info *, localsymbol_t *));
+void alloc_rrs_cpy_reloc __P((struct file_entry *, symbol *));
+
+int claim_rrs_reloc __P((struct file_entry *, struct relocation_info *, symbol *, long *));
+long claim_rrs_jmpslot __P((struct file_entry *, struct relocation_info *, symbol *, long));
+long claim_rrs_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
+long claim_rrs_internal_gotslot __P((struct file_entry *, struct relocation_info *, struct localsymbol *, long));
+void claim_rrs_cpy_reloc __P((struct file_entry *, struct relocation_info *, symbol *));
+void claim_rrs_segment_reloc __P((struct file_entry *, struct relocation_info *));
+void consider_rrs_section_lengths __P((void));
+void relocate_rrs_addresses __P((void));
+void write_rrs __P((void));
+
+/* In <md>.c */
+void md_init_header __P((struct exec *, int, int));
+long md_get_addend __P((struct relocation_info *, unsigned char *));
+void md_relocate __P((struct relocation_info *, long, unsigned char *, int));
+void md_make_jmpslot __P((jmpslot_t *, long, long));
+void md_fix_jmpslot __P((jmpslot_t *, long, u_long));
+int md_make_reloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_jmpreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_gotreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_copyreloc __P((struct relocation_info *, struct relocation_info *));
+void md_set_breakpoint __P((long, long *));
+
+#ifdef NEED_SWAP
+/* In xbits.c: */
+void swap_longs __P((long *, int));
+void swap_symbols __P((struct nlist *, int));
+void swap_zsymbols __P((struct nzlist *, int));
+void swap_ranlib_hdr __P((struct ranlib *, int));
+void swap__dynamic __P((struct link_dynamic *));
+void swap_section_dispatch_table __P((struct section_dispatch_table *));
+void swap_so_debug __P((struct so_debug *));
+void swapin_sod __P((struct sod *, int));
+void swapout_sod __P((struct sod *, int));
+void swapout_fshash __P((struct fshash *, int));
+#endif
+
+#endif /* __DYNAMIC_H__ */
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..758a4b2
--- /dev/null
+++ b/libexec/rtld-aout/i386/md-static-funcs.c
@@ -0,0 +1,17 @@
+/*
+ * $Id$
+ *
+ * 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..8e945e8
--- /dev/null
+++ b/libexec/rtld-aout/i386/md.c
@@ -0,0 +1,384 @@
+/*
+ * 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$
+ */
+
+#include <sys/param.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <err.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+
+#include "dynamic.h"
+
+#if defined(RTLD) && defined(SUN_COMPAT)
+#define REL_SIZE(r) (2) /* !!!!! Sun BUG compatible */
+#else
+#define REL_SIZE(r) ((r)->r_length)
+#endif
+
+/*
+ * 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 (REL_SIZE(rp)) {
+ case 0:
+ return get_byte(addr);
+ case 1:
+ return get_short(addr);
+ case 2:
+ return get_long(addr);
+ default:
+ errx(1, "Unsupported relocation size: %x",
+ REL_SIZE(rp));
+ }
+}
+
+/*
+ * 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;
+int relocatable_output;
+{
+ switch (REL_SIZE(rp)) {
+ case 0:
+ put_byte(addr, relocation);
+ break;
+ case 1:
+ put_short(addr, relocation);
+ break;
+ case 2:
+ put_long(addr, relocation);
+ break;
+ default:
+ errx(1, "Unsupported relocation size: %x",
+ REL_SIZE(rp));
+ }
+}
+
+/*
+ * 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 (rp->r_pcrel)
+ 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;
+}
+
+/*
+ * Bind a jmpslot to its target address. TARGET is where the jmpslot
+ * should jump to, and WHERE is a pointer to the jmpslot's address field.
+ * This is called by the dynamic linker when LD_BIND_NOW is set in the
+ * environment.
+ */
+void
+md_bind_jmpslot(target, where)
+u_long target;
+caddr_t where;
+{
+ jmpslot_t *sp =
+ (jmpslot_t *) (where - offsetof(jmpslot_t, addr[0]));
+
+ md_fix_jmpslot(sp, (long) sp, target);
+}
+
+/*
+ * 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;
+}
+
+void
+md_set_breakpoint(where, savep)
+long where;
+long *savep;
+{
+ *savep = *(long *)where;
+ *(char *)where = TRAP;
+}
+
+#ifndef RTLD
+
+#ifdef __FreeBSD__
+int netzmagic;
+#endif
+
+/*
+ * 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;
+{
+#ifdef NetBSD
+ if (oldmagic || magic == QMAGIC)
+ hp->a_midmag = magic;
+ else
+ N_SETMAGIC((*hp), magic, MID_I386, flags);
+#endif
+#ifdef __FreeBSD__
+ if (oldmagic)
+ hp->a_midmag = magic;
+ else if (netzmagic)
+ N_SETMAGIC_NET((*hp), magic, MID_I386, flags);
+ else
+ N_SETMAGIC((*hp), magic, MID_I386, flags);
+#endif
+
+ /* TEXT_START depends on the value of outheader.a_entry. */
+ if (!(link_mode & SHAREABLE))
+ hp->a_entry = PAGSIZ;
+}
+#endif /* RTLD */
+
+
+#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) & 0x00ffffff;
+ 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 & 3) << 1;
+ bits |= (r->r_extern & 1) << 3;
+ bits |= (r->r_baserel & 1) << 4;
+ bits |= (r->r_jmptable & 1) << 5;
+ bits |= (r->r_relative & 1) << 6;
+#ifdef N_SIZE
+ bits |= (r->r_copy & 1) << 7;
+#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..84785de
--- /dev/null
+++ b/libexec/rtld-aout/i386/md.h
@@ -0,0 +1,245 @@
+/*
+ * 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: md.h,v 1.16 1997/02/22 15:46:34 peter Exp $
+ */
+
+#ifndef __MD_H__
+#define __MD_H__
+
+#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
+
+#if defined(NetBSD) || defined(CROSS_LINKER)
+
+#define N_SET_FLAG(ex,f) (oldmagic || N_GETMAGIC(ex)==QMAGIC ? (0) : \
+ N_SETMAGIC(ex, \
+ N_GETMAGIC(ex), \
+ MID_MACHINE, \
+ N_GETFLAG(ex)|(f)))
+
+#define N_IS_DYNAMIC(ex) ((N_GETFLAG(ex) & EX_DYNAMIC))
+
+#define N_BADMID(ex) \
+ (N_GETMID(ex) != 0 && N_GETMID(ex) != MID_MACHINE)
+
+#endif
+
+/*
+ * FreeBSD does it differently
+ */
+#ifdef __FreeBSD__
+#define N_SET_FLAG(ex,f) (oldmagic ? (0) : \
+ (netzmagic == 0 ? \
+ N_SETMAGIC(ex, \
+ N_GETMAGIC(ex), \
+ MID_MACHINE, \
+ N_GETFLAG(ex)|(f)) : \
+ N_SETMAGIC_NET(ex, \
+ N_GETMAGIC_NET(ex), \
+ MID_MACHINE, \
+ N_GETFLAG_NET(ex)|(f)) ))
+
+#define N_IS_DYNAMIC(ex) ((N_GETMAGIC_NET(ex) == ZMAGIC) ? \
+ ((N_GETFLAG_NET(ex) & EX_DYNAMIC)) : \
+ ((N_GETFLAG(ex) & EX_DYNAMIC) ))
+#define N_BADMID(ex) 0
+#endif
+
+/*
+ * 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)
+
+#define RELOC_INIT_SEGMENT_RELOC(r) ((r)->r_length = 2)
+
+/* 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__dynamic(l)
+#define md_swapout__dynamic(l)
+#define md_swapin_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l)
+#define md_swapin_so_debug(d)
+#define md_swapout_so_debug(d)
+#define md_swapin_rrs_hash(f,n)
+#define md_swapout_rrs_hash(f,n)
+#define md_swapin_sod(l,n)
+#define md_swapout_sod(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
+
+#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); }
+
+#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__dynamic(l) swap__dynamic(l)
+#define md_swapout__dynamic(l) swap__dynamic(l)
+#define md_swapin_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapout_section_dispatch_table(l) swap_section_dispatch_table(l)
+#define md_swapin_so_debug(d) swap_so_debug(d)
+#define md_swapout_so_debug(d) swap_so_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_sod(l,n) swapin_sod(l,n)
+#define md_swapout_sod(l,n) swapout_sod(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))
+
+#else /* We need not swap, but must pay attention to alignment: */
+
+#define md_swap_short(x) (x)
+#define md_swap_long(x) (x)
+
+#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 */
+
+void md_init_header __P((struct exec *, int, int));
+long md_get_addend __P((struct relocation_info *, unsigned char *));
+void md_relocate __P((struct relocation_info *, long, unsigned char *, int));
+void md_make_jmpslot __P((jmpslot_t *, long, long));
+void md_fix_jmpslot __P((jmpslot_t *, long, u_long));
+void md_bind_jmpslot __P((u_long, caddr_t));
+int md_make_reloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_jmpreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_gotreloc __P((struct relocation_info *, struct relocation_info *, int));
+void md_make_copyreloc __P((struct relocation_info *, struct relocation_info *));
+void md_set_breakpoint __P((long, long *));
+
+
+#endif /* __MD_H__ */
diff --git a/libexec/rtld-aout/i386/mdprologue.S b/libexec/rtld-aout/i386/mdprologue.S
new file mode 100644
index 0000000..091fe7f
--- /dev/null
+++ b/libexec/rtld-aout/i386/mdprologue.S
@@ -0,0 +1,93 @@
+/*
+ * 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$
+ */
+
+/*
+ * i386 run-time link editor entry points.
+ */
+
+#include <sys/syscall.h>
+
+ .text
+ .globl _binder, _binder_entry
+
+/*
+ * _rtl(int version, struct crt_ldso *crtp)
+ */
+
+_rtl: # crt0 calls us here
+ pushl %ebp # Allocate stack frame
+ movl %esp,%ebp
+ 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
+
+ popl %ebx
+ leave # remove stack frame
+ ret
+
+ # 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
+
+ xorl %eax,%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
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.1 b/libexec/rtld-aout/rtld.1
new file mode 100644
index 0000000..dbd4dde
--- /dev/null
+++ b/libexec/rtld-aout/rtld.1
@@ -0,0 +1,224 @@
+.\" $Id: rtld.1,v 1.13 1997/02/22 15:46:47 peter Exp $
+.\"
+.\" Copyright (c) 1995 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 acknowledgment:
+.\" This product includes software developed by Paul Kranenburg.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd June 27, 1995
+.Dt RTLD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld.so
+.Nd run-time link-editor
+.Sh DESCRIPTION
+.Nm
+is a self-contained, position independent program image providing run-time
+support for loading and link-editing shared objects into a process'
+address space. It uses the data structures
+.Po
+see
+.Xr link 5
+.Pc
+contained within dynamically linked programs to determine which shared
+libraries are needed and loads them at a convenient virtual address
+using the
+.Xr mmap 2
+system call.
+.Pp
+After all shared libraries have been successfully loaded,
+.Nm
+proceeds to resolve external references from both the main program and
+all objects loaded. A mechanism is provided for initialization routines
+to be called, on a per-object basis, giving a shared object an opportunity
+to perform any extra set-up, before execution of the program proper begins.
+This is useful for C++ libraries that contain static constructors.
+.Pp
+.Nm
+is itself a shared object that is initially loaded by the startup module
+.Em crt0 .
+Since
+.Xr a.out 5
+formats do not provide easy access to the file header from within a running
+process,
+.Em crt0
+uses the special symbol
+.Va _DYNAMIC
+to determine whether a program is in fact dynamically linked or not. Whenever
+the linker
+.Xr ld 1
+has relocated this symbol to a location other than 0,
+.Em crt0
+assumes the services of
+.Nm
+are needed
+.Po
+see
+.Xr link 5
+for details
+.Pc \&.
+.Em crt0
+passes control to
+.Nm
+\&'s entry point before the program's
+.Fn main
+routine is called. Thus,
+.Nm
+can complete the link-editing process before the dynamic program calls upon
+services of any dynamic library.
+.Pp
+To quickly locate the required shared objects in the filesystem,
+.Nm
+may use a
+.Dq hints
+file, prepared by the
+.Xr ldconfig 8
+utility, in which the full path specification of the shared objects can be
+looked up by hashing on the 3-tuple
+.Ao
+library-name, major-version-number, minor-version-number
+.Ac \&.
+.Pp
+.Nm
+recognises a number of environment variables that can be used to modify
+its behaviour as follows:
+.Pp
+.Bl -tag -width "LD_IGNORE_MISSING_OBJECTS"
+.It Ev LD_LIBRARY_PATH
+A colon separated list of directories, overriding the default search path
+for shared libraries.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_PRELOAD
+A colon separated list of shared libraries, to be linked in before any
+other shared libraries. If the directory is not specified then
+the directories specified by LD_LIBRARY_PATH will be searched first
+followed by the set of built-in standard directories.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_BIND_NOW
+When set to a nonempty string, causes
+.Nm
+to relocate all external function calls before starting execution of the
+program. Normally, function calls are bound lazily, at the first call
+of each function.
+.Ev LD_BIND_NOW
+increases the start-up time of a program, but it avoids run-time
+surprises caused by unexpectedly undefined functions.
+.It Ev LD_WARN_NON_PURE_CODE
+When set to a nonempty string, issue a warning whenever a link-editing
+operation requires modification of the text segment of some loaded
+object. This is usually indicative of an incorrectly built library.
+.It Ev LD_SUPPRESS_WARNINGS
+When set to a nonempty string, no warning messages of any kind are
+issued. Normally, a warning is given if satisfactorily versioned
+library could not be found.
+.It Ev LD_IGNORE_MISSING_OBJECTS
+When set to a nonempty string, makes it a nonfatal condition if
+one or more required shared objects cannot be loaded.
+Loading and execution proceeds using the objects that are
+available.
+A warning is produced for each missing object, unless the environment
+variable
+.Ev LD_SUPPRESS_WARNINGS
+is set to a nonempty string.
+.Pp
+This is ignored for set-user-ID and set-group-ID programs.
+.Pp
+Missing shared objects can be ignored without errors if all the
+following conditions hold:
+.Bl -bullet
+.It
+They do not supply definitions for any required data symbols.
+.It
+No functions defined by them are called during program execution.
+.It
+The environment variable
+.Ev LD_BIND_NOW
+is unset or is set to the empty string.
+.El
+.It Ev LD_TRACE_LOADED_OBJECTS
+When set to a nonempty string, causes
+.Nm
+to exit after loading the shared objects and printing a summary which includes
+the absolute pathnames of all objects, to standard output.
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT1
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT2
+When set, these variables are interpreted as format strings a la
+.Xr printf 3
+to customize the trace output and are used by
+.Xr ldd 1 's
+.Fl f
+option and allows
+.Xr ldd 1
+to be operated as a filter more conveniently.
+The following conversions can be used:
+.Bl -tag -indent "LD_TRACE_LOADED_OBJECTS_FMT1 " -width "xxxx"
+.It \&%a
+The main program's name
+.Po also known as
+.Dq __progname
+.Pc .
+.It \&%A
+The value of the environment variable
+.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME
+.It \&%o
+The library name.
+.It \&%m
+The library's major version number.
+.It \&%n
+The library's minor version number.
+.It \&%p
+The full pathname as determined by
+.Nm rtld Ns 's
+library search rules.
+.It \&%x
+The library's load address.
+.El
+.Pp
+Additionally,
+.Sy \en
+and
+.Sy \et
+are recognised and have their usual meaning.
+.\" .It Ev LD_NO_INTERN_SEARCH
+.\" When set,
+.\" .Nm
+.\" does not process any internal search paths that were recorded in the
+.\" executable.
+.\" .It Ev LD_NOSTD_PATH
+.\" When set, do not include a set of built-in standard directory paths for
+.\" searching. This might be useful when running on a system with a completely
+.\" non-standard filesystem layout.
+.El
+.Pp
+.Sh FILES
+/var/run/ld.so.hints
+.Pp
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr link 5 ,
+.Xr ldconfig 8
+.Sh HISTORY
+The shared library model employed first appeared in SunOS 4.0
diff --git a/libexec/rtld-aout/rtld.1aout b/libexec/rtld-aout/rtld.1aout
new file mode 100644
index 0000000..dbd4dde
--- /dev/null
+++ b/libexec/rtld-aout/rtld.1aout
@@ -0,0 +1,224 @@
+.\" $Id: rtld.1,v 1.13 1997/02/22 15:46:47 peter Exp $
+.\"
+.\" Copyright (c) 1995 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 acknowledgment:
+.\" This product includes software developed by Paul Kranenburg.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd June 27, 1995
+.Dt RTLD 1
+.Os FreeBSD
+.Sh NAME
+.Nm ld.so
+.Nd run-time link-editor
+.Sh DESCRIPTION
+.Nm
+is a self-contained, position independent program image providing run-time
+support for loading and link-editing shared objects into a process'
+address space. It uses the data structures
+.Po
+see
+.Xr link 5
+.Pc
+contained within dynamically linked programs to determine which shared
+libraries are needed and loads them at a convenient virtual address
+using the
+.Xr mmap 2
+system call.
+.Pp
+After all shared libraries have been successfully loaded,
+.Nm
+proceeds to resolve external references from both the main program and
+all objects loaded. A mechanism is provided for initialization routines
+to be called, on a per-object basis, giving a shared object an opportunity
+to perform any extra set-up, before execution of the program proper begins.
+This is useful for C++ libraries that contain static constructors.
+.Pp
+.Nm
+is itself a shared object that is initially loaded by the startup module
+.Em crt0 .
+Since
+.Xr a.out 5
+formats do not provide easy access to the file header from within a running
+process,
+.Em crt0
+uses the special symbol
+.Va _DYNAMIC
+to determine whether a program is in fact dynamically linked or not. Whenever
+the linker
+.Xr ld 1
+has relocated this symbol to a location other than 0,
+.Em crt0
+assumes the services of
+.Nm
+are needed
+.Po
+see
+.Xr link 5
+for details
+.Pc \&.
+.Em crt0
+passes control to
+.Nm
+\&'s entry point before the program's
+.Fn main
+routine is called. Thus,
+.Nm
+can complete the link-editing process before the dynamic program calls upon
+services of any dynamic library.
+.Pp
+To quickly locate the required shared objects in the filesystem,
+.Nm
+may use a
+.Dq hints
+file, prepared by the
+.Xr ldconfig 8
+utility, in which the full path specification of the shared objects can be
+looked up by hashing on the 3-tuple
+.Ao
+library-name, major-version-number, minor-version-number
+.Ac \&.
+.Pp
+.Nm
+recognises a number of environment variables that can be used to modify
+its behaviour as follows:
+.Pp
+.Bl -tag -width "LD_IGNORE_MISSING_OBJECTS"
+.It Ev LD_LIBRARY_PATH
+A colon separated list of directories, overriding the default search path
+for shared libraries.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_PRELOAD
+A colon separated list of shared libraries, to be linked in before any
+other shared libraries. If the directory is not specified then
+the directories specified by LD_LIBRARY_PATH will be searched first
+followed by the set of built-in standard directories.
+This is ignored for set-user-ID and set-group-ID programs.
+.It Ev LD_BIND_NOW
+When set to a nonempty string, causes
+.Nm
+to relocate all external function calls before starting execution of the
+program. Normally, function calls are bound lazily, at the first call
+of each function.
+.Ev LD_BIND_NOW
+increases the start-up time of a program, but it avoids run-time
+surprises caused by unexpectedly undefined functions.
+.It Ev LD_WARN_NON_PURE_CODE
+When set to a nonempty string, issue a warning whenever a link-editing
+operation requires modification of the text segment of some loaded
+object. This is usually indicative of an incorrectly built library.
+.It Ev LD_SUPPRESS_WARNINGS
+When set to a nonempty string, no warning messages of any kind are
+issued. Normally, a warning is given if satisfactorily versioned
+library could not be found.
+.It Ev LD_IGNORE_MISSING_OBJECTS
+When set to a nonempty string, makes it a nonfatal condition if
+one or more required shared objects cannot be loaded.
+Loading and execution proceeds using the objects that are
+available.
+A warning is produced for each missing object, unless the environment
+variable
+.Ev LD_SUPPRESS_WARNINGS
+is set to a nonempty string.
+.Pp
+This is ignored for set-user-ID and set-group-ID programs.
+.Pp
+Missing shared objects can be ignored without errors if all the
+following conditions hold:
+.Bl -bullet
+.It
+They do not supply definitions for any required data symbols.
+.It
+No functions defined by them are called during program execution.
+.It
+The environment variable
+.Ev LD_BIND_NOW
+is unset or is set to the empty string.
+.El
+.It Ev LD_TRACE_LOADED_OBJECTS
+When set to a nonempty string, causes
+.Nm
+to exit after loading the shared objects and printing a summary which includes
+the absolute pathnames of all objects, to standard output.
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT1
+.It Ev LD_TRACE_LOADED_OBJECTS_FMT2
+When set, these variables are interpreted as format strings a la
+.Xr printf 3
+to customize the trace output and are used by
+.Xr ldd 1 's
+.Fl f
+option and allows
+.Xr ldd 1
+to be operated as a filter more conveniently.
+The following conversions can be used:
+.Bl -tag -indent "LD_TRACE_LOADED_OBJECTS_FMT1 " -width "xxxx"
+.It \&%a
+The main program's name
+.Po also known as
+.Dq __progname
+.Pc .
+.It \&%A
+The value of the environment variable
+.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME
+.It \&%o
+The library name.
+.It \&%m
+The library's major version number.
+.It \&%n
+The library's minor version number.
+.It \&%p
+The full pathname as determined by
+.Nm rtld Ns 's
+library search rules.
+.It \&%x
+The library's load address.
+.El
+.Pp
+Additionally,
+.Sy \en
+and
+.Sy \et
+are recognised and have their usual meaning.
+.\" .It Ev LD_NO_INTERN_SEARCH
+.\" When set,
+.\" .Nm
+.\" does not process any internal search paths that were recorded in the
+.\" executable.
+.\" .It Ev LD_NOSTD_PATH
+.\" When set, do not include a set of built-in standard directory paths for
+.\" searching. This might be useful when running on a system with a completely
+.\" non-standard filesystem layout.
+.El
+.Pp
+.Sh FILES
+/var/run/ld.so.hints
+.Pp
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr link 5 ,
+.Xr ldconfig 8
+.Sh HISTORY
+The shared library model employed first appeared in SunOS 4.0
diff --git a/libexec/rtld-aout/rtld.c b/libexec/rtld-aout/rtld.c
new file mode 100644
index 0000000..ea33fe8
--- /dev/null
+++ b/libexec/rtld-aout/rtld.c
@@ -0,0 +1,2120 @@
+/*
+ * 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.46 1997/02/22 15:46:48 peter Exp $
+ */
+
+#include <sys/param.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 MAP_COPY
+#define MAP_COPY MAP_PRIVATE
+#endif
+#include <dlfcn.h>
+#include <err.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <link.h>
+
+#include "md.h"
+#include "shlib.h"
+#include "support.h"
+#include "dynamic.h"
+
+#ifndef MAP_ANON
+#define MAP_ANON 0
+#define anon_open() do { \
+ if ((anon_fd = open("/dev/zero", O_RDWR, 0)) == -1) \
+ err("open: %s", "/dev/zero"); \
+} while (0)
+#define anon_close() do { \
+ (void)close(anon_fd); \
+ anon_fd = -1; \
+} while (0)
+#else
+#define anon_open()
+#define anon_close()
+#endif
+
+/*
+ * Structure for building a list of shared objects.
+ */
+struct so_list {
+ struct so_map *sol_map; /* Link map for shared object */
+ struct so_list *sol_next; /* Next entry in the list */
+};
+
+/*
+ * Loader private data, hung off <so_map>->som_spd
+ */
+struct somap_private {
+ int spd_version;
+ struct so_map *spd_parent;
+ struct so_list *spd_children;
+ struct so_map *spd_prev;
+ dev_t spd_dev;
+ ino_t spd_ino;
+ int spd_refcount;
+ int spd_flags;
+#define RTLD_MAIN 0x01
+#define RTLD_RTLD 0x02
+#define RTLD_DL 0x04
+#define RTLD_INIT 0x08
+ unsigned long a_text; /* text size, if known */
+ unsigned long a_data; /* initialized data size */
+ unsigned long a_bss; /* uninitialized data size */
+
+#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)))
+
+/* Start of search paths */
+#define LM_PATHS(smp) ((char *) \
+ ((smp)->som_addr + LM_OFFSET(smp) + LD_PATHS((smp)->som_dynamic)))
+
+/* End of text */
+#define LM_ETEXT(smp) ((char *) \
+ ((smp)->som_addr + LM_TXTADDR(smp) + LD_TEXTSZ((smp)->som_dynamic)))
+
+/* Needed shared objects */
+#define LM_NEED(smp) ((struct sod *) \
+ ((smp)->som_addr + LM_TXTADDR(smp) + LD_NEED((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)
+
+#ifndef RELOC_EXTERN_P
+#define RELOC_EXTERN_P(s) ((s)->r_extern)
+#endif
+
+#ifndef RELOC_SYMBOL
+#define RELOC_SYMBOL(s) ((s)->r_symbolnum)
+#endif
+
+#ifndef RELOC_PCREL_P
+#define RELOC_PCREL_P(s) ((s)->r_pcrel)
+#endif
+
+static char __main_progname[] = "main";
+static char *main_progname = __main_progname;
+static char us[] = "/usr/libexec/ld.so";
+
+char **environ;
+char *__progname;
+int errno;
+
+static uid_t uid, euid;
+static gid_t gid, egid;
+static int careful;
+static int anon_fd = -1;
+
+static char *ld_bind_now;
+static char *ld_ignore_missing_objects;
+static char *ld_library_path;
+static char *ld_preload;
+static char *ld_tracing;
+static char *ld_suppress_warnings;
+static char *ld_warn_non_pure_code;
+
+struct so_map *link_map_head;
+struct so_map *link_map_tail;
+struct rt_symbol *rt_symbol_head;
+
+static void *__dlopen __P((char *, int));
+static int __dlclose __P((void *));
+static void *__dlsym __P((void *, char *));
+static char *__dlerror __P((void));
+static void __dlexit __P((void));
+static void *__dlsym3 __P((void *, char *, void *));
+
+static struct ld_entry ld_entry = {
+ __dlopen, __dlclose, __dlsym, __dlerror, __dlexit, __dlsym3
+};
+
+ void xprintf __P((char *, ...));
+static struct so_map *map_object __P(( char *,
+ struct sod *,
+ struct so_map *));
+static int map_preload __P((void));
+static int map_sods __P((struct so_map *));
+static int reloc_and_init __P((struct so_map *, int));
+static void unmap_object __P((struct so_map *, int));
+static struct so_map *alloc_link_map __P(( char *, struct sod *,
+ struct so_map *, caddr_t,
+ struct _dynamic *));
+static void free_link_map __P((struct so_map *));
+static inline int check_text_reloc __P(( struct relocation_info *,
+ struct so_map *,
+ caddr_t));
+static int reloc_map __P((struct so_map *, int));
+static void reloc_copy __P((struct so_map *));
+static void init_object __P((struct so_map *));
+static void init_sods __P((struct so_list *));
+static int call_map __P((struct so_map *, char *));
+static char *findhint __P((char *, int, int *));
+static char *rtfindlib __P((char *, int, int));
+static char *rtfindfile __P((char *));
+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 void die __P((void));
+static void generror __P((char *, ...));
+static int maphints __P((void));
+static void unmaphints __P((void));
+static void ld_trace __P((struct so_map *));
+static void rt_readenv __P((void));
+static int hinthash __P((char *, int));
+int rtld __P((int, struct crt_ldso *, struct _dynamic *));
+
+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;
+{
+ struct relocation_info *reloc;
+ struct relocation_info *reloc_limit; /* End+1 of relocation */
+ struct so_debug *ddp;
+ struct so_map *main_map;
+ struct so_map *smp;
+ char *add_paths;
+
+ /* Check version */
+ if (version != CRT_VERSION_BSD_2 &&
+ version != CRT_VERSION_BSD_3 &&
+ version != CRT_VERSION_BSD_4 &&
+ version != CRT_VERSION_SUN)
+ return -1;
+
+ /* Fixup __DYNAMIC structure */
+ (long)dp->d_un.d_sdt += crtp->crt_ba;
+
+ /* Relocate ourselves */
+ reloc = (struct relocation_info *) (LD_REL(dp) + crtp->crt_ba);
+ reloc_limit =
+ (struct relocation_info *) ((char *) reloc + LD_RELSZ(dp));
+ while(reloc < reloc_limit) {
+ /*
+ * Objects linked with "-Bsymbolic" (in particular, ld.so
+ * itself) can end up having unused relocation entries at
+ * the end. These can be detected by the fact that they
+ * have an address of 0.
+ */
+ if(reloc->r_address == 0) /* We're done */
+ break;
+ md_relocate_simple(reloc, crtp->crt_ba,
+ reloc->r_address + crtp->crt_ba);
+ ++reloc;
+ }
+
+ if (version >= CRT_VERSION_BSD_4)
+ __progname = crtp->crt_ldso;
+ if (version >= CRT_VERSION_BSD_3)
+ main_progname = crtp->crt_prog;
+
+ /* Some buggy versions of crt0.o have crt_ldso filled in as NULL. */
+ if (__progname == NULL)
+ __progname = us;
+
+ /* Fill in some fields in _DYNAMIC or crt structure */
+ if (version >= CRT_VERSION_BSD_4)
+ crtp->crt_ldentry = &ld_entry; /* crt */
+ else
+ crtp->crt_dp->d_entry = &ld_entry; /* _DYNAMIC */
+
+ /* 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);
+
+ rt_readenv();
+
+ anon_open();
+
+ /* Make a link map entry for the main program */
+ main_map = alloc_link_map(main_progname,
+ (struct sod *) NULL, (struct so_map *) NULL,
+ (caddr_t) 0, crtp->crt_dp);
+ LM_PRIVATE(main_map)->spd_refcount++;
+ LM_PRIVATE(main_map)->spd_flags |= RTLD_MAIN;
+
+ /* Make a link map entry for ourselves */
+ smp = alloc_link_map(us,
+ (struct sod *) NULL, (struct so_map *) NULL,
+ (caddr_t) crtp->crt_ba, dp);
+ LM_PRIVATE(smp)->spd_refcount++;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_RTLD;
+
+ /*
+ * Setup the executable's run path
+ */
+ if (version >= CRT_VERSION_BSD_4) {
+ add_paths = LM_PATHS(main_map);
+ if (add_paths)
+ add_search_path(add_paths);
+ }
+
+ /*
+ * Setup the directory search list for findshlib. We use only
+ * the standard search path. Any extra directories from
+ * LD_LIBRARY_PATH are searched explicitly, in rtfindlib.
+ */
+ std_search_path();
+
+ /* Map in LD_PRELOADs before the main program's shared objects so we
+ can intercept those calls */
+ if (ld_preload != NULL) {
+ if(map_preload() == -1) /* Failed */
+ die();
+ }
+
+ /* Map all the shared objects that the main program depends upon */
+ if(map_sods(main_map) == -1)
+ die();
+
+ if(ld_tracing) { /* We're done */
+ ld_trace(link_map_head);
+ exit(0);
+ }
+
+ crtp->crt_dp->d_un.d_sdt->sdt_loaded = link_map_head->som_next;
+
+ /* Relocate and initialize all mapped objects */
+ if(reloc_and_init(main_map, ld_bind_now != NULL) == -1) /* Failed */
+ die();
+
+ 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) {
+ err(1, "Cannot set breakpoint (%s)", main_progname);
+ }
+ md_set_breakpoint((long)crtp->crt_bp, (long *)&ddp->dd_bpt_shadow);
+ if (mprotect(addr, PAGSIZ, PROT_READ|PROT_EXEC) == -1) {
+ err(1, "Cannot re-protect breakpoint (%s)",
+ main_progname);
+ }
+
+ ddp->dd_bpt_addr = crtp->crt_bp;
+ if (link_map_head)
+ ddp->dd_sym_loaded = 1;
+ }
+
+ /* Close the hints file */
+ unmaphints();
+
+ /* Close our file descriptor */
+ (void)close(crtp->crt_ldfd);
+ anon_close();
+
+ return LDSO_VERSION_HAS_DLSYM3;
+}
+
+void
+ld_trace(smp)
+ struct so_map *smp;
+{
+ char *fmt1, *fmt2, *fmt, *main_local;
+ int c;
+
+ if ((main_local = getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME")) == NULL)
+ main_local = "";
+
+ if ((fmt1 = getenv("LD_TRACE_LOADED_OBJECTS_FMT1")) == NULL)
+ fmt1 = "\t-l%o.%m => %p (%x)\n";
+
+ if ((fmt2 = getenv("LD_TRACE_LOADED_OBJECTS_FMT2")) == NULL)
+ fmt2 = "\t%o (%x)\n";
+
+ for (; smp; smp = smp->som_next) {
+ struct sod *sodp;
+ char *name, *path;
+
+ if ((sodp = smp->som_sod) == NULL)
+ continue;
+
+ name = (char *)sodp->sod_name;
+ if (LM_PARENT(smp))
+ name += (long)LM_LDBASE(LM_PARENT(smp));
+
+ if ((path = smp->som_path) == NULL)
+ path = "not found";
+
+ fmt = sodp->sod_library ? fmt1 : fmt2;
+ while ((c = *fmt++) != '\0') {
+ switch (c) {
+ default:
+ putchar(c);
+ continue;
+ case '\\':
+ switch (c = *fmt) {
+ case '\0':
+ continue;
+ case 'n':
+ putchar('\n');
+ break;
+ case 't':
+ putchar('\t');
+ break;
+ }
+ break;
+ case '%':
+ switch (c = *fmt) {
+ case '\0':
+ continue;
+ case '%':
+ default:
+ putchar(c);
+ break;
+ case 'A':
+ printf("%s", main_local);
+ break;
+ case 'a':
+ printf("%s", main_progname);
+ break;
+ case 'o':
+ printf("%s", name);
+ break;
+ case 'm':
+ printf("%d", sodp->sod_major);
+ break;
+ case 'n':
+ printf("%d", sodp->sod_minor);
+ break;
+ case 'p':
+ printf("%s", path);
+ break;
+ case 'x':
+ printf("%p", smp->som_addr);
+ break;
+ }
+ break;
+ }
+ ++fmt;
+ }
+ }
+}
+
+/*
+ * Allocate a new link map and return a pointer to it.
+ *
+ * PATH is the pathname of the shared object.
+ *
+ * SODP is a pointer to the shared object dependency structure responsible
+ * for causing the new object to be loaded. PARENT is the shared object
+ * into which SODP points. Both can be NULL if the new object is not
+ * being loaded as a result of a shared object dependency.
+ *
+ * ADDR is the address at which the object has been mapped. DP is a pointer
+ * to its _dynamic structure.
+ */
+ 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;
+ size_t smp_size;
+
+#ifdef DEBUG /* { */
+ xprintf("alloc_link_map: \"%s\" at %p\n", path, addr);
+#endif /* } */
+
+ /*
+ * Allocate so_map and private area with a single malloc. Round
+ * up the size of so_map so the private area is aligned.
+ */
+ smp_size = ((((sizeof(struct so_map)) + sizeof (void *) - 1) /
+ sizeof (void *)) * sizeof (void *));
+
+ smp = (struct so_map *)xmalloc(smp_size +
+ sizeof (struct somap_private));
+ smpp = (struct somap_private *) (((caddr_t) smp) + smp_size);
+
+ /* Link the new entry into the list of link maps */
+ smp->som_next = NULL;
+ smpp->spd_prev = link_map_tail;
+ if(link_map_tail == NULL) /* First link map entered into list */
+ link_map_head = link_map_tail = smp;
+ else { /* Append to end of list */
+ link_map_tail->som_next = smp;
+ link_map_tail = smp;
+ }
+
+ smp->som_addr = addr;
+ smp->som_path = path ? strdup(path) : NULL;
+ smp->som_sod = sodp;
+ smp->som_dynamic = dp;
+ smp->som_spd = (caddr_t)smpp;
+
+ smpp->spd_refcount = 0;
+ smpp->spd_flags = 0;
+ smpp->spd_parent = parent;
+ smpp->spd_children = NULL;
+ smpp->a_text = 0;
+ smpp->a_data = 0;
+ smpp->a_bss = 0;
+#ifdef SUN_COMPAT
+ smpp->spd_offset =
+ (addr==0 && dp && dp->d_version==LD_VERSION_SUN) ? PAGSIZ : 0;
+#endif
+ return smp;
+}
+
+/*
+ * Remove the specified link map entry from the list of link maps, and free
+ * the associated storage.
+ */
+ static void
+free_link_map(smp)
+ struct so_map *smp;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+#ifdef DEBUG /* { */
+ xprintf("free_link_map: \"%s\"\n", smp->som_path);
+#endif /* } */
+
+ if(smpp->spd_prev == NULL) /* Removing first entry in list */
+ link_map_head = smp->som_next;
+ else /* Update link of previous entry */
+ smpp->spd_prev->som_next = smp->som_next;
+
+ if(smp->som_next == NULL) /* Removing last entry in list */
+ link_map_tail = smpp->spd_prev;
+ else /* Update back link of next entry */
+ LM_PRIVATE(smp->som_next)->spd_prev = smpp->spd_prev;
+
+ free(smp->som_path);
+ free(smp);
+}
+
+/*
+ * Map the shared object specified by PATH into memory, if it is not
+ * already mapped. Increment the object's reference count, and return a
+ * pointer to its link map.
+ *
+ * As a special case, if PATH is NULL, it is taken to refer to the main
+ * program.
+ *
+ * SODP is a pointer to the shared object dependency structure that caused
+ * this object to be requested. PARENT is a pointer to the link map of
+ * the shared object containing that structure. For a shared object not
+ * being mapped as a result of a shared object dependency, these pointers
+ * should be NULL. An example of this is a shared object that is explicitly
+ * loaded via dlopen().
+ *
+ * The return value is a pointer to the link map for the requested object.
+ * If the operation failed, the return value is NULL. In that case, an
+ * error message can be retrieved by calling dlerror().
+ */
+ static struct so_map *
+map_object(path, sodp, parent)
+ char *path;
+ struct sod *sodp;
+ struct so_map *parent;
+{
+ struct so_map *smp;
+ struct stat statbuf;
+
+ if(path == NULL) /* Special case for the main program itself */
+ smp = link_map_head;
+ else {
+ /*
+ * Check whether the shared object is already mapped.
+ * We check first for an exact match by pathname. That
+ * will detect the usual case. If no match is found by
+ * pathname, then stat the file, and check for a match by
+ * device and inode. That will detect the less common case
+ * involving multiple links to the same library.
+ */
+ for(smp = link_map_head; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & (RTLD_MAIN|RTLD_RTLD))
+ && smp->som_path != NULL
+ && strcmp(smp->som_path, path) == 0)
+ break;
+ }
+ if(smp == NULL) { /* Check for a match by device and inode */
+ if (stat(path, &statbuf) == -1) {
+ generror ("cannot stat \"%s\" : %s",
+ path, strerror(errno));
+ return NULL;
+ }
+ for (smp = link_map_head; smp != NULL;
+ smp = smp->som_next) {
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ if (!(smpp->spd_flags & (RTLD_MAIN | RTLD_RTLD))
+ && smpp->spd_ino == statbuf.st_ino
+ && smpp->spd_dev == statbuf.st_dev)
+ break;
+ }
+ }
+ }
+
+ if (smp == NULL) { /* We must map the object */
+ struct _dynamic *dp;
+ int fd;
+ caddr_t addr;
+ struct exec hdr;
+ struct somap_private *smpp;
+
+ if ((fd = open(path, O_RDONLY, 0)) == -1) {
+ generror ("open failed for \"%s\" : %s",
+ path, strerror (errno));
+ return NULL;
+ }
+
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ generror ("header read failed for \"%s\"", path);
+ (void)close(fd);
+ return NULL;
+ }
+
+ if (N_BADMAG(hdr)) {
+ generror ("bad magic number in \"%s\"", path);
+ (void)close(fd);
+ return NULL;
+ }
+
+ /*
+ * Map the entire address space of the object. It is
+ * tempting to map just the text segment at first, in
+ * order to avoid having to use mprotect to change the
+ * protections of the data segment. But that would not
+ * be correct. Mmap might find a group of free pages
+ * large enough to hold the text segment, but not large
+ * enough for the entire object. When we then mapped
+ * in the data and BSS segments, they would either be
+ * non-contiguous with the text segment (if we didn't
+ * specify MAP_FIXED), or they would map over some
+ * previously mapped region (if we did use MAP_FIXED).
+ * The only way we can be sure of getting a contigous
+ * region that is large enough is to map the entire
+ * region at once.
+ */
+ if ((addr = mmap(0, hdr.a_text + hdr.a_data + hdr.a_bss,
+ PROT_READ|PROT_EXEC,
+ MAP_COPY, fd, 0)) == (caddr_t)-1) {
+ generror ("mmap failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)close(fd);
+ return NULL;
+ }
+
+ (void)close(fd);
+
+ /* Change the data segment to writable */
+ if (mprotect(addr + hdr.a_text, hdr.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
+ generror ("mprotect failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)munmap(addr, hdr.a_text + hdr.a_data + hdr.a_bss);
+ return NULL;
+ }
+
+ /* Map in pages of zeros for the BSS segment */
+ if (mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANON|MAP_COPY|MAP_FIXED,
+ anon_fd, 0) == (caddr_t)-1) {
+ generror ("mmap failed for \"%s\" : %s",
+ path, strerror (errno));
+ (void)munmap(addr, hdr.a_text + hdr.a_data + hdr.a_bss);
+ return NULL;
+ }
+
+ /* 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;
+
+ smp = alloc_link_map(path, sodp, parent, addr, dp);
+
+ /* save segment sizes for unmap. */
+ smpp = LM_PRIVATE(smp);
+ smpp->a_text = hdr.a_text;
+ smpp->a_data = hdr.a_data;
+ smpp->a_bss = hdr.a_bss;
+
+ /*
+ * Save the device and inode, so we can detect multiple links
+ * to the same library. Note, if we reach this point, then
+ * statbuf is guaranteed to have been filled in.
+ */
+ smpp->spd_dev = statbuf.st_dev;
+ smpp->spd_ino = statbuf.st_ino;
+ }
+
+ LM_PRIVATE(smp)->spd_refcount++;
+ if(LM_PRIVATE(smp)->spd_refcount == 1) { /* First use of object */
+ /*
+ * Recursively map all of the shared objects that this
+ * one depends upon.
+ */
+ if(map_sods(smp) == -1) { /* Failed */
+ unmap_object(smp, 0); /* Clean up */
+ return NULL;
+ }
+ }
+
+ return smp;
+}
+
+/*
+ * Map all the shared libraries named in the LD_PRELOAD environment
+ * variable.
+ *
+ * Returns 0 on success, -1 on failure. On failure, an error message can
+ * be gotten via dlerror().
+ */
+ static int
+map_preload __P((void)) {
+ char *ld_name = ld_preload;
+ char *name;
+
+ while ((name = strsep(&ld_name, ":")) != NULL) {
+ char *path = NULL;
+ struct so_map *smp = NULL;
+
+ if (*name != '\0') {
+ path = (strchr(name, '/') != NULL) ? strdup(name) :
+ rtfindfile(name);
+ }
+ if (path == NULL) {
+ generror("Can't find LD_PRELOAD shared"
+ " library \"%s\"", name);
+ } else {
+ smp = map_object(path, (struct sod *) NULL,
+ (struct so_map *) NULL);
+ free(path);
+ }
+ if (ld_name != NULL)
+ *(ld_name - 1) = ':';
+ if (smp == NULL) {
+ /*
+ * We don't bother to unmap already-loaded libraries
+ * on failure, because in that case the program is
+ * about to die anyway.
+ */
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Map all of the shared objects that a given object depends upon. PARENT is
+ * a pointer to the link map for the shared object whose dependencies are
+ * to be mapped.
+ *
+ * Returns 0 on success. Returns -1 on failure. In that case, an error
+ * message can be retrieved by calling dlerror().
+ */
+ static int
+map_sods(parent)
+ struct so_map *parent;
+{
+ struct somap_private *parpp = LM_PRIVATE(parent);
+ struct so_list **soltail = &parpp->spd_children;
+ long next = LD_NEED(parent->som_dynamic);
+
+ while(next != 0) {
+ struct sod *sodp =
+ (struct sod *) (LM_LDBASE(parent) + next);
+ char *name =
+ (char *) (LM_LDBASE(parent) + sodp->sod_name);
+ char *path = NULL;
+ struct so_map *smp = NULL;
+
+ if(sodp->sod_library) {
+ path = rtfindlib(name, sodp->sod_major,
+ sodp->sod_minor);
+ if(path == NULL && !ld_tracing) {
+ generror ("Can't find shared library"
+ " \"lib%s.so.%d.%d\"", name,
+ sodp->sod_major, sodp->sod_minor);
+ }
+ } else {
+ if(careful && name[0] != '/') {
+ generror("Shared library path must start"
+ " with \"/\" for \"%s\"", name);
+ } else
+ path = strdup(name);
+ }
+
+ if(path != NULL) {
+ smp = map_object(path, sodp, parent);
+ free(path);
+ }
+
+ if(smp != NULL) {
+ struct so_list *solp = (struct so_list *)
+ xmalloc(sizeof(struct so_list));
+ solp->sol_map = smp;
+ solp->sol_next = NULL;
+ *soltail = solp;
+ soltail = &solp->sol_next;
+ } else if(ld_tracing) {
+ /*
+ * Allocate a dummy map entry so that we will get the
+ * "not found" message.
+ */
+ (void)alloc_link_map(NULL, sodp, parent, 0, 0);
+ } else if (ld_ignore_missing_objects) {
+ char *msg;
+ /*
+ * Call __dlerror() even it we're not going to use
+ * the message, in order to clear the saved message.
+ */
+ msg = __dlerror(); /* Should never be NULL */
+ if (!ld_suppress_warnings)
+ warnx("warning: %s", msg);
+ } else /* Give up */
+ break;
+
+ next = sodp->sod_next;
+ }
+
+ if(next != 0) {
+ /*
+ * Oh drat, we have to clean up a mess.
+ *
+ * We failed to load a shared object that we depend upon.
+ * So now we have to unload any dependencies that we had
+ * already successfully loaded prior to the error.
+ *
+ * Cleaning up doesn't matter so much for the initial
+ * loading of the program, since any failure is going to
+ * terminate the program anyway. But it is very important
+ * to clean up properly when something is being loaded
+ * via dlopen().
+ */
+ struct so_list *solp;
+
+ while((solp = parpp->spd_children) != NULL) {
+ unmap_object(solp->sol_map, 0);
+ parpp->spd_children = solp->sol_next;
+ free(solp);
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Relocate and initialize the tree of shared objects rooted at the given
+ * link map entry. Returns 0 on success, or -1 on failure. On failure,
+ * an error message can be retrieved via dlerror().
+ */
+ static int
+reloc_and_init(root, bind_now)
+ struct so_map *root;
+ int bind_now;
+{
+ struct so_map *smp;
+
+ /*
+ * Relocate all newly-loaded objects. We avoid recursion for this
+ * step by taking advantage of a few facts. This function is called
+ * only when there are in fact some newly-loaded objects to process.
+ * Furthermore, all newly-loaded objects will have their link map
+ * entries at the end of the link map list. And, the root of the
+ * tree of objects just loaded will have been the first to be loaded
+ * and therefore the first new object in the link map list. Finally,
+ * we take advantage of the fact that we can relocate the newly-loaded
+ * objects in any order.
+ *
+ * All these facts conspire to let us simply loop over the tail
+ * portion of the link map list, relocating each object so
+ * encountered.
+ */
+ for(smp = root; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)) {
+ if(reloc_map(smp, bind_now) < 0)
+ return -1;
+ }
+ }
+
+ /*
+ * Copy any relocated initialized data. Again, we can just loop
+ * over the appropriate portion of the link map list.
+ */
+ for(smp = root; smp != NULL; smp = smp->som_next) {
+ if(!(LM_PRIVATE(smp)->spd_flags & RTLD_RTLD))
+ reloc_copy(smp);
+ }
+
+ /*
+ * Call any object initialization routines.
+ *
+ * Here, the order is very important, and we cannot simply loop
+ * over the newly-loaded objects as we did before. Rather, we
+ * have to initialize the tree of new objects depth-first, and
+ * process the sibling objects at each level in reverse order
+ * relative to the dependency list.
+ *
+ * Here is the reason we initialize depth-first. If an object
+ * depends on one or more other objects, then the objects it
+ * depends on should be initialized first, before the parent
+ * object itself. For it is possible that the parent's
+ * initialization routine will need the services provided by the
+ * objects it depends on -- and those objects had better already
+ * be initialized.
+ *
+ * We initialize the objects at each level of the tree in reverse
+ * order for a similar reason. When an object is linked with
+ * several libraries, it is common for routines in the earlier
+ * libraries to call routines in the later libraries. So, again,
+ * the later libraries need to be initialized first.
+ *
+ * The upshot of these rules is that we have to use recursion to
+ * get the libraries initialized in the best order. But the
+ * recursion is never likely to be very deep.
+ */
+ init_object(root);
+
+ return 0;
+}
+
+/*
+ * Remove a reference to the shared object specified by SMP. If no
+ * references remain, unmap the object and, recursively, its descendents.
+ * This function also takes care of calling the finalization routines for
+ * objects that are removed.
+ *
+ * If KEEP is true, then the actual calls to munmap() are skipped,
+ * and the object is kept in memory. That is used only for finalization,
+ * from dlexit(), when the program is exiting. There are two reasons
+ * for it. First, the program is exiting and there is no point in
+ * spending the time to explicitly unmap its shared objects. Second,
+ * even after dlexit() has been called, there are still a couple of
+ * calls that are made to functions in libc. (This is really a bug
+ * in crt0.) So libc and the main program, at least, must remain
+ * mapped in that situation.
+ *
+ * Under no reasonable circumstances should this function fail. If
+ * anything goes wrong, we consider it an internal error, and report
+ * it with err().
+ */
+ static void
+unmap_object(smp, keep)
+ struct so_map *smp;
+ int keep;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ smpp->spd_refcount--;
+ if(smpp->spd_refcount == 0) { /* Finished with this object */
+ struct so_list *solp;
+
+ if(smpp->spd_flags & RTLD_INIT) { /* Was initialized */
+ /*
+ * Call the object's finalization routine. For
+ * backward compatibility, we first try to call
+ * ".fini". If that does not exist, we call
+ * "__fini".
+ */
+ if(call_map(smp, ".fini") == -1)
+ call_map(smp, "__fini");
+ }
+
+ /* Recursively unreference the object's descendents */
+ while((solp = smpp->spd_children) != NULL) {
+ unmap_object(solp->sol_map, keep);
+ smpp->spd_children = solp->sol_next;
+ free(solp);
+ }
+
+ if(!keep) { /* Unmap the object from memory */
+ if(munmap(smp->som_addr,
+ smpp->a_text + smpp->a_data + smpp->a_bss) < 0)
+ err(1, "internal error 1: munmap failed");
+
+ /* Unlink and free the object's link map entry */
+ free_link_map(smp);
+ }
+ }
+}
+
+static inline int
+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 0;
+
+ if (RELOC_EXTERN_P(r))
+ sym = LM_STRINGS(smp) +
+ LM_SYMBOL(smp, RELOC_SYMBOL(r))->nz_strx;
+ else
+ sym = "";
+
+ if (!ld_suppress_warnings && ld_warn_non_pure_code)
+ warnx("warning: non pure code in %s at %x (%s)",
+ 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) {
+ generror ("mprotect failed for \"%s\" : %s",
+ smp->som_path, strerror (errno));
+ return -1;
+ }
+
+ smp->som_write = 1;
+ return 0;
+}
+
+static int
+reloc_map(smp, bind_now)
+ struct so_map *smp;
+ int bind_now;
+{
+ /*
+ * Caching structure for reducing the number of calls to
+ * lookup() during relocation.
+ *
+ * While relocating a given shared object, the dynamic linker
+ * maintains a caching vector that is directly indexed by
+ * the symbol number in the relocation entry. The first time
+ * a given symbol is looked up, the caching vector is
+ * filled in with a pointer to the symbol table entry, and
+ * a pointer to the so_map of the shared object in which the
+ * symbol was defined. On subsequent uses of the same symbol,
+ * that information is retrieved directly from the caching
+ * vector, without calling lookup() again.
+ *
+ * A symbol that is referenced in a relocation entry is
+ * typically referenced in many relocation entries, so this
+ * caching reduces the number of calls to lookup()
+ * dramatically. The overall improvement in the speed of
+ * dynamic linking is also dramatic -- as much as a factor
+ * of three for programs that use many shared libaries.
+ */
+ struct cacheent {
+ struct nzlist *np; /* Pointer to symbol entry */
+ struct so_map *src_map; /* Shared object that defined symbol */
+ };
+
+ 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);
+ long numsyms = LD_STABSZ(dp) / symsize;
+ size_t cachebytes = numsyms * sizeof(struct cacheent);
+ struct cacheent *symcache =
+ (struct cacheent *) alloca(cachebytes);
+
+ if(symcache == NULL) {
+ generror("Cannot allocate symbol caching vector for %s",
+ smp->som_path);
+ return -1;
+ }
+ bzero(symcache, cachebytes);
+
+ 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;
+
+ /*
+ * Objects linked with "-Bsymbolic" can end up having unused
+ * relocation entries at the end. These can be detected by
+ * the fact that they have an address of 0.
+ */
+ if(r->r_address == 0) /* Finished relocating this object */
+ break;
+
+ addr = smp->som_addr + r->r_address;
+ if (check_text_reloc(r, smp, addr) < 0)
+ return -1;
+
+ if (RELOC_EXTERN_P(r)) {
+ struct so_map *src_map = NULL;
+ struct nzlist *p, *np;
+ long relocation;
+
+ if (RELOC_JMPTAB_P(r) && !bind_now)
+ 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;
+
+ /*
+ * Look up the symbol, checking the caching
+ * vector first.
+ */
+ np = symcache[RELOC_SYMBOL(r)].np;
+ if(np != NULL) /* Symbol already cached */
+ src_map = symcache[RELOC_SYMBOL(r)].src_map;
+ else { /* Symbol not cached yet */
+ np = lookup(sym, &src_map, RELOC_JMPTAB_P(r));
+ /*
+ * Record the needed information about
+ * the symbol in the caching vector,
+ * so that we won't have to call
+ * lookup the next time we encounter
+ * the symbol.
+ */
+ symcache[RELOC_SYMBOL(r)].np = np;
+ symcache[RELOC_SYMBOL(r)].src_map = src_map;
+ }
+
+ if (np == NULL) {
+ generror ("Undefined symbol \"%s\" in %s:%s",
+ sym, main_progname, smp->som_path);
+ return -1;
+ }
+
+ /*
+ * 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_JMPTAB_P(r)) {
+ md_bind_jmpslot(relocation, addr);
+ continue;
+ }
+
+ relocation += md_get_addend(r, 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) {
+ generror ("mprotect failed for \"%s\" : %s",
+ smp->som_path, strerror (errno));
+ return -1;
+ }
+ smp->som_write = 0;
+ }
+ return 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_object(smp)
+ struct so_map *smp;
+{
+ struct somap_private *smpp = LM_PRIVATE(smp);
+
+ if(!(smpp->spd_flags & RTLD_INIT)) { /* Not initialized yet */
+ smpp->spd_flags |= RTLD_INIT;
+
+ /* Make sure all the children are initialized */
+ if(smpp->spd_children != NULL)
+ init_sods(smpp->spd_children);
+
+ if(call_map(smp, ".init") == -1)
+ call_map(smp, "__init");
+ }
+}
+
+ static void
+init_sods(solp)
+ struct so_list *solp;
+{
+ /* Recursively initialize the rest of the list */
+ if(solp->sol_next != NULL)
+ init_sods(solp->sol_next);
+
+ /* Initialize the first element of the list */
+ init_object(solp->sol_map);
+}
+
+
+/*
+ * Call a function in a given shared object. SMP is the shared object, and
+ * SYM is the name of the function.
+ *
+ * Returns 0 on success, or -1 if the symbol was not found. Failure is not
+ * necessarily an error condition, so no error message is generated.
+ */
+ static int
+call_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))();
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * 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 inline 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 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)
+ continue;
+
+ /* 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;
+ long hashval;
+ struct rrs_hash *hp;
+ char *cp;
+ struct nzlist *np;
+
+ /* Some local caching */
+ long symbolbase;
+ struct rrs_hash *hashbase;
+ char *stringbase;
+ int symsize;
+
+ if (*src_map && smp != *src_map)
+ continue;
+
+ if ((buckets = LD_BUCKETS(smp->som_dynamic)) == 0)
+ continue;
+
+ if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ continue;
+
+restart:
+ /*
+ * Compute bucket in which the symbol might be found.
+ */
+ for (hashval = 0, 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_type == N_INDR+N_EXT) {
+ /*
+ * Next symbol gives the aliased name. Restart
+ * search with new name and confine to this map.
+ */
+ name = stringbase + (++np)->nz_strx;
+ *src_map = smp;
+ goto restart;
+ }
+
+ 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)
+ errx(1, "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)
+ errx(1, "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; /* NULL means not mapped */
+static struct hints_bucket *hbuckets;
+static char *hstrtab;
+
+/*
+ * Map the hints file into memory, if it is not already mapped. Returns
+ * 0 on success, or -1 on failure.
+ */
+ static int
+maphints __P((void))
+{
+ static int hints_bad; /* TRUE if hints are unusable */
+ static int paths_added;
+ int hfd;
+ struct hints_header hdr;
+ caddr_t addr;
+
+ if (hheader != NULL) /* Already mapped */
+ return 0;
+
+ if (hints_bad) /* Known to be corrupt or unavailable */
+ return -1;
+
+ if ((hfd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
+ hints_bad = 1;
+ return -1;
+ }
+
+ /* Read the header and check it */
+
+ if (read(hfd, &hdr, sizeof hdr) != sizeof hdr ||
+ HH_BADMAG(hdr) ||
+ (hdr.hh_version != LD_HINTS_VERSION_1 &&
+ hdr.hh_version != LD_HINTS_VERSION_2)) {
+ close(hfd);
+ hints_bad = 1;
+ return -1;
+ }
+
+ /* Map the hints into memory */
+
+ addr = mmap(0, hdr.hh_ehints, PROT_READ, MAP_SHARED, hfd, 0);
+ if (addr == (caddr_t)-1) {
+ close(hfd);
+ hints_bad = 1;
+ return -1;
+ }
+
+ close(hfd);
+
+ hheader = (struct hints_header *)addr;
+ hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
+ hstrtab = (char *)(addr + hheader->hh_strtab);
+ /* pluck out the system ldconfig path */
+ if (hheader->hh_version >= LD_HINTS_VERSION_2 && !paths_added) {
+ add_search_path(hstrtab + hheader->hh_dirlist);
+ paths_added = 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Unmap the hints file, if it is currently mapped.
+ */
+ static void
+unmaphints()
+{
+ if (hheader != NULL) {
+ munmap((caddr_t)hheader, hheader->hh_ehints);
+ hheader = NULL;
+ }
+}
+
+ int
+hinthash(cp, vmajor)
+ char *cp;
+ int vmajor;
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+
+ return k;
+}
+
+#undef major
+#undef minor
+
+/*
+ * Search for a library in the hints generated by ldconfig. On success,
+ * returns the full pathname of the matching library. This string is
+ * always dynamically allocated on the heap.
+ *
+ * Returns the minor number of the matching library via the pointer
+ * argument MINORP.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+findhint(name, major, minorp)
+ char *name;
+ int major;
+ int *minorp;
+{
+ struct hints_bucket *bp =
+ hbuckets + (hinthash(name, major) % hheader->hh_nbucket);
+
+ while (1) {
+ /* Sanity check */
+ if (bp->hi_namex >= hheader->hh_strtab_sz) {
+ warnx("Bad name index: %#x\n", bp->hi_namex);
+ break;
+ }
+ if (bp->hi_pathx >= hheader->hh_strtab_sz) {
+ warnx("Bad path index: %#x\n", bp->hi_pathx);
+ break;
+ }
+
+ /*
+ * We accept the current hints entry if its name matches
+ * and its major number matches. We don't have to search
+ * for the best minor number, because that was already
+ * done by "ldconfig" when it built the hints file.
+ */
+ if (strcmp(name, hstrtab + bp->hi_namex) == 0 &&
+ bp->hi_major == major) {
+ struct stat s;
+
+ if (stat(hstrtab + bp->hi_pathx, &s) == -1)
+ return NULL; /* Doesn't actually exist */
+ *minorp = bp->hi_ndewey >= 2 ? bp->hi_minor : -1;
+ return strdup(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;
+}
+
+/*
+ * Search for the given shared library. On success, returns a string
+ * containing the full pathname for the library. This string is always
+ * dynamically allocated on the heap.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+rtfindlib(name, major, minor)
+ char *name;
+ int major, minor;
+{
+ char *ld_path = ld_library_path;
+ char *path = NULL;
+ int realminor = -1;
+
+ if (ld_path != NULL) { /* First, search the directories in ld_path */
+ /*
+ * There is no point in trying to use the hints file for this.
+ */
+ char *dir;
+
+ while (path == NULL && (dir = strsep(&ld_path, ":")) != NULL) {
+ path = search_lib_dir(dir, name, &major, &realminor, 0);
+ if (ld_path != NULL)
+ *(ld_path - 1) = ':';
+ }
+ }
+
+ if (path == NULL && maphints() == 0) /* Search the hints file */
+ path = findhint(name, major, &realminor);
+
+ if (path == NULL) /* Search the standard directories */
+ path = findshlib(name, &major, &realminor, 0);
+
+ if (path != NULL && realminor < minor && !ld_suppress_warnings) {
+ warnx("warning: %s: minor version %d"
+ " older than expected %d, using it anyway",
+ path, realminor, minor);
+ }
+
+ return path;
+}
+
+/*
+ * Search for the given shared library file. This is similar to rtfindlib,
+ * except that the argument is the actual name of the desired library file.
+ * Thus there is no need to worry about version numbers. The return value
+ * is a string containing the full pathname for the library. This string
+ * is always dynamically allocated on the heap.
+ *
+ * Returns NULL if the library cannot be found.
+ */
+ static char *
+rtfindfile(name)
+ char *name;
+{
+ char *ld_path = ld_library_path;
+ char *path = NULL;
+
+ if (ld_path != NULL) { /* First, search the directories in ld_path */
+ char *dir;
+
+ while (path == NULL && (dir = strsep(&ld_path, ":")) != NULL) {
+ struct stat sb;
+
+ path = concat(dir, "/", name);
+ if (lstat(path, &sb) == -1) { /* Does not exist */
+ free(path);
+ path = NULL;
+ }
+ if (ld_path != NULL)
+ *(ld_path - 1) = ':';
+ }
+ }
+
+ /*
+ * We don't search the hints file. It is organized around major
+ * and minor version numbers, so it is not suitable for finding
+ * a specific file name.
+ */
+
+ if (path == NULL) /* Search the standard directories */
+ path = find_lib_file(name);
+
+ return path;
+}
+
+/*
+ * Buffer for error messages and a pointer that is set to point to the buffer
+ * when a error occurs. It acts as a last error flag, being set to NULL
+ * after an error is returned.
+ */
+#define DLERROR_BUF_SIZE 512
+static char dlerror_buf [DLERROR_BUF_SIZE];
+static char *dlerror_msg = NULL;
+
+
+ static void *
+__dlopen(path, mode)
+ char *path;
+ int mode;
+{
+ struct so_map *old_tail = link_map_tail;
+ struct so_map *smp;
+ int bind_now = mode == RTLD_NOW;
+
+ /*
+ * path == NULL is handled by map_object()
+ */
+
+ anon_open();
+
+ /* Map the object, and the objects on which it depends */
+ smp = map_object(path, (struct sod *) NULL, (struct so_map *) NULL);
+ if(smp == NULL) /* Failed */
+ return NULL;
+ LM_PRIVATE(smp)->spd_flags |= RTLD_DL;
+
+ /* Relocate and initialize all newly-mapped objects */
+ if(link_map_tail != old_tail) { /* We have mapped some new objects */
+ if(reloc_and_init(smp, bind_now) == -1) /* Failed */
+ return NULL;
+ }
+
+ unmaphints();
+ anon_close();
+
+ return smp;
+}
+
+ static int
+__dlclose(fd)
+ void *fd;
+{
+ struct so_map *smp = (struct so_map *)fd;
+ struct so_map *scanp;
+
+#ifdef DEBUG
+ xprintf("dlclose(%s): refcount = %d\n", smp->som_path,
+ LM_PRIVATE(smp)->spd_refcount);
+#endif
+ /* Check the argument for validity */
+ for(scanp = link_map_head; scanp != NULL; scanp = scanp->som_next)
+ if(scanp == smp) /* We found the map in the list */
+ break;
+ if(scanp == NULL || !(LM_PRIVATE(smp)->spd_flags & RTLD_DL)) {
+ generror("Invalid argument to dlclose");
+ return -1;
+ }
+
+ unmap_object(smp, 0);
+
+ return 0;
+}
+
+/*
+ * This form of dlsym is obsolete. Current versions of crt0 don't call
+ * it. It can still be called by old executables that were linked with
+ * old versions of crt0.
+ */
+ static void *
+__dlsym(fd, sym)
+ void *fd;
+ char *sym;
+{
+ if (fd == RTLD_NEXT) {
+ generror("RTLD_NEXT not supported by this version of"
+ " /usr/lib/crt0.o");
+ return NULL;
+ }
+ return __dlsym3(fd, sym, NULL);
+}
+
+ static void *
+__dlsym3(fd, sym, retaddr)
+ void *fd;
+ char *sym;
+ void *retaddr;
+{
+ struct so_map *smp;
+ struct so_map *src_map;
+ struct nzlist *np;
+ long addr;
+
+ if (fd == RTLD_NEXT) {
+ /* Find the shared object that contains the caller. */
+ for (smp = link_map_head; smp != NULL; smp = smp->som_next) {
+ void *textbase = smp->som_addr + LM_TXTADDR(smp);
+ void *textlimit = LM_ETEXT(smp);
+
+ if (textbase <= retaddr && retaddr < textlimit)
+ break;
+ }
+ if (smp == NULL) {
+ generror("Cannot determine caller's shared object");
+ return NULL;
+ }
+ smp = smp->som_next;
+ if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_RTLD)
+ smp = smp->som_next;
+ if (smp == NULL) {
+ generror("No next shared object for RTLD_NEXT");
+ return NULL;
+ }
+ do {
+ src_map = smp;
+ np = lookup(sym, &src_map, 1);
+ } while (np == NULL && (smp = smp->som_next) != NULL);
+ } else {
+ smp = (struct so_map *)fd;
+ src_map = NULL;
+
+ /*
+ * Restrict search to passed map if dlopen()ed.
+ */
+ if (smp != NULL && LM_PRIVATE(smp)->spd_flags & RTLD_DL)
+ src_map = smp;
+
+ np = lookup(sym, &src_map, 1);
+ }
+
+ if (np == NULL) {
+ generror("Undefined symbol");
+ return NULL;
+ }
+
+ addr = np->nz_value;
+ if (src_map)
+ addr += (long)src_map->som_addr;
+
+ return (void *)addr;
+}
+
+ static char *
+__dlerror __P((void))
+{
+ char *err;
+
+ err = dlerror_msg;
+ dlerror_msg = NULL; /* Next call will return NULL */
+
+ return err;
+}
+
+ static void
+__dlexit __P((void))
+{
+#ifdef DEBUG
+xprintf("__dlexit called\n");
+#endif
+
+ unmap_object(link_map_head, 1);
+}
+
+/*
+ * Print the current error message and exit with failure status.
+ */
+static void
+die __P((void))
+{
+ char *msg;
+
+ fprintf(stderr, "ld.so failed");
+ if ((msg = __dlerror()) != NULL)
+ fprintf(stderr, ": %s", msg);
+ putc('\n', stderr);
+ _exit(1);
+}
+
+
+/*
+ * Generate an error message that can be later be retrieved via dlerror.
+ */
+static void
+#if __STDC__
+generror(char *fmt, ...)
+#else
+generror(fmt, va_alist)
+char *fmt;
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vsnprintf (dlerror_buf, DLERROR_BUF_SIZE, fmt, ap);
+ dlerror_msg = dlerror_buf;
+
+ va_end(ap);
+}
+
+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
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ (void)write(1, buf, strlen(buf));
+ va_end(ap);
+}
+
+/*
+ * rt_readenv() etc.
+ *
+ * Do a sweep over the environment once only, pick up what
+ * looks interesting.
+ *
+ * This is pretty obscure, but is relatively simple. Simply
+ * look at each environment variable, if it starts with "LD_" then
+ * look closer at it. If it's in our table, set the variable
+ * listed. effectively, this is like:
+ * ld_preload = careful ? NULL : getenv("LD_PRELOAD");
+ * except that the environment is scanned once only to pick up all
+ * known variables, rather than scanned multiple times for each
+ * variable.
+ *
+ * If an environment variable of interest is set to the empty string, we
+ * treat it as if it were unset.
+ */
+
+#define L(n, u, v) { n, sizeof(n) - 1, u, v },
+struct env_scan_tab {
+ char *name;
+ int len;
+ int unsafe;
+ char **value;
+} scan_tab[] = {
+ L("LD_LIBRARY_PATH=", 1, &ld_library_path)
+ L("LD_PRELOAD=", 1, &ld_preload)
+ L("LD_IGNORE_MISSING_OBJECTS=", 1, &ld_ignore_missing_objects)
+ L("LD_TRACE_LOADED_OBJECTS=", 0, &ld_tracing)
+ L("LD_BIND_NOW=", 0, &ld_bind_now)
+ L("LD_SUPPRESS_WARNINGS=", 0, &ld_suppress_warnings)
+ L("LD_WARN_NON_PURE_CODE=", 0, &ld_warn_non_pure_code)
+ { NULL, 0, NULL }
+};
+#undef L
+
+static void
+rt_readenv()
+{
+ char **p = environ;
+ char *v;
+ struct env_scan_tab *t;
+
+ /* for each string in the environment... */
+ while ((v = *p++)) {
+
+ /* check for LD_xxx */
+ if (v[0] != 'L' || v[1] != 'D' || v[2] != '_')
+ continue;
+
+ for (t = scan_tab; t->name; t++) {
+ if (careful && t->unsafe)
+ continue; /* skip for set[ug]id */
+ if (strncmp(t->name, v, t->len) == 0) {
+ if (*(v + t->len) != '\0') /* Not empty */
+ *t->value = v + t->len;
+ break;
+ }
+ }
+ }
+}
diff --git a/libexec/rtld-aout/shlib.c b/libexec/rtld-aout/shlib.c
new file mode 100644
index 0000000..efb0bb6
--- /dev/null
+++ b/libexec/rtld-aout/shlib.c
@@ -0,0 +1,342 @@
+/*
+ * 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$
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <a.out.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <link.h>
+#include "shlib.h"
+#include "support.h"
+
+/*
+ * Standard directories to search for files specified by -l.
+ */
+#ifndef STANDARD_SEARCH_DIRS
+#define STANDARD_SEARCH_DIRS "/usr/lib"
+#endif
+
+/*
+ * Actual vector of library search directories,
+ * including `-L'ed and LD_LIBRARY_PATH spec'd ones.
+ */
+char **search_dirs;
+int n_search_dirs;
+
+char *standard_search_dirs[] = {
+ STANDARD_SEARCH_DIRS
+};
+
+
+void
+add_search_dir(name)
+ char *name;
+{
+ int n;
+
+ for (n = 0; n < n_search_dirs; n++)
+ if (strcmp(search_dirs[n], name) == 0)
+ return;
+ n_search_dirs++;
+ search_dirs = (char **)
+ xrealloc(search_dirs, n_search_dirs * sizeof search_dirs[0]);
+ search_dirs[n_search_dirs - 1] = strdup(name);
+}
+
+void
+add_search_path(path)
+char *path;
+{
+ register char *cp, *dup;
+
+ if (path == NULL)
+ return;
+
+ /* Add search directories from `path' */
+ path = dup = strdup(path);
+ while ((cp = strsep(&path, ":")) != NULL)
+ add_search_dir(cp);
+ free(dup);
+}
+
+void
+std_search_path()
+{
+ int i, n;
+
+ /* 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;
+{
+ register 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;
+
+ errx(1, "cmpndewey: cant happen");
+ return 0;
+}
+
+/*
+ * Search directories for a shared library matching the given
+ * major and minor version numbers. See search_lib_dir() below for
+ * the detailed matching rules.
+ *
+ * As soon as a directory with an acceptable match is found, the search
+ * terminates. Subsequent directories are not searched for a better
+ * match. This is in conformance with the SunOS searching rules. Also,
+ * it avoids a lot of directory searches that are virtually guaranteed to
+ * be fruitless.
+ *
+ * The return value is a full pathname to the matching library. The
+ * string is dynamically allocated. If no matching library is found, the
+ * function returns NULL.
+ */
+
+char *
+findshlib(name, majorp, minorp, do_dot_a)
+char *name;
+int *majorp, *minorp;
+int do_dot_a;
+{
+ int i;
+
+ for (i = 0; i < n_search_dirs; i++) {
+ char *path;
+
+ path = search_lib_dir(search_dirs[i], name, majorp, minorp,
+ do_dot_a);
+ if(path != NULL)
+ return path;
+ }
+
+ return NULL;
+}
+
+/*
+ * Search library directories for a file with the given name. The
+ * return value is a full pathname to the matching file. The string
+ * is dynamically allocated. If no matching file is found, the function
+ * returns NULL.
+ */
+
+char *
+find_lib_file(name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; i < n_search_dirs; i++) {
+ char *path = concat(search_dirs[i], "/", name);
+ struct stat sb;
+
+ if (lstat(path, &sb) != -1) /* We found it */
+ return path;
+
+ free(path);
+ }
+
+ return NULL;
+}
+
+/*
+ * Search a given directory for a library (preferably shared) satisfying
+ * the given criteria.
+ *
+ * The matching rules are as follows:
+ *
+ * if(*majorp == -1)
+ * find the library with the highest major version;
+ * else
+ * insist on a major version identical to *majorp;
+ *
+ * Always find the library with the highest minor version;
+ * if(*minorp != -1)
+ * insist on a minor version >= *minorp;
+ *
+ * It is invalid to specify a specific minor number while wildcarding
+ * the major number.
+ *
+ * The actual major and minor numbers found are returned via the pointer
+ * arguments.
+ *
+ * A suitable shared library is always preferred over a static (.a) library.
+ * If do_dot_a is false, then a static library will not be accepted in
+ * any case.
+ *
+ * The return value is a full pathname to the matching library. The
+ * string is dynamically allocated. If no matching library is found, the
+ * function returns NULL.
+ */
+
+char *
+search_lib_dir(dir, name, majorp, minorp, do_dot_a)
+ char *dir;
+ char *name;
+ int *majorp;
+ int *minorp;
+ int do_dot_a;
+{
+ int namelen;
+ DIR *dd;
+ struct dirent *dp;
+ int best_dewey[MAXDEWEY];
+ int best_ndewey;
+ char dot_a_name[MAXNAMLEN+1];
+ char dot_so_name[MAXNAMLEN+1];
+
+ if((dd = opendir(dir)) == NULL)
+ return NULL;
+
+ namelen = strlen(name);
+ best_ndewey = 0;
+ dot_a_name[0] = '\0';
+ dot_so_name[0] = '\0';
+
+ while((dp = readdir(dd)) != NULL) {
+ char *extension;
+
+ if(strlen(dp->d_name) < 3 + namelen + 2 || /* lib+xxx+.a */
+ strncmp(dp->d_name, "lib", 3) != 0 ||
+ strncmp(dp->d_name + 3, name, namelen) != 0 ||
+ dp->d_name[3+namelen] != '.')
+ continue;
+
+ extension = dp->d_name + 3 + namelen + 1; /* a or so.* */
+
+ if(strncmp(extension, "so.", 3) == 0) {
+ int cur_dewey[MAXDEWEY];
+ int cur_ndewey;
+
+ cur_ndewey = getdewey(cur_dewey, extension+3);
+ if(cur_ndewey == 0) /* No version number */
+ continue;
+
+ if(*majorp != -1) { /* Need exact match on major */
+ if(cur_dewey[0] != *majorp)
+ continue;
+ if(*minorp != -1) { /* Need minor >= minimum */
+ if(cur_ndewey < 2 ||
+ cur_dewey[1] < *minorp)
+ continue;
+ }
+ }
+
+ if(cmpndewey(cur_dewey, cur_ndewey, best_dewey,
+ best_ndewey) <= 0) /* No better than prior match */
+ continue;
+
+ /* We found a better match */
+ strcpy(dot_so_name, dp->d_name);
+ bcopy(cur_dewey, best_dewey,
+ cur_ndewey * sizeof best_dewey[0]);
+ best_ndewey = cur_ndewey;
+ } else if(do_dot_a && strcmp(extension, "a") == 0)
+ strcpy(dot_a_name, dp->d_name);
+ }
+ closedir(dd);
+
+ if(dot_so_name[0] != '\0') {
+ *majorp = best_dewey[0];
+ if(best_ndewey >= 2)
+ *minorp = best_dewey[1];
+ return concat(dir, "/", dot_so_name);
+ }
+
+ if(dot_a_name[0] != '\0')
+ return concat(dir, "/", dot_a_name);
+
+ return NULL;
+}
diff --git a/libexec/rtld-aout/shlib.h b/libexec/rtld-aout/shlib.h
new file mode 100644
index 0000000..796d37e
--- /dev/null
+++ b/libexec/rtld-aout/shlib.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (C) 1996
+ * Peter Wemm. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *-
+ * $Id$
+ */
+
+/*
+ * prototypes for shlib.c. Big deal.
+ */
+
+extern char **search_dirs;
+extern int n_search_dirs;
+
+void add_search_dir __P((char *));
+void add_search_path __P((char *));
+void std_search_path __P((void));
+int getdewey __P((int[], char *));
+int cmpndewey __P((int[], int, int[], int));
+char *findshlib __P((char *, int *, int *, int));
+char *find_lib_file __P((char *));
+char *search_lib_dir __P((char *, char *, int *, int *, int));
diff --git a/libexec/rtld-aout/support.c b/libexec/rtld-aout/support.c
new file mode 100644
index 0000000..0d9df2a
--- /dev/null
+++ b/libexec/rtld-aout/support.c
@@ -0,0 +1,86 @@
+/*
+ * Generic "support" routines to replace those obtained from libiberty for ld.
+ *
+ * I've collected these from random bits of (published) code I've written
+ * over the years, not that they are a big deal. peter@freebsd.org
+ *-
+ * Copyright (C) 1996
+ * Peter Wemm. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *-
+ * $Id$
+ */
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+
+#include "support.h"
+
+char *
+concat(s1, s2, s3)
+ const char *s1, *s2, *s3;
+{
+ int len = 1;
+ char *s;
+ if (s1)
+ len += strlen(s1);
+ if (s2)
+ len += strlen(s2);
+ if (s3)
+ len += strlen(s3);
+ s = xmalloc(len);
+ s[0] = '\0';
+ if (s1)
+ strcat(s, s1);
+ if (s2)
+ strcat(s, s2);
+ if (s3)
+ strcat(s, s3);
+ return s;
+}
+
+void *
+xmalloc(n)
+ size_t n;
+{
+ char *p = malloc(n);
+
+ if (p == NULL)
+ errx(1, "Could not allocate memory");
+
+ return p;
+}
+
+void *
+xrealloc(p, n)
+ void *p;
+ size_t n;
+{
+ p = realloc(p, n);
+
+ if (p == NULL)
+ errx(1, "Could not allocate memory");
+
+ return p;
+}
diff --git a/libexec/rtld-aout/support.h b/libexec/rtld-aout/support.h
new file mode 100644
index 0000000..5be1e31
--- /dev/null
+++ b/libexec/rtld-aout/support.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (C) 1996
+ * Peter Wemm. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *-
+ * $Id$
+ */
+
+/*
+ * prototypes for support.c. Big deal.
+ */
+
+void *xmalloc __P((size_t));
+void *xrealloc __P((void *, size_t));
+char *concat __P((const char *, const char *, const char *));
OpenPOWER on IntegriCloud