b9aa930e44
NetBSD ld code except for local changes for dlopen() and friends and the hashing on the minor value of the shlibs. We should be binary compatible now with all their libraries. Obtained from: NetBSD
1247 lines
32 KiB
C
1247 lines
32 KiB
C
/*
|
|
* 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.13 1994/12/23 22:30:48 nate 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <ar.h>
|
|
#include <ranlib.h>
|
|
#include <a.out.h>
|
|
#include <stab.h>
|
|
#include <string.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 discarded_rrs_relocs;
|
|
|
|
static int number_of_gotslots = 1;
|
|
static int number_of_jmpslots = 1;
|
|
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 got_origin;
|
|
static int current_reloc_offset;
|
|
static int current_hash_index;
|
|
int number_of_shobjs;
|
|
|
|
/* Convert a GOT offset into a table entry */
|
|
#define GOTP(off) ((got_t *)((long)rrs_got + got_origin + (off)))
|
|
|
|
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 |
|
|
| |
|
|
+-------------------+ <-- sdt_got
|
|
| |
|
|
| _GOT_ | <-- _GLOBAL_OFFSET_TABLE_
|
|
| | ( == sdt_got + got_origin)
|
|
| |
|
|
+-------------------+ <-- sdt_plt
|
|
| |
|
|
| PLT |
|
|
| |
|
|
+-------------------+
|
|
*/
|
|
|
|
/*
|
|
* 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->flags & GS_HASJMPSLOT)
|
|
return;
|
|
|
|
sp->flags |= GS_HASJMPSLOT;
|
|
number_of_jmpslots++;
|
|
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) {
|
|
warnx("%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->flags & LS_HASGOTSLOT)
|
|
return;
|
|
|
|
lsp->flags |= LS_HASGOTSLOT;
|
|
|
|
} else {
|
|
|
|
if (sp == NULL) {
|
|
warnx("%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->flags & GS_HASGOTSLOT)
|
|
return;
|
|
|
|
sp->flags |= GS_HASGOTSLOT;
|
|
}
|
|
|
|
number_of_gotslots++;
|
|
reserved_rrs_relocs++;
|
|
}
|
|
|
|
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)
|
|
errx(1, "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)
|
|
warnx("%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)
|
|
warnx("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_HASJMPSLOT))
|
|
errx(1, "internal error: "
|
|
"%s: claim_rrs_jmpslot: %s: no reservation",
|
|
get_file_name(entry),
|
|
sp->name);
|
|
|
|
if (sp->jmpslot_offset != -1)
|
|
return rrs_sdt.sdt_plt + sp->jmpslot_offset;
|
|
|
|
sp->jmpslot_offset = current_jmpslot_offset;
|
|
current_jmpslot_offset += sizeof(jmpslot_t);
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n",
|
|
get_file_name(entry),
|
|
sp->name, sp->rrs_symbolnum, sp->jmpslot_offset);
|
|
#endif
|
|
|
|
if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
|
|
if (!sp->defined)
|
|
warnx("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 (rrs_section_type == RRS_PARTIAL || !JMPSLOT_NEEDS_RELOC) {
|
|
/* PLT is self-contained */
|
|
discarded_rrs_relocs++;
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* Install a run-time relocation for this PLT entry.
|
|
*/
|
|
r = rrs_next_reloc();
|
|
|
|
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;
|
|
|
|
if (!(sp->flags & GS_HASGOTSLOT))
|
|
errx(1, "internal error: "
|
|
"%s: claim_rrs_gotslot: %s: no reservation",
|
|
get_file_name(entry), sp->name);
|
|
|
|
if (sp->gotslot_offset != -1) {
|
|
#ifdef DIAGNOSTIC
|
|
if (*GOTP(sp->gotslot_offset) != addend +
|
|
((!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))
|
|
? sp->value : 0))
|
|
errx(1, "%s: %s: gotslot at %#x is multiple valued, "
|
|
"*got = %#x, addend = %#x, sp->value = %#x",
|
|
get_file_name(entry), sp->name,
|
|
sp->gotslot_offset,
|
|
*GOTP(sp->gotslot_offset), addend, sp->value);
|
|
#endif
|
|
/* This symbol already passed here before. */
|
|
return sp->gotslot_offset;
|
|
}
|
|
|
|
if (current_got_offset == 0)
|
|
/* GOT offset 0 is reserved */
|
|
current_got_offset += sizeof(got_t);
|
|
|
|
if (current_got_offset > MAX_GOTOFF)
|
|
errx(1, "%s: GOT overflow on symbol `%s' at %#x",
|
|
get_file_name(entry), sp->name, RELOC_ADDRESS(rp));
|
|
|
|
sp->gotslot_offset = current_got_offset;
|
|
current_got_offset += sizeof(got_t);
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrs_gotslot: %s(%d,%#x) slot offset %#x, addend %#x\n",
|
|
sp->name, sp->rrs_symbolnum, sp->value, sp->gotslot_offset, addend);
|
|
#endif
|
|
|
|
if (sp->defined &&
|
|
(!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))) {
|
|
|
|
/*
|
|
* Reduce to just a base-relative translation.
|
|
*/
|
|
|
|
*GOTP(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.
|
|
*/
|
|
warnx("Cannot reduce symbol \"%s\" in %s",
|
|
sp->name, get_file_name(entry));
|
|
|
|
} else {
|
|
|
|
/*
|
|
* This gotslot will be updated with symbol value at run-time.
|
|
*/
|
|
|
|
*GOTP(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)
|
|
warnx("Cannot reduce symbol \"%s\" in %s",
|
|
sp->name, get_file_name(entry));
|
|
discarded_rrs_relocs++;
|
|
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();
|
|
r->r_address = got_symbol->value + 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 - got_symbol->value;
|
|
|
|
if (!(lsp->flags & LS_HASGOTSLOT))
|
|
errx(1, "internal error: "
|
|
"%s: claim_rrs_internal_gotslot at %#x: no reservation",
|
|
get_file_name(entry), RELOC_ADDRESS(rp));
|
|
|
|
if (lsp->gotslot_offset != -1) {
|
|
/* Already claimed */
|
|
if (*GOTP(lsp->gotslot_offset) != addend)
|
|
errx(1, "%s: gotslot at %#x is multiple valued",
|
|
get_file_name(entry), lsp->gotslot_offset);
|
|
return lsp->gotslot_offset;
|
|
}
|
|
|
|
if (current_got_offset == 0)
|
|
/* GOT offset 0 is reserved */
|
|
current_got_offset += sizeof(got_t);
|
|
|
|
if (current_got_offset > MAX_GOTOFF)
|
|
errx(1, "%s: GOT overflow for relocation at %#x",
|
|
get_file_name(entry), RELOC_ADDRESS(rp));
|
|
|
|
lsp->gotslot_offset = current_got_offset;
|
|
current_got_offset += sizeof(got_t);
|
|
|
|
*GOTP(lsp->gotslot_offset) = addend;
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n",
|
|
get_file_name(entry), lsp->gotslot_offset, addend);
|
|
#endif
|
|
|
|
if (rrs_section_type == RRS_PARTIAL) {
|
|
discarded_rrs_relocs++;
|
|
return lsp->gotslot_offset;
|
|
}
|
|
|
|
/*
|
|
* Relocation entry needed for this static GOT entry.
|
|
*/
|
|
r = rrs_next_reloc();
|
|
r->r_address = got_symbol->value + 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))
|
|
errx(1, "internal error: "
|
|
"%s: claim_cpy_reloc: %s: no reservation",
|
|
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;
|
|
|
|
#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)
|
|
errx(1, "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;
|
|
if (reserved_rrs_relocs > 0)
|
|
errx(1, "internal error: empty RRS has reservations");
|
|
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))
|
|
errx(1, "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
|
|
* and calculate string space.
|
|
* Assign number 0 to __DYNAMIC (!! Sun compatibility)
|
|
*/
|
|
dynamic_symbol->rrs_symbolnum = number_of_rrs_symbols++;
|
|
FOR_EACH_SYMBOL(i ,sp) {
|
|
if ((link_mode & SHAREABLE) && sp->warning) {
|
|
/* Allocate N_WARNING & co */
|
|
rrs_strtab_size +=
|
|
2 + strlen(sp->name) + strlen(sp->warning);
|
|
number_of_rrs_symbols += 2;
|
|
}
|
|
|
|
if (!(sp->flags & GS_REFERENCED))
|
|
continue;
|
|
|
|
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;
|
|
|
|
/*
|
|
* Get ready to allocate linkage table offsets.
|
|
* First jmpslot is reserved for the run-time binder
|
|
* GOT entry at offset 0 is reserved for `__DYNAMIC'.
|
|
*/
|
|
current_jmpslot_offset = sizeof(jmpslot_t);
|
|
current_got_offset = 0;
|
|
|
|
if (1 /* Not "-fPIC" seen */) {
|
|
int gotsize = number_of_gotslots * sizeof(got_t);
|
|
|
|
if (gotsize + MIN_GOTOFF - (int)sizeof(got_t) > MAX_GOTOFF)
|
|
warnx("Global Offset Table overflow");
|
|
if (gotsize > MAX_GOTOFF)
|
|
/* Position at "two-complements" origin */
|
|
current_got_offset += MIN_GOTOFF;
|
|
}
|
|
|
|
got_origin = -current_got_offset;
|
|
|
|
if (rrs_section_type == RRS_NONE)
|
|
return;
|
|
|
|
if (rrs_section_type == RRS_PARTIAL) {
|
|
rrs_sdt.sdt_got = rrs_data_start;
|
|
got_symbol->value = rrs_sdt.sdt_got + got_origin;
|
|
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.
|
|
* The value `&__DYNAMIC' is in the GOT table at offset 0.
|
|
*/
|
|
got_symbol->value = rrs_sdt.sdt_got + got_origin;
|
|
*GOTP(0) = 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 (fseek(outstream, pos, SEEK_SET) != 0)
|
|
err(1, "write_rrs_data: fseek");
|
|
|
|
if (rrs_section_type == RRS_PARTIAL) {
|
|
/*
|
|
* Only a GOT and PLT are needed.
|
|
*/
|
|
md_swapout_got(rrs_got, number_of_gotslots);
|
|
mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outstream);
|
|
|
|
md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
|
|
mywrite(rrs_plt, number_of_jmpslots,
|
|
sizeof(jmpslot_t), outstream);
|
|
|
|
return;
|
|
}
|
|
|
|
md_swapout__dynamic(&rrs_dyn);
|
|
mywrite(&rrs_dyn, 1, sizeof(struct _dynamic), outstream);
|
|
|
|
md_swapout_so_debug(&rrs_so_debug);
|
|
mywrite(&rrs_so_debug, 1, sizeof(struct so_debug), outstream);
|
|
|
|
md_swapout_section_dispatch_table(&rrs_sdt);
|
|
mywrite(&rrs_sdt, 1, sizeof(struct section_dispatch_table), outstream);
|
|
|
|
md_swapout_got(rrs_got, number_of_gotslots);
|
|
mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outstream);
|
|
|
|
md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
|
|
mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outstream);
|
|
}
|
|
|
|
void
|
|
write_rrs_text()
|
|
{
|
|
long pos;
|
|
int i;
|
|
int symsize;
|
|
struct nzlist *nlp;
|
|
int offset = 0;
|
|
struct shobj *shp;
|
|
struct sod *sodp;
|
|
int bind;
|
|
|
|
if (rrs_section_type == RRS_PARTIAL)
|
|
return;
|
|
|
|
pos = rrs_text_start + (N_TXTOFF(outheader) - TEXT_START(outheader));
|
|
if (fseek(outstream, pos, SEEK_SET) != 0)
|
|
err(1, "write_rrs_text: fseek");
|
|
|
|
/* Write relocation records */
|
|
md_swapout_reloc(rrs_reloc, reserved_rrs_relocs);
|
|
mywrite(rrs_reloc, reserved_rrs_relocs,
|
|
sizeof(struct relocation_info), outstream);
|
|
|
|
/* 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), outstream);
|
|
|
|
/*
|
|
* 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 == dynamic_symbol)
|
|
continue;
|
|
|
|
if ((link_mode & SHAREABLE) && sp->warning) {
|
|
/*
|
|
* Write a N_WARNING duo.
|
|
*/
|
|
nlp->nz_type = N_WARNING;
|
|
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->warning);
|
|
offset += 1 + strlen(sp->warning);
|
|
INCR_NLP(nlp);
|
|
|
|
nlp->nz_type = N_UNDF + N_EXT;
|
|
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->name);
|
|
offset += 1 + strlen(sp->name);
|
|
INCR_NLP(nlp);
|
|
}
|
|
|
|
if (!(sp->flags & GS_REFERENCED))
|
|
continue;
|
|
|
|
if ((long)nlp - (long)rrs_symbols >=
|
|
number_of_rrs_symbols * rrs_symbol_size)
|
|
errx(1, "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;
|
|
|
|
bind = (sp->flags & GS_WEAK) ? BIND_WEAK : 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(bind, 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(bind, 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;
|
|
nlp->nz_other = N_OTHER(bind, 0);
|
|
} else if (!sp->defined) {
|
|
/* undefined */
|
|
nlp->nz_type = N_UNDF | N_EXT;
|
|
nlp->nz_value = 0;
|
|
if (sp->so_defined && sp->jmpslot_offset != -1) {
|
|
/*
|
|
* A PLT entry. The auxiliary type -- which
|
|
* must be AUX_FUNC -- is used by the run-time
|
|
* linker to unambiguously resolve function
|
|
* address references.
|
|
*/
|
|
if (sp->aux != AUX_FUNC)
|
|
errx(1, "%s: non-function jmpslot",
|
|
sp->name);
|
|
nlp->nz_other = N_OTHER(bind, sp->aux);
|
|
nlp->nz_value =
|
|
rrs_sdt.sdt_plt + sp->jmpslot_offset;
|
|
}
|
|
} else
|
|
errx(1, "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)
|
|
errx(1, "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, outstream);
|
|
|
|
/* Write the strings */
|
|
mywrite(rrs_strtab, rrs_strtab_size, 1, outstream);
|
|
|
|
/*
|
|
* 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)
|
|
errx(1, "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)
|
|
errx(1, "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), outstream);
|
|
|
|
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, outstream);
|
|
}
|
|
}
|
|
|
|
void
|
|
write_rrs()
|
|
{
|
|
|
|
/*
|
|
* First, do some consistency checks on the RRS segment.
|
|
*/
|
|
if (rrs_section_type == RRS_NONE) {
|
|
if (reserved_rrs_relocs > 1)
|
|
errx(1, "internal error: "
|
|
"RRS relocs in static program: %d",
|
|
reserved_rrs_relocs-1);
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("rrs_relocs: reserved %d claimed %d discarded %d, gotslots %d jmpslots %d\n",
|
|
reserved_rrs_relocs, claimed_rrs_relocs, discarded_rrs_relocs,
|
|
number_of_gotslots-1, number_of_jmpslots-1);
|
|
#endif
|
|
|
|
/* Final consistency check */
|
|
if (claimed_rrs_relocs + discarded_rrs_relocs != reserved_rrs_relocs) {
|
|
errx(1, "internal error: "
|
|
"reserved relocs(%d) != claimed(%d) + discarded(%d)",
|
|
reserved_rrs_relocs,
|
|
claimed_rrs_relocs,
|
|
discarded_rrs_relocs);
|
|
}
|
|
|
|
/* Write the RRS segments. */
|
|
write_rrs_text ();
|
|
write_rrs_data ();
|
|
}
|