1019 lines
25 KiB
C
1019 lines
25 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 withough specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $Id: rrs.c,v 1.1 1993/10/16 21:52:34 pk Exp $
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/file.h>
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#include <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 link_dynamic rrs_dyn; /* defined in link.h */
|
|
static struct ld_debug rrs_ld_debug; /* defined in link.h */
|
|
static struct link_dynamic_2 rrs_dyn2; /* 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;
|
|
static int number_of_shobjs;
|
|
|
|
struct shobj {
|
|
struct shobj *next;
|
|
struct file_entry *entry;
|
|
};
|
|
|
|
/*
|
|
RRS text segment:
|
|
+-------------------+ <-- ld_rel (rrs_text_start)
|
|
| |
|
|
| relocation |
|
|
| |
|
|
+-------------------+ <-- <link_dynamic_2>.ld_hash
|
|
| |
|
|
| hash buckets |
|
|
| |
|
|
+-------------------+ <-- <link_dynamic_2>.ld_stab
|
|
| |
|
|
| symbols |
|
|
| |
|
|
+-------------------+ <-- <link_dynamic_2>.ld_strings
|
|
| |
|
|
| strings |
|
|
| |
|
|
+-------------------+ <-- <link_dynamic_2>.ld_need
|
|
| |
|
|
| shobjs |
|
|
| |
|
|
+-------------------+
|
|
| |
|
|
| shobjs strings | <-- <shobj>.lo_name
|
|
| |
|
|
+-------------------+
|
|
|
|
|
|
RRS data segment:
|
|
|
|
+-------------------+ <-- __DYNAMIC (rrs_data_start)
|
|
| |
|
|
| link_dymamic |
|
|
| |
|
|
+-------------------+ <-- __DYNAMIC.ldd
|
|
| |
|
|
| ld_debug |
|
|
| |
|
|
+-------------------+ <-- __DYNAMIC.ld_un.ld_2
|
|
| |
|
|
| link_dymamic_2 |
|
|
| |
|
|
+-------------------+ <-- _GLOBAL_OFFSET_TABLE_ (ld_got)
|
|
| |
|
|
| _GOT_ |
|
|
| |
|
|
+-------------------+ <-- ld_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.
|
|
*/
|
|
void
|
|
rrs_add_shobj(entry)
|
|
struct file_entry *entry;
|
|
{
|
|
struct shobj **p;
|
|
|
|
for (p = &rrs_shobjs; *p != NULL; p = &(*p)->next);
|
|
*p = (struct shobj *)xmalloc(sizeof(struct shobj));
|
|
(*p)->next = NULL;
|
|
(*p)->entry = entry;
|
|
|
|
number_of_shobjs++;
|
|
}
|
|
|
|
void
|
|
alloc_rrs_reloc(sp)
|
|
symbol *sp;
|
|
{
|
|
#ifdef DEBUG
|
|
printf("alloc_rrs_reloc: %s\n", sp->name);
|
|
#endif
|
|
reserved_rrs_relocs++;
|
|
}
|
|
|
|
void
|
|
alloc_rrs_segment_reloc(r)
|
|
struct relocation_info *r;
|
|
{
|
|
#ifdef DEBUG
|
|
printf("alloc_rrs_segment_reloc at %#x\n", r->r_address);
|
|
#endif
|
|
reserved_rrs_relocs++;
|
|
}
|
|
|
|
void
|
|
alloc_rrs_jmpslot(sp)
|
|
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(r, lsp)
|
|
struct relocation_info *r;
|
|
struct localsymbol *lsp;
|
|
{
|
|
symbol *sp = lsp->symbol;
|
|
|
|
if (!RELOC_EXTERN_P(r)) {
|
|
|
|
if (sp != NULL)
|
|
fatal("internal error: lsp->symbol not NULL");
|
|
|
|
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 (!entry_symbol || (link_mode & SYMBOLIC))
|
|
reserved_rrs_relocs++;
|
|
}
|
|
|
|
} else if (sp->gotslot_offset == -1) {
|
|
/*
|
|
* 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(sp)
|
|
symbol *sp;
|
|
{
|
|
if (sp->cpyreloc_reserved)
|
|
return;
|
|
#ifdef DEBUG
|
|
printf("alloc_rrs_copy: %s\n", sp->name);
|
|
#endif
|
|
sp->cpyreloc_reserved = 1;
|
|
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(rp, sp, relocation)
|
|
struct relocation_info *rp;
|
|
symbol *sp;
|
|
long *relocation;
|
|
{
|
|
struct relocation_info *r = rrs_next_reloc();
|
|
|
|
if (rp->r_address < text_start + text_size)
|
|
error("RRS text relocation at %#x (symbol %s)",
|
|
rp->r_address, sp->name);
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrs_reloc: %s\n", sp->name);
|
|
#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", sp->name);
|
|
RELOC_EXTERN_P(r) = 0;
|
|
*relocation += sp->value;
|
|
(void) md_make_reloc(rp, r, RELTYPE_RELATIVE);
|
|
return 0;
|
|
} else {
|
|
RELOC_EXTERN_P(r) = 1;
|
|
*relocation = 0;
|
|
return md_make_reloc(rp, r, RELTYPE_EXTERN);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Claim a jmpslot. Setup RRS relocation if claimed for the first time.
|
|
*/
|
|
long
|
|
claim_rrs_jmpslot(rp, sp, addend)
|
|
struct relocation_info *rp;
|
|
symbol *sp;
|
|
long addend;
|
|
{
|
|
struct relocation_info *r;
|
|
|
|
if (sp->jmpslot_claimed)
|
|
return rrs_dyn2.ld_plt + sp->jmpslot_offset;
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrs_jmpslot: %s(%d) -> offset %x (textreloc %#x)\n",
|
|
sp->name, sp->rrs_symbolnum, sp->jmpslot_offset, text_relocation);
|
|
#endif
|
|
|
|
if (sp->jmpslot_offset == -1)
|
|
fatal(
|
|
"internal error: claim_rrs_jmpslot: %s: jmpslot_offset == -1\n",
|
|
sp->name);
|
|
|
|
if (link_mode & SYMBOLIC) {
|
|
if (!sp->defined)
|
|
error("Cannot reduce symbol %s", sp->name);
|
|
|
|
md_fix_jmpslot( rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
|
|
rrs_dyn2.ld_plt + sp->jmpslot_offset,
|
|
sp->value);
|
|
if (!JMPSLOT_NEEDS_RELOC) {
|
|
return rrs_dyn2.ld_plt + sp->jmpslot_offset;
|
|
}
|
|
} else {
|
|
md_make_jmpslot( rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
|
|
sp->jmpslot_offset,
|
|
claimed_rrs_relocs);
|
|
|
|
}
|
|
|
|
r = rrs_next_reloc();
|
|
sp->jmpslot_claimed = 1;
|
|
|
|
RELOC_SYMBOL(r) = sp->rrs_symbolnum;
|
|
|
|
r->r_address = (long)rrs_dyn2.ld_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_dyn2.ld_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(rp, lsp, addend)
|
|
struct relocation_info *rp;
|
|
struct localsymbol *lsp;
|
|
long addend;
|
|
{
|
|
struct relocation_info *r;
|
|
symbol *sp = lsp->symbol;
|
|
|
|
#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: claim_rrs_gotslot: %s: gotslot_offset == -1\n",
|
|
sp->name);
|
|
|
|
if (entry_symbol || (link_mode & SYMBOLIC)) {
|
|
|
|
if (!sp->defined)
|
|
error("Cannot reduce symbol %s", sp->name);
|
|
|
|
*(got_t *)((long)rrs_got + sp->gotslot_offset) =
|
|
sp->value + addend;
|
|
#if 0
|
|
if (sp->defined == N_TEXT + N_EXT)
|
|
*(got_t *)((long)rrs_got + sp->gotslot_offset) += addend;
|
|
#endif
|
|
|
|
} else {
|
|
|
|
*(got_t *)((long)rrs_got + sp->gotslot_offset) = addend;
|
|
|
|
}
|
|
|
|
if (sp->gotslot_claimed)
|
|
return sp->gotslot_offset;
|
|
|
|
/* Claim a relocation entry */
|
|
r = rrs_next_reloc();
|
|
sp->gotslot_claimed = 1;
|
|
r->r_address = rrs_dyn2.ld_got + sp->gotslot_offset;
|
|
RELOC_SYMBOL(r) = sp->rrs_symbolnum;
|
|
|
|
if (entry_symbol || (link_mode & SYMBOLIC)) {
|
|
if (!sp->defined)
|
|
error("Cannot reduce symbol %s", sp->name);
|
|
RELOC_EXTERN_P(r) = 0;
|
|
md_make_gotreloc(rp, r, RELTYPE_RELATIVE);
|
|
} else {
|
|
RELOC_EXTERN_P(r) = 1;
|
|
md_make_gotreloc(rp, r, 0);
|
|
}
|
|
|
|
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(rp, lsp, addend)
|
|
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_dyn2.ld_got;
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrsinternal__gotslot: slot offset %#x, addend = %#x\n",
|
|
lsp->gotslot_offset, addend);
|
|
#endif
|
|
|
|
if (lsp->gotslot_offset == -1)
|
|
fatal(
|
|
"internal error: claim_rrs_internal_gotslot: slot_offset == -1\n");
|
|
|
|
*(long *)((long)rrs_got + lsp->gotslot_offset) = addend;
|
|
|
|
if (entry_symbol /* || (link_mode & SYMBOLIC)??? */ )
|
|
return lsp->gotslot_offset;
|
|
|
|
|
|
/* Relocation entry needed for this static GOT entry */
|
|
if (lsp->gotslot_claimed)
|
|
return lsp->gotslot_offset;
|
|
|
|
/* Claim a relocation entry */
|
|
r = rrs_next_reloc();
|
|
lsp->gotslot_claimed = 1;
|
|
r->r_address = rrs_dyn2.ld_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(rp, sp)
|
|
struct relocation_info *rp;
|
|
symbol *sp;
|
|
{
|
|
struct relocation_info *r;
|
|
|
|
if (sp->cpyreloc_claimed)
|
|
return;
|
|
|
|
if (!sp->cpyreloc_reserved)
|
|
fatal("internal error: claim_cpy_reloc: %s: no reservation\n",
|
|
sp->name);
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrs_copy: %s -> %x\n", sp->name, sp->so_defined);
|
|
#endif
|
|
|
|
r = rrs_next_reloc();
|
|
sp->cpyreloc_claimed = 1;
|
|
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(rp)
|
|
struct relocation_info *rp;
|
|
{
|
|
struct relocation_info *r = rrs_next_reloc();
|
|
|
|
#ifdef DEBUG
|
|
printf("claim_rrs_segment_reloc: %x\n", 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_dyn2.ld_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;
|
|
int symbolsize;
|
|
|
|
/* First, determine what of the RRS we want */
|
|
|
|
if (relocatable_output)
|
|
rrs_section_type = RRS_NONE;
|
|
else if (entry_symbol == NULL)
|
|
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 (entry_symbol && !dynamic_symbol->referenced)
|
|
fatal("No reference to __DYNAMIC");
|
|
|
|
dynamic_symbol->referenced = 1;
|
|
|
|
if (number_of_gotslots > 1)
|
|
got_symbol->referenced = 1;
|
|
|
|
|
|
/* 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->referenced) {
|
|
rrs_strtab_size += 1 + strlen(sp->name);
|
|
if (sp != dynamic_symbol)
|
|
sp->rrs_symbolnum = number_of_rrs_symbols++;
|
|
}
|
|
} 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_dyn2.ld_buckets = number_of_rrs_symbols/4;
|
|
if (rrs_dyn2.ld_buckets < 4)
|
|
rrs_dyn2.ld_buckets = 4;
|
|
|
|
number_of_rrs_hash_entries = rrs_dyn2.ld_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_dyn2.ld_buckets; n++)
|
|
rrs_hashtab[n].rh_symbolnum = -1;
|
|
current_hash_index = rrs_dyn2.ld_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->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 link_dynamic);
|
|
rrs_data_size += sizeof(struct ld_debug);
|
|
rrs_data_size += sizeof(struct link_dynamic_2);
|
|
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 link_object);
|
|
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) {
|
|
rrs_dyn2.ld_got = rrs_data_start;
|
|
rrs_dyn2.ld_plt = rrs_dyn2.ld_got +
|
|
number_of_gotslots * sizeof(got_t);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* RRS data relocations.
|
|
*/
|
|
rrs_dyn.ld_version = soversion;
|
|
rrs_dyn.ldd = (struct ld_debug *)
|
|
(rrs_data_start + sizeof(struct link_dynamic));
|
|
rrs_dyn.ld_un.ld_2 = (struct link_dynamic_2 *)
|
|
((long)rrs_dyn.ldd + sizeof(struct ld_debug));
|
|
|
|
rrs_dyn2.ld_got = (long)rrs_dyn.ld_un.ld_2 +
|
|
sizeof(struct link_dynamic_2);
|
|
rrs_dyn2.ld_plt = rrs_dyn2.ld_got + number_of_gotslots*sizeof(got_t);
|
|
|
|
/*
|
|
* RRS text relocations.
|
|
*/
|
|
rrs_dyn2.ld_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)
|
|
rrs_dyn2.ld_rel -= N_TXTADDR(outheader);
|
|
#endif
|
|
|
|
rrs_dyn2.ld_hash = rrs_dyn2.ld_rel +
|
|
reserved_rrs_relocs * sizeof(struct relocation_info);
|
|
rrs_dyn2.ld_symbols = rrs_dyn2.ld_hash +
|
|
number_of_rrs_hash_entries * sizeof(struct rrs_hash);
|
|
rrs_dyn2.ld_strings = rrs_dyn2.ld_symbols +
|
|
number_of_rrs_symbols * rrs_symbol_size;
|
|
rrs_dyn2.ld_str_sz = rrs_strtab_size;
|
|
rrs_dyn2.ld_text_sz = text_size;
|
|
rrs_dyn2.ld_plt_sz = number_of_jmpslots * sizeof(jmpslot_t);
|
|
|
|
rrs_dyn2.ld_need = rrs_shobjs ? rrs_dyn2.ld_strings+rrs_strtab_size : 0;
|
|
rrs_dyn2.ld_stab_hash = 0;
|
|
rrs_dyn2.ld_rules = 0;
|
|
|
|
/*
|
|
* Assign addresses to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC
|
|
* &__DYNAMIC is also in the first GOT entry.
|
|
*/
|
|
got_symbol->value = rrs_dyn2.ld_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) {
|
|
if (number_of_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) {
|
|
md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
|
|
mywrite(rrs_plt, number_of_jmpslots,
|
|
sizeof(jmpslot_t), outdesc);
|
|
}
|
|
return;
|
|
}
|
|
|
|
md_swapout_link_dynamic(&rrs_dyn);
|
|
mywrite(&rrs_dyn, 1, sizeof(struct link_dynamic), outdesc);
|
|
|
|
md_swapout_ld_debug(&rrs_ld_debug);
|
|
mywrite(&rrs_ld_debug, 1, sizeof(struct ld_debug), outdesc);
|
|
|
|
md_swapout_link_dynamic_2(&rrs_dyn2);
|
|
mywrite(&rrs_dyn2, 1, sizeof(struct link_dynamic_2), 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 link_object *lo;
|
|
|
|
if (rrs_section_type == RRS_NONE)
|
|
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->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 (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;
|
|
}
|
|
if (LD_VERSION_NZLIST_P(soversion))
|
|
nlp->nz_size = sp->size;
|
|
} else if (sp->max_common_size) {
|
|
/*
|
|
* a common definition
|
|
*/
|
|
nlp->nz_type = N_UNDF | N_EXT;
|
|
nlp->nz_value = sp->max_common_size;
|
|
} else if (!sp->defined) {
|
|
/* undefined */
|
|
nlp->nz_type = N_UNDF | N_EXT;
|
|
nlp->nz_value = 0;
|
|
} else
|
|
fatal(
|
|
"internal error: %s defined in mysterious way",
|
|
sp->name);
|
|
|
|
nlp->nz_strx = offset;
|
|
strcpy(rrs_strtab + offset, sp->name);
|
|
offset += 1 + strlen(sp->name);
|
|
|
|
INCR_NLP(nlp);
|
|
|
|
} END_EACH_SYMBOL;
|
|
|
|
if (MALIGN(offset) != rrs_strtab_size)
|
|
fatal(
|
|
"internal error: inconsistent RRS string table length: %d",
|
|
offset);
|
|
|
|
/* 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_dyn2.ld_need + number_of_shobjs * sizeof(struct link_object);
|
|
lo = (struct link_object *)alloca(
|
|
number_of_shobjs * sizeof(struct link_object));
|
|
|
|
for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) {
|
|
char *name = shp->entry->local_sym_name;
|
|
|
|
if (shp == NULL)
|
|
fatal("internal error: shp == NULL");
|
|
|
|
lo[i].lo_name = pos;
|
|
lo[i].lo_major = shp->entry->lib_major;
|
|
lo[i].lo_minor = shp->entry->lib_minor;
|
|
|
|
if (*name == '-' && *(name+1) == 'l') {
|
|
name += 2;
|
|
lo[i].lo_library = 1;
|
|
} else
|
|
lo[i].lo_library = 0;
|
|
|
|
pos += 1 + strlen(name);
|
|
lo[i].lo_next = (i == number_of_shobjs - 1) ? 0 :
|
|
(rrs_dyn2.ld_need + (i+1)*sizeof(struct link_object));
|
|
|
|
}
|
|
if (shp != NULL)
|
|
fatal("internal error: shp != NULL");
|
|
|
|
md_swapout_link_object(lo, number_of_shobjs);
|
|
mywrite(lo, number_of_shobjs, sizeof(struct link_object), 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: claimed relocs(%d) != allocated(%d)",
|
|
reserved_rrs_relocs, claimed_rrs_relocs);
|
|
}
|
|
|
|
/* Write the RRS segments. */
|
|
write_rrs_text ();
|
|
write_rrs_data ();
|
|
}
|