aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/ld/rrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/ld/rrs.c')
-rw-r--r--gnu/usr.bin/ld/rrs.c1174
1 files changed, 1174 insertions, 0 deletions
diff --git a/gnu/usr.bin/ld/rrs.c b/gnu/usr.bin/ld/rrs.c
new file mode 100644
index 000000000000..050fcd6552ea
--- /dev/null
+++ b/gnu/usr.bin/ld/rrs.c
@@ -0,0 +1,1174 @@
+/*
+ * 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: rrs.c,v 1.11 1994/02/13 20:41:40 jkh Exp $
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+#include <strings.h>
+
+#include "ld.h"
+
+static struct _dynamic rrs_dyn; /* defined in link.h */
+static struct so_debug rrs_so_debug; /* defined in link.h */
+static struct section_dispatch_table rrs_sdt; /* defined in link.h */
+static got_t *rrs_got;
+static jmpslot_t *rrs_plt; /* defined in md.h */
+static struct relocation_info *rrs_reloc;
+static struct nzlist *rrs_symbols; /* RRS symbol table */
+static char *rrs_strtab; /* RRS strings */
+static struct rrs_hash *rrs_hashtab; /* RT hash table */
+static struct shobj *rrs_shobjs;
+
+static int reserved_rrs_relocs;
+static int claimed_rrs_relocs;
+
+static int number_of_gotslots;
+static int number_of_jmpslots;
+static int number_of_rrs_hash_entries;
+static int number_of_rrs_symbols;
+static int rrs_strtab_size;
+static int rrs_symbol_size;
+
+static int current_jmpslot_offset;
+static int current_got_offset;
+static int current_reloc_offset;
+static int current_hash_index;
+int number_of_shobjs;
+
+struct shobj {
+ struct shobj *next;
+ struct file_entry *entry;
+};
+
+/*
+RRS text segment:
+ +-------------------+ <-- sdt_rel (rrs_text_start)
+ | |
+ | relocation |
+ | |
+ +-------------------+ <-- <sdt>.sdt_hash
+ | |
+ | hash buckets |
+ | |
+ +-------------------+ <-- <sdt>.sdt_nzlist
+ | |
+ | symbols |
+ | |
+ +-------------------+ <-- <sdt>.sdt_strings
+ | |
+ | strings |
+ | |
+ +-------------------+ <-- <sdt>.sdt_sods
+ | |
+ | shobjs |
+ | |
+ +-------------------+
+ | |
+ | shobjs strings | <-- <shobj>.sod_name
+ | |
+ +-------------------+
+
+
+RRS data segment:
+
+ +-------------------+ <-- __DYNAMIC (rrs_data_start)
+ | |
+ | _dymamic |
+ | |
+ +-------------------+ <-- __DYNAMIC.d_debug
+ | |
+ | so_debug |
+ | |
+ +-------------------+ <-- __DYNAMIC.d_un.d_sdt
+ | |
+ | sdt |
+ | |
+ +-------------------+ <-- _GLOBAL_OFFSET_TABLE_ (sdt_got)
+ | |
+ | _GOT_ |
+ | |
+ +-------------------+ <-- sdt_plt
+ | |
+ | PLT |
+ | |
+ +-------------------+
+*/
+
+/*
+ * Initialize RRS
+ */
+
+void
+init_rrs()
+{
+ reserved_rrs_relocs = 0;
+ claimed_rrs_relocs = 0;
+
+ number_of_rrs_symbols = 0;
+ rrs_strtab_size = 0;
+
+ /* First jmpslot reserved for run-time binder */
+ current_jmpslot_offset = sizeof(jmpslot_t);
+ number_of_jmpslots = 1;
+
+ /* First gotslot reserved for __DYNAMIC */
+ current_got_offset = sizeof(got_t);
+ number_of_gotslots = 1;
+
+ current_reloc_offset = 0;
+}
+
+/*
+ * Add NAME to the list of needed run-time objects.
+ * Return 1 if ENTRY was added to the list.
+ */
+int
+rrs_add_shobj(entry)
+struct file_entry *entry;
+{
+ struct shobj **p;
+
+ for (p = &rrs_shobjs; *p != NULL; p = &(*p)->next)
+ if (strcmp((*p)->entry->filename, entry->filename) == 0)
+ return 0;
+ *p = (struct shobj *)xmalloc(sizeof(struct shobj));
+ (*p)->next = NULL;
+ (*p)->entry = entry;
+
+ number_of_shobjs++;
+ return 1;
+}
+
+void
+alloc_rrs_reloc(entry, sp)
+struct file_entry *entry;
+symbol *sp;
+{
+#ifdef DEBUG
+printf("alloc_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry));
+#endif
+ reserved_rrs_relocs++;
+}
+
+void
+alloc_rrs_segment_reloc(entry, r)
+struct file_entry *entry;
+struct relocation_info *r;
+{
+#ifdef DEBUG
+printf("alloc_rrs_segment_reloc at %#x in %s\n",
+ r->r_address, get_file_name(entry));
+#endif
+ reserved_rrs_relocs++;
+}
+
+void
+alloc_rrs_jmpslot(entry, sp)
+struct file_entry *entry;
+symbol *sp;
+{
+ if (sp->jmpslot_offset == -1) {
+ sp->jmpslot_offset = current_jmpslot_offset;
+ current_jmpslot_offset += sizeof(jmpslot_t);
+ number_of_jmpslots++;
+ if (!(link_mode & SYMBOLIC) || JMPSLOT_NEEDS_RELOC) {
+ reserved_rrs_relocs++;
+ }
+ }
+}
+
+void
+alloc_rrs_gotslot(entry, r, lsp)
+struct file_entry *entry;
+struct relocation_info *r;
+struct localsymbol *lsp;
+{
+ symbol *sp = lsp->symbol;
+
+ if (!RELOC_EXTERN_P(r)) {
+
+ if (sp != NULL) {
+ error("%s: relocation for internal symbol expected at %#x",
+ get_file_name(entry), RELOC_ADDRESS(r));
+ return;
+ }
+
+ if (!RELOC_STATICS_THROUGH_GOT_P(r))
+ /* No need for a GOT slot */
+ return;
+
+ if (lsp->gotslot_offset == -1) {
+ lsp->gotslot_offset = current_got_offset;
+ current_got_offset += sizeof(got_t);
+ number_of_gotslots++;
+ /*
+ * Now, see if slot needs run-time fixing
+ * If the load address is known (entry_symbol), this
+ * slot will have its final value set by `claim_got'
+ */
+ if ((link_mode & SHAREABLE) || (link_mode & SYMBOLIC))
+ reserved_rrs_relocs++;
+ }
+
+ } else {
+
+ if (sp == NULL) {
+ error("%s: relocation must refer to global symbol at %#x",
+ get_file_name(entry), RELOC_ADDRESS(r));
+ return;
+ }
+
+ if (sp->alias)
+ sp = sp->alias;
+
+ if (sp->gotslot_offset != -1)
+ return;
+
+ /*
+ * External symbols always get a relocation entry
+ */
+ sp->gotslot_offset = current_got_offset;
+ reserved_rrs_relocs++;
+ current_got_offset += sizeof(got_t);
+ number_of_gotslots++;
+ }
+
+}
+
+void
+alloc_rrs_cpy_reloc(entry, sp)
+struct file_entry *entry;
+symbol *sp;
+{
+ if (sp->flags & GS_CPYRELOCRESERVED)
+ return;
+#ifdef DEBUG
+printf("alloc_rrs_copy: %s in %s\n", sp->name, get_file_name(entry));
+#endif
+ sp->flags |= GS_CPYRELOCRESERVED;
+ reserved_rrs_relocs++;
+}
+
+static struct relocation_info *
+rrs_next_reloc()
+{
+ struct relocation_info *r;
+
+ r = rrs_reloc + claimed_rrs_relocs++;
+ if (claimed_rrs_relocs > reserved_rrs_relocs)
+ fatal("internal error: RRS relocs exceed allocation %d",
+ reserved_rrs_relocs);
+ return r;
+}
+
+/*
+ * Claim a RRS relocation as a result of a regular (ie. non-PIC)
+ * relocation record in a rel file.
+ *
+ * Return 1 if the output file needs no further updating.
+ * Return 0 if the relocation value pointed to by RELOCATION must
+ * written to a.out.
+ */
+int
+claim_rrs_reloc(entry, rp, sp, relocation)
+struct file_entry *entry;
+struct relocation_info *rp;
+symbol *sp;
+long *relocation;
+{
+ struct relocation_info *r = rrs_next_reloc();
+
+ if (rp->r_address < text_start + text_size)
+ error("%s: RRS text relocation at %#x for \"%s\"",
+ get_file_name(entry), rp->r_address, sp->name);
+
+#ifdef DEBUG
+printf("claim_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry));
+#endif
+ r->r_address = rp->r_address;
+ r->r_symbolnum = sp->rrs_symbolnum;
+
+ if (link_mode & SYMBOLIC) {
+ if (!sp->defined)
+ error("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+ RELOC_EXTERN_P(r) = 0;
+ *relocation += sp->value;
+ (void) md_make_reloc(rp, r, RELTYPE_RELATIVE);
+ return 0;
+ } else {
+ RELOC_EXTERN_P(r) = 1;
+ return md_make_reloc(rp, r, RELTYPE_EXTERN);
+ }
+}
+
+/*
+ * Claim a jmpslot. Setup RRS relocation if claimed for the first time.
+ */
+long
+claim_rrs_jmpslot(entry, rp, sp, addend)
+struct file_entry *entry;
+struct relocation_info *rp;
+symbol *sp;
+long addend;
+{
+ struct relocation_info *r;
+
+ if (sp->flags & GS_JMPSLOTCLAIMED)
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+
+#ifdef DEBUG
+printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x (textreloc %#x)\n",
+ get_file_name(entry),
+ sp->name, sp->rrs_symbolnum, sp->jmpslot_offset, text_relocation);
+#endif
+
+ if (sp->jmpslot_offset == -1)
+ fatal(
+ "internal error: %s: claim_rrs_jmpslot: %s: jmpslot_offset == -1\n",
+ get_file_name(entry),
+ sp->name);
+
+ if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
+ if (!sp->defined)
+ error("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+
+ md_fix_jmpslot( rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
+ rrs_sdt.sdt_plt + sp->jmpslot_offset,
+ sp->value);
+ if (!JMPSLOT_NEEDS_RELOC) {
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+ }
+ } else {
+ md_make_jmpslot(rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
+ sp->jmpslot_offset,
+ claimed_rrs_relocs);
+ }
+
+ if (rrs_section_type == RRS_PARTIAL)
+ /* PLT is self-contained */
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+
+ /*
+ * Install a run-time relocation for this PLT entry.
+ */
+ r = rrs_next_reloc();
+ sp->flags |= GS_JMPSLOTCLAIMED;
+
+ RELOC_SYMBOL(r) = sp->rrs_symbolnum;
+
+ r->r_address = (long)rrs_sdt.sdt_plt + sp->jmpslot_offset;
+
+ if (link_mode & SYMBOLIC) {
+ RELOC_EXTERN_P(r) = 0;
+ md_make_jmpreloc(rp, r, RELTYPE_RELATIVE);
+ } else {
+ RELOC_EXTERN_P(r) = 1;
+ md_make_jmpreloc(rp, r, 0);
+ }
+
+ return rrs_sdt.sdt_plt + sp->jmpslot_offset;
+}
+
+/*
+ * Claim GOT entry for a global symbol. If this is the first relocation
+ * claiming the entry, setup a RRS relocation for it.
+ * Return offset into the GOT allocated to this symbol.
+ */
+long
+claim_rrs_gotslot(entry, rp, lsp, addend)
+struct file_entry *entry;
+struct relocation_info *rp;
+struct localsymbol *lsp;
+long addend;
+{
+ struct relocation_info *r;
+ symbol *sp = lsp->symbol;
+ int reloc_type = 0;
+
+ if (sp == NULL) {
+ return 0;
+ }
+
+ if (sp->alias)
+ sp = sp->alias;
+
+#ifdef DEBUG
+printf("claim_rrs_gotslot: %s(%d) slot offset %#x, addend %#x\n",
+ sp->name, sp->rrs_symbolnum, sp->gotslot_offset, addend);
+#endif
+ if (sp->gotslot_offset == -1)
+ fatal(
+ "internal error: %s: claim_rrs_gotslot: %s: gotslot_offset == -1\n",
+ get_file_name(entry), sp->name);
+
+ if (sp->flags & GS_GOTSLOTCLAIMED)
+ /* This symbol already passed here before. */
+ return sp->gotslot_offset;
+
+ if (sp->defined &&
+ (!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))) {
+
+ /*
+ * Reduce to just a base-relative translation.
+ */
+
+ *(got_t *)((long)rrs_got + sp->gotslot_offset) =
+ sp->value + addend;
+ reloc_type = RELTYPE_RELATIVE;
+
+ } else if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
+ /*
+ * SYMBOLIC: all symbols must be known.
+ * RRS_PARTIAL: we don't link against shared objects,
+ * so again all symbols must be known.
+ */
+ error("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+
+ } else {
+
+ /*
+ * This gotslot will be updated with symbol value at run-rime.
+ */
+
+ *(got_t *)((long)rrs_got + sp->gotslot_offset) = addend;
+ }
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ /*
+ * Base address is known, gotslot should be fully
+ * relocated by now.
+ * NOTE: RRS_PARTIAL implies !SHAREABLE.
+ */
+ if (!sp->defined)
+ error("Cannot reduce symbol \"%s\" in %s",
+ sp->name, get_file_name(entry));
+ return sp->gotslot_offset;
+ }
+
+ /*
+ * Claim a relocation entry.
+ * If symbol is defined and in "main" (!SHAREABLE)
+ * we still put out a relocation as we cannot easily
+ * undo the allocation.
+ * `RELTYPE_RELATIVE' relocations have the external bit off
+ * as no symbol need be looked up at run-time.
+ */
+ r = rrs_next_reloc();
+ sp->flags |= GS_GOTSLOTCLAIMED;
+ r->r_address = rrs_sdt.sdt_got + sp->gotslot_offset;
+ RELOC_SYMBOL(r) = sp->rrs_symbolnum;
+ RELOC_EXTERN_P(r) = !(reloc_type == RELTYPE_RELATIVE);
+ md_make_gotreloc(rp, r, reloc_type);
+
+ return sp->gotslot_offset;
+}
+
+/*
+ * Claim a GOT entry for a static symbol. Return offset of the
+ * allocated GOT entry. If RELOC_STATICS_THROUGH_GOT_P is in effect
+ * return the offset of the symbol with respect to the *location* of
+ * the GOT.
+ */
+long
+claim_rrs_internal_gotslot(entry, rp, lsp, addend)
+struct file_entry *entry;
+struct relocation_info *rp;
+struct localsymbol *lsp;
+long addend;
+{
+ struct relocation_info *r;
+
+ addend += lsp->nzlist.nz_value;
+
+ if (!RELOC_STATICS_THROUGH_GOT_P(r))
+ return addend - rrs_sdt.sdt_got;
+
+#ifdef DEBUG
+printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n",
+ get_file_name(entry), lsp->gotslot_offset, addend);
+#endif
+
+ if (lsp->gotslot_offset == -1)
+ fatal(
+ "internal error: %s: claim_rrs_internal_gotslot at %#x: slot_offset == -1\n",
+ get_file_name(entry), RELOC_ADDRESS(rp));
+
+ if (lsp->flags & LS_GOTSLOTCLAIMED)
+ /* Already done */
+ return lsp->gotslot_offset;
+
+ *(long *)((long)rrs_got + lsp->gotslot_offset) = addend;
+
+ if (!(link_mode & SHAREABLE))
+ return lsp->gotslot_offset;
+
+ /*
+ * Relocation entry needed for this static GOT entry.
+ */
+ r = rrs_next_reloc();
+ lsp->flags |= LS_GOTSLOTCLAIMED;
+ r->r_address = rrs_sdt.sdt_got + lsp->gotslot_offset;
+ RELOC_EXTERN_P(r) = 0;
+ md_make_gotreloc(rp, r, RELTYPE_RELATIVE);
+ return lsp->gotslot_offset;
+}
+
+void
+claim_rrs_cpy_reloc(entry, rp, sp)
+struct file_entry *entry;
+struct relocation_info *rp;
+symbol *sp;
+{
+ struct relocation_info *r;
+
+ if (sp->flags & GS_CPYRELOCCLAIMED)
+ return;
+
+ if (!(sp->flags & GS_CPYRELOCRESERVED))
+ fatal("internal error: %s: claim_cpy_reloc: %s: no reservation\n",
+ get_file_name(entry), sp->name);
+
+#ifdef DEBUG
+printf("claim_rrs_copy: %s: %s -> %x\n",
+ get_file_name(entry), sp->name, sp->so_defined);
+#endif
+
+ r = rrs_next_reloc();
+ sp->flags |= GS_CPYRELOCCLAIMED;
+ r->r_address = rp->r_address;
+ RELOC_SYMBOL(r) = sp->rrs_symbolnum;
+ RELOC_EXTERN_P(r) = RELOC_EXTERN_P(rp);
+ md_make_cpyreloc(rp, r);
+}
+
+void
+claim_rrs_segment_reloc(entry, rp)
+struct file_entry *entry;
+struct relocation_info *rp;
+{
+ struct relocation_info *r = rrs_next_reloc();
+
+#ifdef DEBUG
+printf("claim_rrs_segment_reloc: %s at %#x\n",
+ get_file_name(entry), rp->r_address);
+#endif
+ r->r_address = rp->r_address;
+ RELOC_TYPE(r) = RELOC_TYPE(rp);
+ RELOC_EXTERN_P(r) = 0;
+ md_make_reloc(rp, r, RELTYPE_RELATIVE);
+
+}
+
+/*
+ * Fill the RRS hash table for the given symbol name.
+ * NOTE: the hash value computation must match the one in rtld.
+ */
+void
+rrs_insert_hash(cp, index)
+char *cp;
+int index;
+{
+ int hashval = 0;
+ struct rrs_hash *hp;
+
+ for (; *cp; cp++)
+ hashval = (hashval << 1) + *cp;
+
+ hashval = (hashval & 0x7fffffff) % rrs_sdt.sdt_buckets;
+
+ /* Get to the bucket */
+ hp = rrs_hashtab + hashval;
+ if (hp->rh_symbolnum == -1) {
+ /* Empty bucket, use it */
+ hp->rh_symbolnum = index;
+ hp->rh_next = 0;
+ return;
+ }
+
+ while (hp->rh_next != 0)
+ hp = rrs_hashtab + hp->rh_next;
+
+ hp->rh_next = current_hash_index++;
+ hp = rrs_hashtab + hp->rh_next;
+ hp->rh_symbolnum = index;
+ hp->rh_next = 0;
+}
+
+/*
+ * There are two interesting cases to consider here.
+ *
+ * 1) No shared objects were loaded, but there were PIC input rel files.
+ * In this case we must output a _GLOBAL_OFFSET_TABLE_ but no other
+ * RRS data. Also, the entries in the GOT must be fully resolved.
+ *
+ * 2) It's a genuine dynamically linked program, so the whole RRS scoop
+ * goes into a.out.
+ */
+void
+consider_rrs_section_lengths()
+{
+ int n;
+ struct shobj *shp, **shpp;
+ int symbolsize;
+
+#ifdef notyet
+/* We run into trouble with this as long as shared object symbols
+ are not checked for definitions */
+ /*
+ * First, determine the real number of shared objects we need.
+ */
+ for (shpp = &rrs_shobjs; *shpp; shpp = &(*shpp)->next) {
+ while (*shpp && !((*shpp)->entry->flags & E_SYMBOLS_USED)) {
+ if (--number_of_shobjs < 0)
+ fatal("internal error: number_of_shobjs < 0");
+ *shpp = (*shpp)->next;
+ }
+ if (*shpp == NULL)
+ break;
+ }
+#endif
+
+ /* First, determine what of the RRS we want */
+ if (relocatable_output)
+ rrs_section_type = RRS_NONE;
+ else if (link_mode & SHAREABLE)
+ rrs_section_type = RRS_FULL;
+ else if (number_of_shobjs == 0 /*&& !(link_mode & DYNAMIC)*/) {
+ /*
+ * First slots in both tables are reserved
+ * hence the "> 1" condition
+ */
+ if (number_of_gotslots > 1 || number_of_jmpslots > 1)
+ rrs_section_type = RRS_PARTIAL;
+ else
+ rrs_section_type = RRS_NONE;
+ } else
+ rrs_section_type = RRS_FULL;
+
+ if (rrs_section_type == RRS_NONE) {
+ got_symbol->defined = 0;
+ return;
+ }
+
+ rrs_symbol_size = LD_VERSION_NZLIST_P(soversion) ?
+ sizeof(struct nzlist) : sizeof(struct nlist);
+
+ /*
+ * If there is an entry point, __DYNAMIC must be referenced (usually
+ * from crt0), as this is the method used to determine whether the
+ * run-time linker must be called.
+ */
+ if (!(link_mode & SHAREABLE) &&
+ !(dynamic_symbol->flags & GS_REFERENCED))
+ fatal("No reference to __DYNAMIC");
+
+ dynamic_symbol->flags |= GS_REFERENCED;
+
+ if (number_of_gotslots > 1)
+ got_symbol->flags |= GS_REFERENCED;
+
+
+ /* Next, allocate relocs, got and plt */
+ n = reserved_rrs_relocs * sizeof(struct relocation_info);
+ rrs_reloc = (struct relocation_info *)xmalloc(n);
+ bzero(rrs_reloc, n);
+
+ n = number_of_gotslots * sizeof(got_t);
+ rrs_got = (got_t *)xmalloc(n);
+ bzero(rrs_got, n);
+
+ n = number_of_jmpslots * sizeof(jmpslot_t);
+ rrs_plt = (jmpslot_t *)xmalloc(n);
+ bzero(rrs_plt, n);
+
+ /* Initialize first jmpslot */
+ md_fix_jmpslot(rrs_plt, 0, 0);
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ rrs_data_size = number_of_gotslots * sizeof(got_t);
+ rrs_data_size += number_of_jmpslots * sizeof(jmpslot_t);
+ return;
+ }
+
+ /*
+ * Walk the symbol table, assign RRS symbol numbers
+ * Assign number 0 to __DYNAMIC (!! Sun compatibility)
+ */
+ dynamic_symbol->rrs_symbolnum = number_of_rrs_symbols++;
+ FOR_EACH_SYMBOL(i ,sp) {
+ if (sp->flags & GS_REFERENCED) {
+ rrs_strtab_size += 1 + strlen(sp->name);
+ if (sp != dynamic_symbol)
+ sp->rrs_symbolnum = number_of_rrs_symbols++;
+ if (sp->alias) {
+ /*
+ * (sigh) Always allocate space to hold the
+ * indirection. At this point there's not
+ * enough information to decide whether it's
+ * actually needed or not.
+ */
+ number_of_rrs_symbols++;
+ rrs_strtab_size += 1 + strlen(sp->alias->name);
+ }
+ }
+ } END_EACH_SYMBOL;
+
+ /*
+ * Now that we know how many RRS symbols there are going to be,
+ * allocate and initialize the RRS symbol hash table.
+ */
+ rrs_sdt.sdt_buckets = number_of_rrs_symbols/4;
+ if (rrs_sdt.sdt_buckets < 4)
+ rrs_sdt.sdt_buckets = 4;
+
+ number_of_rrs_hash_entries = rrs_sdt.sdt_buckets + number_of_rrs_symbols;
+ rrs_hashtab = (struct rrs_hash *)xmalloc(
+ number_of_rrs_hash_entries * sizeof(struct rrs_hash));
+ for (n = 0; n < rrs_sdt.sdt_buckets; n++)
+ rrs_hashtab[n].rh_symbolnum = -1;
+ current_hash_index = rrs_sdt.sdt_buckets;
+
+ /*
+ * Get symbols into hash table now, so we can fine tune the size
+ * of the latter. We adjust the value of `number_of_rrs_hash_entries'
+ * to the number of hash link slots actually used.
+ */
+ FOR_EACH_SYMBOL(i ,sp) {
+ if (sp->flags & GS_REFERENCED)
+ rrs_insert_hash(sp->name, sp->rrs_symbolnum);
+ } END_EACH_SYMBOL;
+ number_of_rrs_hash_entries = current_hash_index;
+
+ /*
+ * Calculate RRS section sizes.
+ */
+ rrs_data_size = sizeof(struct _dynamic);
+ rrs_data_size += sizeof(struct so_debug);
+ rrs_data_size += sizeof(struct section_dispatch_table);
+ rrs_data_size += number_of_gotslots * sizeof(got_t);
+ rrs_data_size += number_of_jmpslots * sizeof(jmpslot_t);
+ rrs_data_size = MALIGN(rrs_data_size);
+
+ rrs_text_size = reserved_rrs_relocs * sizeof(struct relocation_info);
+ rrs_text_size += number_of_rrs_hash_entries * sizeof(struct rrs_hash);
+ rrs_text_size += number_of_rrs_symbols * rrs_symbol_size;
+
+ /* Align strings size */
+ rrs_strtab_size = MALIGN(rrs_strtab_size);
+ rrs_text_size += rrs_strtab_size;
+
+ /* Process needed shared objects */
+ for (shp = rrs_shobjs; shp; shp = shp->next) {
+ char *name = shp->entry->local_sym_name;
+
+ if (*name == '-' && *(name+1) == 'l')
+ name += 2;
+
+ rrs_text_size += sizeof(struct sod);
+ rrs_text_size += 1 + strlen(name);
+ }
+
+ /* Finally, align size */
+ rrs_text_size = MALIGN(rrs_text_size);
+}
+
+void
+relocate_rrs_addresses()
+{
+
+ dynamic_symbol->value = 0;
+
+ if (rrs_section_type == RRS_NONE)
+ return;
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ got_symbol->value = rrs_sdt.sdt_got = rrs_data_start;
+ rrs_sdt.sdt_plt = rrs_sdt.sdt_got +
+ number_of_gotslots * sizeof(got_t);
+ return;
+ }
+
+ /*
+ * RRS data relocations.
+ */
+ rrs_dyn.d_version = soversion;
+ rrs_dyn.d_debug = (struct so_debug *)
+ (rrs_data_start + sizeof(struct _dynamic));
+ rrs_dyn.d_un.d_sdt = (struct section_dispatch_table *)
+ ((long)rrs_dyn.d_debug + sizeof(struct so_debug));
+
+ rrs_sdt.sdt_got = (long)rrs_dyn.d_un.d_sdt +
+ sizeof(struct section_dispatch_table);
+ rrs_sdt.sdt_plt = rrs_sdt.sdt_got + number_of_gotslots*sizeof(got_t);
+
+ /*
+ * RRS text relocations.
+ */
+ rrs_sdt.sdt_rel = rrs_text_start;
+ /*
+ * Sun BUG compatibility alert.
+ * Main program's RRS text values are relative to TXTADDR? WHY??
+ */
+#ifdef SUN_COMPAT
+ if (soversion == LD_VERSION_SUN && !(link_mode & SHAREABLE))
+ rrs_sdt.sdt_rel -= N_TXTADDR(outheader);
+#endif
+
+ rrs_sdt.sdt_hash = rrs_sdt.sdt_rel +
+ reserved_rrs_relocs * sizeof(struct relocation_info);
+ rrs_sdt.sdt_nzlist = rrs_sdt.sdt_hash +
+ number_of_rrs_hash_entries * sizeof(struct rrs_hash);
+ rrs_sdt.sdt_strings = rrs_sdt.sdt_nzlist +
+ number_of_rrs_symbols * rrs_symbol_size;
+ rrs_sdt.sdt_str_sz = rrs_strtab_size;
+ rrs_sdt.sdt_text_sz = text_size;
+ rrs_sdt.sdt_plt_sz = number_of_jmpslots * sizeof(jmpslot_t);
+
+ rrs_sdt.sdt_sods = rrs_shobjs ? rrs_sdt.sdt_strings+rrs_strtab_size : 0;
+ rrs_sdt.sdt_filler1 = 0;
+ rrs_sdt.sdt_filler2 = 0;
+
+ /*
+ * Assign addresses to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC
+ * &__DYNAMIC is also in the first GOT entry.
+ */
+ got_symbol->value = rrs_sdt.sdt_got;
+
+ *rrs_got = dynamic_symbol->value = rrs_data_start;
+
+}
+
+void
+write_rrs_data()
+{
+ long pos;
+
+ if (rrs_section_type == RRS_NONE)
+ return;
+
+ pos = rrs_data_start + (N_DATOFF(outheader) - DATA_START(outheader));
+ if (lseek(outdesc, pos, L_SET) != pos)
+ fatal("write_rrs_data: cant position in output file");
+
+ if (rrs_section_type == RRS_PARTIAL) {
+ /*
+ * Only a GOT and PLT are needed.
+ */
+ if (number_of_gotslots <= 1)
+ fatal("write_rrs_data: # gotslots <= 1");
+
+ md_swapout_got(rrs_got, number_of_gotslots);
+ mywrite(rrs_got, number_of_gotslots,
+ sizeof(got_t), outdesc);
+
+ if (number_of_jmpslots <= 1)
+ fatal("write_rrs_data: # jmpslots <= 1");
+
+ md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
+ mywrite(rrs_plt, number_of_jmpslots,
+ sizeof(jmpslot_t), outdesc);
+ return;
+ }
+
+ md_swapout__dynamic(&rrs_dyn);
+ mywrite(&rrs_dyn, 1, sizeof(struct _dynamic), outdesc);
+
+ md_swapout_so_debug(&rrs_so_debug);
+ mywrite(&rrs_so_debug, 1, sizeof(struct so_debug), outdesc);
+
+ md_swapout_section_dispatch_table(&rrs_sdt);
+ mywrite(&rrs_sdt, 1, sizeof(struct section_dispatch_table), outdesc);
+
+ md_swapout_got(rrs_got, number_of_gotslots);
+ mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outdesc);
+
+ md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
+ mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outdesc);
+}
+
+void
+write_rrs_text()
+{
+ long pos;
+ int i;
+ int symsize;
+ struct nzlist *nlp;
+ int offset = 0;
+ struct shobj *shp;
+ struct sod *sodp;
+
+ if (rrs_section_type == RRS_PARTIAL)
+ return;
+
+ pos = rrs_text_start + (N_TXTOFF(outheader) - TEXT_START(outheader));
+ if (lseek(outdesc, pos, L_SET) != pos)
+ fatal("write_rrs_text: cant position in output file");
+
+ /* Write relocation records */
+ md_swapout_reloc(rrs_reloc, reserved_rrs_relocs);
+ mywrite(rrs_reloc, reserved_rrs_relocs,
+ sizeof(struct relocation_info), outdesc);
+
+ /* Write the RRS symbol hash tables */
+ md_swapout_rrs_hash(rrs_hashtab, number_of_rrs_hash_entries);
+ mywrite(rrs_hashtab, number_of_rrs_hash_entries, sizeof(struct rrs_hash), outdesc);
+
+ /*
+ * Determine size of an RRS symbol entry, allocate space
+ * to collect them in.
+ */
+ symsize = number_of_rrs_symbols * rrs_symbol_size;
+ nlp = rrs_symbols = (struct nzlist *)alloca(symsize);
+ rrs_strtab = (char *)alloca(rrs_strtab_size);
+
+#define INCR_NLP(p) ((p) = (struct nzlist *)((long)(p) + rrs_symbol_size))
+
+ /* __DYNAMIC symbol *must* be first for Sun compatibility */
+ nlp->nz_desc = nlp->nz_other = 0;
+ if (LD_VERSION_NZLIST_P(soversion))
+ nlp->nz_size = 0;
+ nlp->nz_type = dynamic_symbol->defined;
+ nlp->nz_value = dynamic_symbol->value;
+ nlp->nz_value = dynamic_symbol->value;
+ nlp->nz_strx = offset;
+ strcpy(rrs_strtab + offset, dynamic_symbol->name);
+ offset += 1 + strlen(dynamic_symbol->name);
+ INCR_NLP(nlp);
+
+ /*
+ * Now, for each global symbol, construct a nzlist element
+ * for inclusion in the RRS symbol table.
+ */
+ FOR_EACH_SYMBOL(i, sp) {
+
+ if (!(sp->flags & GS_REFERENCED) || sp == dynamic_symbol)
+ continue;
+
+ if ((long)nlp - (long)rrs_symbols >=
+ number_of_rrs_symbols * rrs_symbol_size)
+ fatal(
+ "internal error: rrs symbols exceed allocation %d ",
+ number_of_rrs_symbols);
+
+ nlp->nz_desc = 0;
+ nlp->nz_other = 0;
+ if (LD_VERSION_NZLIST_P(soversion))
+ nlp->nz_size = 0;
+
+ if (sp->defined > 1) {
+ /* defined with known type */
+ if (!(link_mode & SHAREABLE) &&
+ sp->alias && sp->alias->defined > 1) {
+ /*
+ * If the target of an indirect symbol has
+ * been defined and we are outputting an
+ * executable, resolve the indirection; it's
+ * no longer needed.
+ */
+ nlp->nz_type = sp->alias->defined;
+ nlp->nz_value = sp->alias->value;
+ nlp->nz_other = N_OTHER(0, sp->alias->aux);
+ } else if (sp->defined == N_SIZE) {
+ /*
+ * Make sure this symbol isn't going
+ * to define anything.
+ */
+ nlp->nz_type = N_UNDF;
+ nlp->nz_value = 0;
+ } else {
+ nlp->nz_type = sp->defined;
+ nlp->nz_value = sp->value;
+ nlp->nz_other = N_OTHER(0, sp->aux);
+ }
+ if (LD_VERSION_NZLIST_P(soversion))
+ nlp->nz_size = sp->size;
+ } else if (sp->common_size) {
+ /*
+ * a common definition
+ */
+ nlp->nz_type = N_UNDF | N_EXT;
+ nlp->nz_value = sp->common_size;
+ } else if (!sp->defined) {
+ /* undefined */
+ nlp->nz_type = N_UNDF | N_EXT;
+ nlp->nz_value = 0;
+ if (sp->so_defined && sp->jmpslot_offset != -1) {
+ /*
+ * Define a "weak" function symbol.
+ */
+ if (sp->aux != AUX_FUNC)
+ fatal("%s: non-function jmpslot",
+ sp->name);
+ nlp->nz_other = N_OTHER(0, sp->aux);
+ nlp->nz_value =
+ rrs_sdt.sdt_plt + sp->jmpslot_offset;
+ }
+ } else
+ fatal(
+ "internal error: %s defined in mysterious way",
+ sp->name);
+
+ /* Set symbol's name */
+ nlp->nz_strx = offset;
+ strcpy(rrs_strtab + offset, sp->name);
+ offset += 1 + strlen(sp->name);
+
+ if (sp->alias) {
+ /*
+ * Write an extra symbol for indirections (possibly
+ * just a dummy).
+ */
+ int t = (nlp->nz_type == N_INDR + N_EXT);
+
+ INCR_NLP(nlp);
+ nlp->nz_type = N_UNDF + t?N_EXT:0;
+ nlp->nz_un.n_strx = offset;
+ nlp->nz_value = 0;
+ nlp->nz_other = 0;
+ nlp->nz_desc = 0;
+ nlp->nz_size = 0;
+ strcpy(rrs_strtab + offset, sp->alias->name);
+ offset += 1 + strlen(sp->alias->name);
+ }
+
+ INCR_NLP(nlp);
+
+ } END_EACH_SYMBOL;
+
+ if (MALIGN(offset) != rrs_strtab_size)
+ fatal(
+ "internal error: inconsistent RRS string table length: %d, expected %d",
+ offset, rrs_strtab_size);
+
+ /* Write the symbol table */
+ if (rrs_symbol_size == sizeof(struct nlist))
+ md_swapout_symbols(rrs_symbols, number_of_rrs_symbols);
+ else
+ md_swapout_zsymbols(rrs_symbols, number_of_rrs_symbols);
+ mywrite(rrs_symbols, symsize, 1, outdesc);
+
+ /* Write the strings */
+ mywrite(rrs_strtab, rrs_strtab_size, 1, outdesc);
+
+ /*
+ * Write the names of the shared objects needed at run-time
+ */
+ pos = rrs_sdt.sdt_sods + number_of_shobjs * sizeof(struct sod);
+ sodp = (struct sod *)alloca( number_of_shobjs * sizeof(struct sod));
+
+ for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) {
+ char *name = shp->entry->local_sym_name;
+
+ if (i >= number_of_shobjs)
+ fatal("internal error: # of link objects exceeds %d",
+ number_of_shobjs);
+
+ sodp[i].sod_name = pos;
+ sodp[i].sod_major = shp->entry->lib_major;
+ sodp[i].sod_minor = shp->entry->lib_minor;
+
+ if (*name == '-' && *(name+1) == 'l') {
+ name += 2;
+ sodp[i].sod_library = 1;
+ } else
+ sodp[i].sod_library = 0;
+
+ pos += 1 + strlen(name);
+ sodp[i].sod_next = (i == number_of_shobjs - 1) ? 0 :
+ (rrs_sdt.sdt_sods + (i+1)*sizeof(struct sod));
+ }
+
+ if (i < number_of_shobjs)
+ fatal("internal error: # of link objects less then expected %d",
+ number_of_shobjs);
+
+ md_swapout_sod(sodp, number_of_shobjs);
+ mywrite(sodp, number_of_shobjs, sizeof(struct sod), outdesc);
+
+ for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) {
+ char *name = shp->entry->local_sym_name;
+
+ if (*name == '-' && *(name+1) == 'l') {
+ name += 2;
+ }
+
+ mywrite(name, strlen(name) + 1, 1, outdesc);
+ }
+}
+
+void
+write_rrs()
+{
+
+ /*
+ * First, do some consistency checks on the RRS segment.
+ */
+ if (rrs_section_type == RRS_NONE) {
+ if (reserved_rrs_relocs > 1)
+ fatal(
+ "internal error: RRS relocs in static program: %d",
+ reserved_rrs_relocs-1);
+ return;
+ }
+
+#ifdef DEBUG
+printf("rrs_relocs %d, gotslots %d, jmpslots %d\n",
+ reserved_rrs_relocs, number_of_gotslots-1, number_of_jmpslots-1);
+#endif
+
+ if (claimed_rrs_relocs != reserved_rrs_relocs) {
+/*
+ fatal("internal error: reserved relocs(%d) != claimed(%d)",
+ reserved_rrs_relocs, claimed_rrs_relocs);
+*/
+ printf("FIX:internal error: reserved relocs(%d) != claimed(%d)\n",
+ reserved_rrs_relocs, claimed_rrs_relocs);
+ }
+
+ /* Write the RRS segments. */
+ write_rrs_text ();
+ write_rrs_data ();
+}