* Copyright (c) 1993 Paul Kranenburg
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.9 1993/12/04 00:53:00 jkh Exp $
#include <sys/resource.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 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 file_entry
*entry
;
+-------------------+ <-- ld_rel (rrs_text_start)
+-------------------+ <-- <link_dynamic_2>.ld_hash
+-------------------+ <-- <link_dynamic_2>.ld_stab
+-------------------+ <-- <link_dynamic_2>.ld_strings
+-------------------+ <-- <link_dynamic_2>.ld_need
| shobjs strings | <-- <shobj>.lo_name
+-------------------+ <-- __DYNAMIC (rrs_data_start)
+-------------------+ <-- __DYNAMIC.ldd
+-------------------+ <-- __DYNAMIC.ld_un.ld_2
+-------------------+ <-- _GLOBAL_OFFSET_TABLE_ (ld_got)
+-------------------+ <-- ld_plt
number_of_rrs_symbols
= 0;
/* First jmpslot reserved for run-time binder */
current_jmpslot_offset
= sizeof(jmpslot_t
);
/* First gotslot reserved for __DYNAMIC */
current_got_offset
= sizeof(got_t
);
current_reloc_offset
= 0;
* Add NAME to the list of needed run-time objects.
* Return 1 if ENTRY was added to the list.
struct file_entry
*entry
;
for (p
= &rrs_shobjs
; *p
!= NULL
; p
= &(*p
)->next
)
if (strcmp((*p
)->entry
->filename
, entry
->filename
) == 0)
*p
= (struct shobj
*)xmalloc(sizeof(struct shobj
));
alloc_rrs_reloc(entry
, sp
)
struct file_entry
*entry
;
printf("alloc_rrs_reloc: %s in %s\n", sp
->name
, get_file_name(entry
));
alloc_rrs_segment_reloc(entry
, r
)
struct file_entry
*entry
;
struct relocation_info
*r
;
printf("alloc_rrs_segment_reloc at %#x in %s\n",
r
->r_address
, get_file_name(entry
));
alloc_rrs_jmpslot(entry
, sp
)
struct file_entry
*entry
;
if (sp
->jmpslot_offset
== -1) {
sp
->jmpslot_offset
= current_jmpslot_offset
;
current_jmpslot_offset
+= sizeof(jmpslot_t
);
if (!(link_mode
& SYMBOLIC
) || JMPSLOT_NEEDS_RELOC
) {
alloc_rrs_gotslot(entry
, r
, lsp
)
struct file_entry
*entry
;
struct relocation_info
*r
;
symbol
*sp
= lsp
->symbol
;
if (!RELOC_EXTERN_P(r
)) {
error("%s: relocation for internal symbol expected at %#x",
get_file_name(entry
), RELOC_ADDRESS(r
));
if (!RELOC_STATICS_THROUGH_GOT_P(r
))
/* No need for a GOT slot */
if (lsp
->gotslot_offset
== -1) {
lsp
->gotslot_offset
= current_got_offset
;
current_got_offset
+= sizeof(got_t
);
* 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
))
error("%s: relocation must refer to global symbol at %#x",
get_file_name(entry
), RELOC_ADDRESS(r
));
if (sp
->gotslot_offset
!= -1)
* External symbols always get a relocation entry
sp
->gotslot_offset
= current_got_offset
;
current_got_offset
+= sizeof(got_t
);
alloc_rrs_cpy_reloc(entry
, sp
)
struct file_entry
*entry
;
if (sp
->cpyreloc_reserved
)
printf("alloc_rrs_copy: %s in %s\n", sp
->name
, get_file_name(entry
));
sp
->cpyreloc_reserved
= 1;
static struct relocation_info
*
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",
* 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
claim_rrs_reloc(entry
, rp
, sp
, relocation
)
struct file_entry
*entry
;
struct relocation_info
*rp
;
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
);
printf("claim_rrs_reloc: %s in %s\n", sp
->name
, get_file_name(entry
));
r
->r_address
= rp
->r_address
;
r
->r_symbolnum
= sp
->rrs_symbolnum
;
if (link_mode
& SYMBOLIC
) {
error("Cannot reduce symbol \"%s\" in %s",
sp
->name
, get_file_name(entry
));
*relocation
+= sp
->value
;
(void) md_make_reloc(rp
, r
, RELTYPE_RELATIVE
);
return md_make_reloc(rp
, r
, RELTYPE_EXTERN
);
* Claim a jmpslot. Setup RRS relocation if claimed for the first time.
claim_rrs_jmpslot(entry
, rp
, sp
, addend
)
struct file_entry
*entry
;
struct relocation_info
*rp
;
struct relocation_info
*r
;
return rrs_dyn2
.ld_plt
+ sp
->jmpslot_offset
;
printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x (textreloc %#x)\n",
sp
->name
, sp
->rrs_symbolnum
, sp
->jmpslot_offset
, text_relocation
);
if (sp
->jmpslot_offset
== -1)
"internal error: %s: claim_rrs_jmpslot: %s: jmpslot_offset == -1\n",
if ((link_mode
& SYMBOLIC
) || rrs_section_type
== RRS_PARTIAL
) {
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_dyn2
.ld_plt
+ sp
->jmpslot_offset
,
if (!JMPSLOT_NEEDS_RELOC
) {
return rrs_dyn2
.ld_plt
+ sp
->jmpslot_offset
;
md_make_jmpslot( rrs_plt
+ sp
->jmpslot_offset
/sizeof(jmpslot_t
),
if (rrs_section_type
== RRS_PARTIAL
)
/* PLT is self-contained */
return rrs_dyn2
.ld_plt
+ sp
->jmpslot_offset
;
* Install a run-time relocation for this PLT entry.
RELOC_SYMBOL(r
) = sp
->rrs_symbolnum
;
r
->r_address
= (long)rrs_dyn2
.ld_plt
+ sp
->jmpslot_offset
;
if (link_mode
& SYMBOLIC
) {
md_make_jmpreloc(rp
, r
, RELTYPE_RELATIVE
);
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.
claim_rrs_gotslot(entry
, rp
, lsp
, addend
)
struct file_entry
*entry
;
struct relocation_info
*rp
;
struct relocation_info
*r
;
symbol
*sp
= lsp
->symbol
;
printf("claim_rrs_gotslot: %s(%d) slot offset %#x, addend %#x\n",
sp
->name
, sp
->rrs_symbolnum
, sp
->gotslot_offset
, addend
);
if (sp
->gotslot_offset
== -1)
"internal error: %s: claim_rrs_gotslot: %s: gotslot_offset == -1\n",
get_file_name(entry
), sp
->name
);
/* This symbol already passed here before. */
return sp
->gotslot_offset
;
(!(link_mode
& SHAREABLE
) || (link_mode
& SYMBOLIC
))) {
* Reduce to just a base-relative translation.
*(got_t
*)((long)rrs_got
+ sp
->gotslot_offset
) =
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
));
* 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
* NOTE: RRS_PARTIAL implies !SHAREABLE.
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
* `RELTYPE_RELATIVE' relocations have the external bit off
* as no symbol need be looked up at run-time.
r
->r_address
= rrs_dyn2
.ld_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
claim_rrs_internal_gotslot(entry
, rp
, lsp
, addend
)
struct file_entry
*entry
;
struct relocation_info
*rp
;
struct relocation_info
*r
;
addend
+= lsp
->nzlist
.nz_value
;
if (!RELOC_STATICS_THROUGH_GOT_P(r
))
return addend
- rrs_dyn2
.ld_got
;
printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n",
get_file_name(entry
), lsp
->gotslot_offset
, addend
);
if (lsp
->gotslot_offset
== -1)
"internal error: %s: claim_rrs_internal_gotslot at %#x: slot_offset == -1\n",
get_file_name(entry
), RELOC_ADDRESS(rp
));
if (lsp
->gotslot_claimed
)
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.
lsp
->gotslot_claimed
= 1;
r
->r_address
= rrs_dyn2
.ld_got
+ lsp
->gotslot_offset
;
md_make_gotreloc(rp
, r
, RELTYPE_RELATIVE
);
return lsp
->gotslot_offset
;
claim_rrs_cpy_reloc(entry
, rp
, sp
)
struct file_entry
*entry
;
struct relocation_info
*rp
;
struct relocation_info
*r
;
if (sp
->cpyreloc_claimed
)
if (!sp
->cpyreloc_reserved
)
fatal("internal error: %s: claim_cpy_reloc: %s: no reservation\n",
get_file_name(entry
), sp
->name
);
printf("claim_rrs_copy: %s: %s -> %x\n",
get_file_name(entry
), sp
->name
, sp
->so_defined
);
sp
->cpyreloc_claimed
= 1;
r
->r_address
= rp
->r_address
;
RELOC_SYMBOL(r
) = sp
->rrs_symbolnum
;
RELOC_EXTERN_P(r
) = RELOC_EXTERN_P(rp
);
claim_rrs_segment_reloc(entry
, rp
)
struct file_entry
*entry
;
struct relocation_info
*rp
;
struct relocation_info
*r
= rrs_next_reloc();
printf("claim_rrs_segment_reloc: %s at %#x\n",
get_file_name(entry
), rp
->r_address
);
r
->r_address
= rp
->r_address
;
RELOC_TYPE(r
) = RELOC_TYPE(rp
);
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.
rrs_insert_hash(cp
, index
)
hashval
= (hashval
<< 1) + *cp
;
hashval
= (hashval
& 0x7fffffff) % rrs_dyn2
.ld_buckets
;
hp
= rrs_hashtab
+ hashval
;
if (hp
->rh_symbolnum
== -1) {
/* Empty bucket, use it */
hp
->rh_symbolnum
= index
;
hp
= rrs_hashtab
+ hp
->rh_next
;
hp
->rh_next
= current_hash_index
++;
hp
= rrs_hashtab
+ hp
->rh_next
;
hp
->rh_symbolnum
= index
;
* 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
consider_rrs_section_lengths()
/* First, determine what of the RRS we want */
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
;
rrs_section_type
= RRS_NONE
;
rrs_section_type
= RRS_FULL
;
if (rrs_section_type
== RRS_NONE
) {
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
->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
);
n
= number_of_gotslots
* sizeof(got_t
);
rrs_got
= (got_t
*)xmalloc(n
);
n
= number_of_jmpslots
* sizeof(jmpslot_t
);
rrs_plt
= (jmpslot_t
*)xmalloc(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
);
* Walk the symbol table, assign RRS symbol numbers
* Assign number 0 to __DYNAMIC (!! Sun compatibility)
dynamic_symbol
->rrs_symbolnum
= number_of_rrs_symbols
++;
rrs_strtab_size
+= 1 + strlen(sp
->name
);
if (sp
!= dynamic_symbol
)
sp
->rrs_symbolnum
= number_of_rrs_symbols
++;
* (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.
rrs_strtab_size
+= 1 + strlen(sp
->alias
->name
);
* 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)
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.
rrs_insert_hash(sp
->name
, sp
->rrs_symbolnum
);
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
;
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')
rrs_text_size
+= sizeof(struct link_object
);
rrs_text_size
+= 1 + strlen(name
);
/* Finally, align size */
rrs_text_size
= MALIGN(rrs_text_size
);
dynamic_symbol
->value
= 0;
if (rrs_section_type
== RRS_NONE
)
if (rrs_section_type
== RRS_PARTIAL
) {
got_symbol
->value
= rrs_dyn2
.ld_got
= rrs_data_start
;
rrs_dyn2
.ld_plt
= rrs_dyn2
.ld_got
+
number_of_gotslots
* sizeof(got_t
);
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_dyn2
.ld_rel
= rrs_text_start
;
* Sun BUG compatibility alert.
* Main program's RRS text values are relative to TXTADDR? WHY??
if (soversion
== LD_VERSION_SUN
&& !(link_mode
& SHAREABLE
))
rrs_dyn2
.ld_rel
-= N_TXTADDR(outheader
);
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;
* 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
;
if (rrs_section_type
== RRS_NONE
)
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
,
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
);
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
);
if (rrs_section_type
== RRS_PARTIAL
)
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
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_type
= dynamic_symbol
->defined
;
nlp
->nz_value
= dynamic_symbol
->value
;
nlp
->nz_value
= dynamic_symbol
->value
;
strcpy(rrs_strtab
+ offset
, dynamic_symbol
->name
);
offset
+= 1 + strlen(dynamic_symbol
->name
);
* Now, for each global symbol, construct a nzlist element
* for inclusion in the RRS symbol table.
if (!sp
->referenced
|| sp
== dynamic_symbol
)
if ((long)nlp
- (long)rrs_symbols
>=
number_of_rrs_symbols
* rrs_symbol_size
)
"internal error: rrs symbols exceed allocation %d ",
if (LD_VERSION_NZLIST_P(soversion
))
/* 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
nlp
->nz_type
= sp
->alias
->defined
;
nlp
->nz_value
= sp
->alias
->value
;
} else if (sp
->defined
== N_SIZE
) {
* Make sure this symbol isn't going
nlp
->nz_type
= sp
->defined
;
nlp
->nz_value
= sp
->value
;
if (LD_VERSION_NZLIST_P(soversion
))
} else if (sp
->max_common_size
) {
nlp
->nz_type
= N_UNDF
| N_EXT
;
nlp
->nz_value
= sp
->max_common_size
;
} else if (!sp
->defined
) {
nlp
->nz_type
= N_UNDF
| N_EXT
;
"internal error: %s defined in mysterious way",
/* Handle auxialiary type qualifiers */
if (sp
->so_defined
!= (N_TEXT
+N_EXT
))
fatal("internal error: %s: other but not text",
if (sp
->jmpslot_offset
== -1)
"internal error: %s has no jmpslot but other",
rrs_dyn2
.ld_plt
+ sp
->jmpslot_offset
;
"internal error: %s: unsupported other value: %x",
strcpy(rrs_strtab
+ offset
, sp
->name
);
offset
+= 1 + strlen(sp
->name
);
* Write an extra symbol for indirections (possibly
int t
= (nlp
->nz_type
== N_INDR
+ N_EXT
);
nlp
->nz_type
= N_UNDF
+ t
?N_EXT
:0;
nlp
->nz_un
.n_strx
= offset
;
strcpy(rrs_strtab
+ offset
, sp
->alias
->name
);
offset
+= 1 + strlen(sp
->alias
->name
);
if (MALIGN(offset
) != rrs_strtab_size
)
"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
);
md_swapout_zsymbols(rrs_symbols
, number_of_rrs_symbols
);
mywrite(rrs_symbols
, symsize
, 1, outdesc
);
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 (i
>= number_of_shobjs
)
fatal("internal error: # of link objects exceeds %d",
lo
[i
].lo_major
= shp
->entry
->lib_major
;
lo
[i
].lo_minor
= shp
->entry
->lib_minor
;
if (*name
== '-' && *(name
+1) == 'l') {
lo
[i
].lo_next
= (i
== number_of_shobjs
- 1) ? 0 :
(rrs_dyn2
.ld_need
+ (i
+1)*sizeof(struct link_object
));
if (i
< number_of_shobjs
)
fatal("internal error: # of link objects less then expected %d",
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') {
mywrite(name
, strlen(name
) + 1, 1, outdesc
);
* First, do some consistency checks on the RRS segment.
if (rrs_section_type
== RRS_NONE
) {
if (reserved_rrs_relocs
> 1)
"internal error: RRS relocs in static program: %d",
printf("rrs_relocs %d, gotslots %d, jmpslots %d\n",
reserved_rrs_relocs
, number_of_gotslots
-1, number_of_jmpslots
-1);
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. */