indirect_sections.c [plain text]
#ifdef SHLIB
#include "shlib.h"
#endif
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <mach/mach.h>
#else
#include <mach/kern_return.h>
#endif
#include <stdarg.h>
#include <string.h>
#include "stuff/openstep_mach.h"
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include "stuff/arch.h"
#include "stuff/reloc.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "pass2.h"
#include "generic_reloc.h"
#include "pass1.h"
#include "symbols.h"
#include "layout.h"
#include "indirect_sections.h"
#include "dylibs.h"
__private_extern__ unsigned long nindirectsyms = 0;
__private_extern__ enum bool save_lazy_symbol_pointer_relocs = FALSE;
#ifndef SA_RLD
static unsigned long lookup_indirect_item(
struct merged_symbol *merged_symbol,
struct object_file *obj,
unsigned long index,
struct indirect_section_data *data,
unsigned long stride,
enum bool *new);
__private_extern__
void
indirect_section_merge(
struct indirect_section_data *data,
struct merged_section *ms,
struct section *s,
struct section_map *section_map,
enum bool redo_live)
{
unsigned long i, j, stride, section_type, nitems, index;
struct fine_reloc *fine_relocs;
struct nlist *nlists;
unsigned long *indirect_symtab;
struct undefined_map *undefined_map;
struct merged_symbol *merged_symbol, *indr_symbol;
enum bool new;
struct relocation_info *relocs, reloc;
struct scattered_relocation_info *sreloc, *spair_reloc;
unsigned long r_address, r_pcrel, r_length, r_type, pair_r_type, r_extern,
r_symbolnum, r_scattered, r_value, pair;
#ifndef RLD
enum bool pic;
#endif
enum bool defined, force_extern_reloc;
unsigned long nsect;
char *strings;
merged_symbol = NULL;
if(s->size == 0)
return;
stride = 0;
pair_r_type = 0;
section_type = s->flags & SECTION_TYPE;
if(section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_NON_LAZY_SYMBOL_POINTERS){
stride = 4;
}
else if(section_type == S_SYMBOL_STUBS)
stride = s->reserved2;
else
fatal("internal error, in indirect_section_merge() section type "
"(%lu) is not correct for an indirect section", section_type);
nitems = s->size / stride;
if(s->size % stride != 0){
error_with_cur_obj("malformed object (section (%.16s,%.16s) size "
"is not a multiple of %lu bytes)", s->segname, s->sectname,
stride);
return;
}
if(cur_obj->dysymtab == NULL){
error_with_cur_obj("malformed object (file has indirect section "
"(%.16s,%.16s) but no dysymtab_command)", s->segname,
s->sectname);
return;
}
if(s->reserved1 > cur_obj->dysymtab->nindirectsyms){
error_with_cur_obj("malformed object (index into indirect symbol "
"table (reserved1 field) for indirect section (%.16s,%.16s) "
"past the end of the table)", s->segname, s->sectname);
return;
}
if(s->reserved1 + nitems > cur_obj->dysymtab->nindirectsyms){
error_with_cur_obj("malformed object (indirect symbol table entries"
"for section (%.16s,%.16s) extends past the end of the table)",
s->segname, s->sectname);
return;
}
if(s->size == 0){
if(redo_live == FALSE){
section_map->fine_relocs = NULL;
section_map->nfine_relocs = 0;
}
return;
}
#ifdef DEBUG
if(redo_live == FALSE){
data->nfiles++;
data->nitems += nitems;
}
#endif
nlists = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
indirect_symtab = (unsigned long *)(cur_obj->obj_addr +
cur_obj->dysymtab->indirectsymoff);
strings = cur_obj->obj_addr + cur_obj->symtab->stroff;
if(redo_live == FALSE){
fine_relocs = allocate(nitems * sizeof(struct fine_reloc));
memset(fine_relocs, '\0', nitems * sizeof(struct fine_reloc));
}
else{
fine_relocs = section_map->fine_relocs;
nitems = section_map->nfine_relocs;
}
for(i = 0; i < nitems; i++){
index = indirect_symtab[s->reserved1 + i];
if(index == INDIRECT_SYMBOL_LOCAL ||
index == INDIRECT_SYMBOL_ABS){
if(redo_live == FALSE){
fine_relocs[i].local_symbol = TRUE;
fine_relocs[i].indirect_defined = FALSE;
fine_relocs[i].use_contents = TRUE;
fine_relocs[i].input_offset = i * stride;
fine_relocs[i].merged_symbol = NULL;
if(index == INDIRECT_SYMBOL_LOCAL)
fine_relocs[i].indirect_symbol_local = TRUE;
}
if(redo_live == FALSE || fine_relocs[i].live == TRUE){
fine_relocs[i].output_offset = lookup_indirect_item(
NULL, cur_obj, index, data, stride, &new);
}
else if(redo_live == TRUE && fine_relocs[i].live == FALSE){
fine_relocs[i].use_contents = FALSE;
}
goto account_for_size;
}
undefined_map = bsearch(&index, cur_obj->undefined_maps,
cur_obj->nundefineds, sizeof(struct undefined_map),
(int (*)(const void *, const void *))undef_bsearch);
if(undefined_map != NULL){
merged_symbol = undefined_map->merged_symbol;
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT &&
(merged_symbol->nlist.n_type & N_EXT) != N_EXT &&
section_type == S_NON_LAZY_SYMBOL_POINTERS &&
output_for_dyld == FALSE)
fatal("indirect symbol:%s can not be a private extern",
strings + nlists[index].n_un.n_strx);
}
else if((nlists[index].n_type & N_EXT) == N_EXT){
merged_symbol = lookup_symbol(strings +
nlists[index].n_un.n_strx);
if(merged_symbol->name_len == 0)
fatal("interal error, indirect_section_merge() failed in "
"looking up external symbol");
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT &&
(merged_symbol->nlist.n_type & N_EXT) != N_EXT &&
section_type == S_NON_LAZY_SYMBOL_POINTERS &&
output_for_dyld == FALSE)
fatal("indirect symbol:%s can not be a private extern",
strings + nlists[index].n_un.n_strx);
}
else if((nlists[index].n_type & N_PEXT) == N_PEXT &&
(nlists[index].n_type & N_EXT) != N_EXT &&
section_type == S_NON_LAZY_SYMBOL_POINTERS &&
output_for_dyld == FALSE)
fatal("indirect symbol:%s can not be a private extern",
strings + nlists[index].n_un.n_strx);
else if((nlists[index].n_type & N_STAB) == 0){
merged_symbol = NULL;
}
else{
error_with_cur_obj("malformed object (bad indirect symbol "
"table entry (%ld) (symbol at index %lu is a stab)",
s->reserved1 + i, index);
return;
}
if(redo_live == FALSE)
fine_relocs[i].input_offset = i * stride;
if(merged_symbol == NULL){
if(section_type == S_NON_LAZY_SYMBOL_POINTERS){
if((nlists[index].n_type & N_PEXT) == 0){
error_with_cur_obj("malformed object (bad indirect "
"symbol table entry (%ld) (symbol at index %lu is "
"not external)", s->reserved1 + i, index);
return;
}
if(redo_live == FALSE){
fine_relocs[i].local_symbol = TRUE;
fine_relocs[i].indirect_defined = TRUE;
fine_relocs[i].use_contents = TRUE;
fine_relocs[i].merged_symbol = NULL;
}
if(redo_live == FALSE || fine_relocs[i].live == TRUE){
fine_relocs[i].output_offset = lookup_indirect_item(
NULL, cur_obj, index, data, stride, &new);
}
else if(redo_live == TRUE && fine_relocs[i].live == FALSE){
fine_relocs[i].use_contents = FALSE;
}
}
else{
if(redo_live == FALSE){
fine_relocs[i].local_symbol = TRUE;
fine_relocs[i].indirect_defined = TRUE;
fine_relocs[i].use_contents = FALSE;
fine_relocs[i].output_offset = index;
fine_relocs[i].merged_symbol = NULL;
}
}
}
else{
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR &&
merged_symbol->defined_in_dylib == FALSE){
indr_symbol = NULL;
for(j = 0; j < nindr_symbol_pairs; j++){
if(indr_symbol_pairs[j].merged_symbol == merged_symbol)
indr_symbol = indr_symbol_pairs[j].indr_symbol;
}
if(indr_symbol == NULL)
indr_symbol = (struct merged_symbol *)
(merged_symbol->nlist.n_value);
merged_symbol = indr_symbol;
}
if(redo_live == FALSE)
fine_relocs[i].local_symbol = FALSE;
if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF) ||
merged_symbol->nlist.n_type == (N_EXT | N_PBUD) ||
(merged_symbol->nlist.n_type == (N_EXT | N_INDR) &&
merged_symbol->defined_in_dylib == TRUE)){
if(redo_live == FALSE){
fine_relocs[i].indirect_defined = FALSE;
}
}
else if((merged_symbol->nlist.n_type & N_TYPE) == N_SECT &&
(merged_symbol->definition_object->section_maps[
merged_symbol->nlist.n_sect - 1].
s->flags & SECTION_TYPE) == S_COALESCED &&
filetype != MH_DYLINKER){
if((output_for_dyld &&
(has_dynamic_linker_command || filetype == MH_BUNDLE) &&
(((merged_symbol->nlist.n_desc & N_WEAK_DEF) !=
N_WEAK_DEF) ||
((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT &&
keep_private_externs == FALSE) ) ) ||
(filetype == MH_DYLIB && multi_module_dylib == FALSE &&
(merged_symbol->nlist.n_type & N_PEXT) == N_PEXT) ){
if(redo_live == FALSE)
fine_relocs[i].indirect_defined = TRUE;
}
else{
if(redo_live == FALSE)
fine_relocs[i].indirect_defined = FALSE;
}
}
else{
if(redo_live == FALSE)
fine_relocs[i].indirect_defined = TRUE;
}
if((merged_symbol->nlist.n_type & N_TYPE) == N_ABS)
section_map->absolute_indirect_defineds = TRUE;
if((filetype == MH_DYLIB && multi_module_dylib == TRUE) ||
section_type == S_NON_LAZY_SYMBOL_POINTERS ||
fine_relocs[i].indirect_defined == FALSE){
if(redo_live == FALSE || fine_relocs[i].live == TRUE){
fine_relocs[i].output_offset = lookup_indirect_item(
merged_symbol, NULL, 0, data, stride, &new);
}
else if(redo_live == TRUE && fine_relocs[i].live == FALSE){
new = FALSE;
}
fine_relocs[i].use_contents = new;
if(redo_live == FALSE)
fine_relocs[i].merged_symbol = merged_symbol;
}
else{
if(redo_live == FALSE){
fine_relocs[i].use_contents = FALSE;
fine_relocs[i].merged_symbol = merged_symbol;
}
}
}
account_for_size:
if(fine_relocs[i].use_contents){
if(redo_live == FALSE || fine_relocs[i].live == TRUE){
ms->s.size += stride;
nindirectsyms++;
}
}
}
if(redo_live == FALSE){
section_map->fine_relocs = fine_relocs;
section_map->nfine_relocs = nitems;
}
if(section_type == S_LAZY_SYMBOL_POINTERS && s->nreloc != nitems){
error_with_cur_obj("malformed object (lazy symbol pointer section "
"(%.16s,%.16s) does not have is exactly one relocation entry "
"for each pointer)", s->segname, s->sectname);
return;
}
relocs = (struct relocation_info *)(cur_obj->obj_addr + s->reloff);
for(i = 0; i < s->nreloc; i++){
reloc = relocs[i];
if(cur_obj->swapped &&
section_map->input_relocs_already_swapped == FALSE)
swap_relocation_info(&reloc, 1, host_byte_sex);
if((reloc.r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)(&reloc);
r_scattered = 1;
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_length = sreloc->r_length;
r_value = sreloc->r_value;
r_type = sreloc->r_type;
r_extern = 0;
r_symbolnum = 0;
for(j = 0; j < cur_obj->nsection_maps; j++){
if(r_value >= cur_obj->section_maps[j].s->addr &&
r_value < cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size){
r_symbolnum = j + 1;
break;
}
}
if(r_symbolnum == 0){
for(j = 0; j < cur_obj->nsection_maps; j++){
if(r_value == cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size){
r_symbolnum = j + 1;
break;
}
}
if(r_symbolnum == 0){
error_with_cur_obj("r_value (0x%x) field of relocation "
"entry %lu in section (%.16s,%.16s) out of range",
(unsigned int)r_value, i, section_map->s->segname,
section_map->s->sectname);
return;
}
}
}
else{
r_scattered = 0;
r_address = reloc.r_address;
r_pcrel = reloc.r_pcrel;
r_length = reloc.r_length;
r_type = reloc.r_type;
r_extern = reloc.r_extern;
r_symbolnum = reloc.r_symbolnum;
}
if(r_type == reloc_pair_r_type(arch_flag.cputype)){
error_with_cur_obj("malformed object (stray relocation PAIR "
"entry (%lu) in section (%.16s,%.16s))", i, s->segname,
s->sectname);
continue;
}
if(r_address >= s->size){
error_with_cur_obj("malformed object (r_address (0x%x) field "
"of relocation entry %ld in section (%.16s,%.16s) out of "
"range)",(unsigned int)r_address, i,s->segname,s->sectname);
continue;
}
if(reloc_has_pair(arch_flag.cputype, r_type)){
if(i + 1 < s->nreloc){
reloc = relocs[i + 1];
if(cur_obj->swapped &&
section_map->input_relocs_already_swapped == FALSE)
swap_relocation_info(&reloc, 1, host_byte_sex);
if((reloc.r_address & R_SCATTERED) != 0){
spair_reloc = (struct scattered_relocation_info *)
&reloc;
pair_r_type = spair_reloc->r_type;
}
else{
pair_r_type = reloc.r_type;
}
}
if(i + 1 >= s->nreloc ||
pair_r_type != reloc_pair_r_type(arch_flag.cputype)){
error_with_cur_obj("malformed object (relocation entry "
"(%lu) in section (%.16s,%.16s) missing following "
"associated PAIR entry)", i, s->segname, s->sectname);
continue;
}
}
if(section_type == S_LAZY_SYMBOL_POINTERS){
if(r_address % 4 != 0){
error_with_cur_obj("malformed object, illegal reference "
"(r_address (0x%x) field of relocation entry %lu in "
"lazy symbol pointer section (%.16s,%.16s) is not a "
"multiple of 4)", (unsigned int)r_address, i,
s->segname, s->sectname);
continue;
}
if(r_length != 2){
error_with_cur_obj("malformed object, illegal reference "
"(r_length (0x%x) field of relocation entry %lu in "
"lazy symbol pointer section (%.16s,%.16s) is not 2 "
"(long))", (unsigned int)r_length, i, s->segname,
s->sectname);
continue;
}
if(r_pcrel != 0){
error_with_cur_obj("malformed object, illegal reference "
"(r_pcrel (0x%x) field of relocation entry %lu in lazy "
"symbol pointer section (%.16s,%.16s) is not 0 "
"(FALSE))", (unsigned int)r_pcrel, i, s->segname,
s->sectname);
continue;
}
if(r_type != 0){
error_with_cur_obj("malformed object, illegal reference "
"(r_type (0x%x) field of relocation entry %lu in lazy "
"symbol pointer section (%.16s,%.16s) is not 0 "
"(VANILLA))", (unsigned int)r_type, i, s->segname,
s->sectname);
continue;
}
if(r_scattered != 0){
error_with_cur_obj("malformed object, illegal reference "
"(relocation entry %lu in lazy symbol pointer section "
"(%.16s,%.16s) is a scattered type)", i, s->segname,
s->sectname);
continue;
}
if(r_extern == 0 && r_symbolnum == R_ABS){
error_with_cur_obj("malformed object, illegal reference "
"(reference from a lazy symbol pointer section (%.16s,"
"%.16s) relocation entry (%lu) which is not to a "
"symbol stub section)", s->segname, s->sectname, i);
continue;
}
}
defined = TRUE;
force_extern_reloc = FALSE;
if(output_for_dyld && r_extern){
if(r_symbolnum >= cur_obj->symtab->nsyms){
error_with_cur_obj("r_symbolnum (%lu) field of external "
"relocation entry %lu in section (%.16s,%.16s) out of "
"range", r_symbolnum, i, s->segname, s->sectname);
continue;
}
undefined_map = bsearch(&r_symbolnum,
cur_obj->undefined_maps, cur_obj->nundefineds,
sizeof(struct undefined_map),
(int (*)(const void *, const void *))undef_bsearch);
if(undefined_map != NULL){
merged_symbol = undefined_map->merged_symbol;
}
else{
if((nlists[r_symbolnum].n_type & N_EXT) != N_EXT){
error_with_cur_obj("r_symbolnum (%lu) field of "
"external relocation entry %lu in section "
"(%.16s,%.16s) refers to a non-external symbol",
r_symbolnum, i, s->segname, s->sectname);
continue;
}
if((nlists[r_symbolnum].n_type & N_TYPE) == N_SECT &&
(cur_obj->section_maps[nlists[r_symbolnum].
n_sect-1].s->flags & SECTION_TYPE) == S_COALESCED){
merged_symbol = lookup_symbol(strings +
nlists[r_symbolnum].n_un.n_strx);
if(merged_symbol->name_len == 0){
fatal("internal error, in indirect_section_merge() "
"failed to lookup coalesced symbol %s",
strings + nlists[r_symbolnum].n_un.n_strx);
}
if(((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT &&
keep_private_externs == FALSE) ||
dynamic == FALSE ||
(output_for_dyld && has_dynamic_linker_command))
force_extern_reloc = FALSE;
else
force_extern_reloc = TRUE;
}
else{
if(nlists[r_symbolnum].n_type != (N_EXT | N_UNDF)){
error_with_cur_obj("r_symbolnum (%lu) field of "
"external relocation entry %lu in section "
"(%.16s,%.16s) refers to a non-undefined "
"symbol", r_symbolnum, i,
section_map->s->segname,
section_map->s->sectname);
return;
}
print_obj_name(cur_obj);
fatal("internal error, in indirect_section_merge()"
" symbol index %lu in above file not in "
"undefined map", r_symbolnum);
}
}
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF) ||
merged_symbol->nlist.n_type == (N_EXT | N_PBUD) ||
(merged_symbol->nlist.n_type == (N_EXT | N_INDR) &&
merged_symbol->defined_in_dylib == TRUE)){
if(merged_symbol->error_flagged_for_dylib == 0){
error_with_cur_obj("illegal undefined reference "
"for multi module MH_DYLIB output file to "
"symbol: %s from section (%.16s,%.16s) "
"relocation entry: %lu",
merged_symbol->nlist.n_un.n_name, s->segname,
s->sectname, i);
merged_symbol->error_flagged_for_dylib = 1;
}
}
else if((merged_symbol->nlist.n_type & N_PEXT) != N_PEXT){
if(merged_symbol->error_flagged_for_dylib == 0){
error_with_cur_obj("illegal external reference for "
"multi module MH_DYLIB output file to symbol: "
"%s (not a private extern symbol) from section "
"(%.16s,%.16s) relocation entry: %lu",
merged_symbol->nlist.n_un.n_name,
s->segname, s->sectname, i);
merged_symbol->error_flagged_for_dylib = 1;
}
}
}
else{
if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF) ||
merged_symbol->nlist.n_type == (N_EXT | N_PBUD) ||
(merged_symbol->nlist.n_type == (N_EXT | N_INDR) &&
merged_symbol->defined_in_dylib == TRUE))
defined = FALSE;
else
defined = TRUE;
}
}
if(reloc_has_pair(arch_flag.cputype, r_type))
pair = 1;
else
pair = 0;
#ifndef RLD
if(output_for_dyld &&
fine_reloc_offset_in_output(section_map, r_address)){
if(dead_strip == FALSE || redo_live == TRUE)
ms->relocated = TRUE;
if(r_extern == 0)
pic = (enum bool)
(reloc_is_sectdiff(arch_flag.cputype, r_type) ||
(r_pcrel == 1 && r_symbolnum != NO_SECT));
else
pic = (enum bool)
(r_pcrel == 1 &&
(merged_symbol->nlist.n_type & N_TYPE) == N_SECT);
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
if(pic == FALSE)
ms->nlocrel += 1 + pair;
}
else if(has_dynamic_linker_command){
if(r_extern){
if(defined == FALSE)
ms->nextrel += 1 + pair;
else if(save_lazy_symbol_pointer_relocs == TRUE &&
section_type == S_LAZY_SYMBOL_POINTERS)
ms->nlocrel += 1 + pair;
}
else if(save_lazy_symbol_pointer_relocs == TRUE &&
section_type == S_LAZY_SYMBOL_POINTERS){
ms->nlocrel += 1 + pair;
}
}
else{
if(r_extern){
if(defined == FALSE || force_extern_reloc == TRUE)
ms->nextrel += 1 + pair;
else if(pic == FALSE)
ms->nlocrel += 1 + pair;
}
else if(pic == FALSE)
ms->nlocrel += 1 + pair;
}
}
else if(save_reloc &&
fine_reloc_offset_in_output(section_map, r_address)){
ms->s.nreloc += 1 + pair;
nreloc += 1 + pair;
}
#endif
i += pair;
}
if(ms->s.nreloc != 0){
if(dead_strip == FALSE || redo_live == TRUE)
ms->relocated = TRUE;
}
if(dead_strip == FALSE || redo_live == TRUE){
for(nsect = 0; nsect < cur_obj->nsection_maps; nsect++)
if(s == cur_obj->section_maps[nsect].s)
break;
nsect++;
strings = (char *)(cur_obj->obj_addr + cur_obj->symtab->stroff);
discard_local_symbols_for_section(nsect, nlists, strings, s,
section_map);
}
}
static
unsigned long
lookup_indirect_item(
struct merged_symbol *merged_symbol,
struct object_file *obj,
unsigned long index,
struct indirect_section_data *data,
unsigned long stride,
enum bool *new)
{
unsigned long hashval, output_offset;
struct indirect_item_block **p, *indirect_item_block;
struct indirect_item *indirect_item;
struct indirect_item_bucket *bp;
if(data->hashtable == NULL){
data->hashtable = allocate(sizeof(struct indirect_item_bucket *) *
INDIRECT_SECTION_HASHSIZE);
memset(data->hashtable, '\0',
sizeof(struct indirect_item_bucket *) *
INDIRECT_SECTION_HASHSIZE);
}
#if defined(DEBUG) && defined(PROBE_COUNT)
data->nprobes++;
#endif
hashval = ((unsigned long)merged_symbol) % INDIRECT_SECTION_HASHSIZE;
for(bp = data->hashtable[hashval]; bp; bp = bp->next){
#if defined(DEBUG) && defined(PROBE_COUNT)
data->nprobes++;
#endif
if(bp->indirect_item->merged_symbol == merged_symbol &&
merged_symbol != NULL){
*new = FALSE;
return(bp->output_offset);
}
}
bp = allocate(sizeof(struct indirect_item_bucket));
output_offset = 0;
for(p = &(data->indirect_item_blocks);
*p ;
p = &(indirect_item_block->next)){
indirect_item_block = *p;
if(indirect_item_block->used != INDIRECT_SECTION_BLOCK_SIZE){
indirect_item = indirect_item_block->indirect_items +
indirect_item_block->used;
indirect_item->merged_symbol = merged_symbol;
indirect_item->obj = obj;
indirect_item->index = index;
bp->indirect_item = indirect_item;
bp->output_offset = output_offset +
indirect_item_block->used * stride;
bp->next = data->hashtable[hashval];
data->hashtable[hashval] = bp;
indirect_item_block->used++;
*new = TRUE;
return(bp->output_offset);
}
output_offset += indirect_item_block->used * stride;
}
*p = allocate(sizeof(struct indirect_item_block));
indirect_item_block = *p;
indirect_item = indirect_item_block->indirect_items;
indirect_item->merged_symbol = merged_symbol;
indirect_item->obj = obj;
indirect_item->index = index;
indirect_item_block->used = 1;
indirect_item_block->next = NULL;
bp->indirect_item = indirect_item;
bp->output_offset = output_offset;
bp->next = data->hashtable[hashval];
data->hashtable[hashval] = bp;
*new = TRUE;
return(bp->output_offset);
}
__private_extern__
void
indirect_section_order(
struct indirect_section_data *data,
struct merged_section *ms)
{
#ifndef RLD
kern_return_t r;
#ifdef __MWERKS__
struct indirect_section_data *dummy1;
struct merged_section *dummy2;
dummy1 = data;
dummy2 = ms;
#endif
warning("section ordering for indirect sections not supported ("
"-sectorder %s %s %s ignored)", ms->s.segname, ms->s.sectname,
ms->order_filename);
if((r = vm_deallocate(mach_task_self(), (vm_address_t)
ms->order_addr, ms->order_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for -sectorder "
"file: %s for section (%.16s,%.16s)",
ms->order_filename, ms->s.segname,
ms->s.sectname);
ms->order_addr = NULL;
#else
#ifdef __MWERKS__
struct indirect_section_data *dummy1;
struct merged_section *dummy2;
dummy1 = data;
dummy2 = ms;
#endif
#endif
}
__private_extern__
void
indirect_section_reset_live(
struct indirect_section_data *data,
struct merged_section *ms)
{
nindirectsyms = 0;
ms->s.size = 0;
if(output_for_dyld){
ms->nlocrel = 0;
ms->nextrel = 0;
}
else if(save_reloc){
nreloc -= ms->s.nreloc;
ms->s.nreloc = 0;
}
indirect_section_free(data);
}
#ifndef RLD
__private_extern__
enum bool
indirect_live_ref(
struct fine_reloc *fine_reloc,
struct section_map *map,
struct object_file *obj,
struct ref *r)
{
unsigned long index, value, r_symbolnum;
struct nlist *nlists;
char *contents;
if((map->s->flags & SECTION_TYPE) != S_SYMBOL_STUBS &&
(map->s->flags & SECTION_TYPE) != S_LAZY_SYMBOL_POINTERS &&
(map->s->flags & SECTION_TYPE) != S_NON_LAZY_SYMBOL_POINTERS)
fatal("internal error: indirect_live_ref() called with map not for "
"indirect section");
if(fine_reloc->local_symbol == TRUE){
if(fine_reloc->use_contents == FALSE){
if((map->s->flags & SECTION_TYPE) ==
S_NON_LAZY_SYMBOL_POINTERS){
fatal("internal error: indirect_live_ref() called "
"with fine_reloc for non-lazy pointer with "
"local_symbol == TRUE and use_contents == "
"FALSE");
}
index = fine_reloc->output_offset;
nlists = (struct nlist *)(obj->obj_addr +
obj->symtab->symoff);
r_symbolnum = r_symbolnum_from_r_value(nlists[index].n_value,
obj);
r->map = &(obj->section_maps[r_symbolnum - 1]);
r->fine_reloc = fine_reloc_for_input_offset(r->map,
nlists[index].n_value - r->map->s->addr);
r->obj = obj;
r->merged_symbol = NULL;
return(TRUE);
}
else{
if((map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
(map->s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS)
fatal("internal error: indirect_live_ref() called "
"with fine_reloc for stub or lazy pointer "
"with local_symbol == TRUE and use_contents "
"== TRUE");
if(fine_reloc->indirect_symbol_local == TRUE){
contents = obj->obj_addr + map->s->offset;
memcpy(&value, contents + fine_reloc->input_offset, 4);
if(obj->swapped)
value = SWAP_LONG(value);
r_symbolnum = r_symbolnum_from_r_value(value, obj);
r->map = &(obj->section_maps[r_symbolnum - 1]);
r->fine_reloc = fine_reloc_for_input_offset(r->map,
value - r->map->s->addr);
r->obj = obj;
r->merged_symbol = NULL;
return(TRUE);
}
else{
return(FALSE);
}
}
}
else{
r->merged_symbol = fine_reloc->merged_symbol;
r->fine_reloc = NULL;
r->map = NULL;
r->obj = NULL;
return(TRUE);
}
}
#endif
__private_extern__
void
indirect_section_free(
struct indirect_section_data *data)
{
unsigned long i;
struct indirect_item_bucket *bp, *next_bp;
struct indirect_item_block *indirect_item_block,
*next_indirect_item_block;
if(data->hashtable != NULL){
for(i = 0; i < INDIRECT_SECTION_HASHSIZE; i++){
for(bp = data->hashtable[i]; bp; ){
next_bp = bp->next;
free(bp);
bp = next_bp;
}
}
free(data->hashtable);
data->hashtable = NULL;
}
for(indirect_item_block = data->indirect_item_blocks;
indirect_item_block;
indirect_item_block = next_indirect_item_block){
next_indirect_item_block = indirect_item_block->next;
free(indirect_item_block);
}
data->indirect_item_blocks = NULL;
}
#endif
__private_extern__
enum bool
legal_reference(
struct section_map *from_map,
unsigned long from_offset,
struct section_map *to_map,
unsigned long to_offset,
unsigned long from_reloc_index,
enum bool sectdiff_reloc)
{
#ifndef SA_RLD
unsigned long to_section_type, from_section_type;
unsigned long *indirect_symtab;
struct fine_reloc *to_fine_reloc, *from_fine_reloc;
struct merged_symbol *merged_symbol;
unsigned long stride;
from_section_type = from_map->s->flags & SECTION_TYPE;
if(from_section_type == S_COALESCED){
from_fine_reloc =
fine_reloc_for_input_offset(from_map, from_offset);
if(from_fine_reloc->use_contents == FALSE)
return(TRUE);
}
to_section_type = to_map->s->flags & SECTION_TYPE;
if(to_section_type == S_COALESCED){
to_fine_reloc = fine_reloc_for_input_offset(to_map, to_offset);
if(to_fine_reloc->local_symbol == TRUE)
return(TRUE);
if(to_fine_reloc->use_contents == FALSE){
merged_symbol = to_fine_reloc->merged_symbol;
if(merged_symbol->defined_in_dylib == TRUE){
if(sectdiff_reloc == TRUE && dynamic == TRUE){
error_with_cur_obj("illegal reference for -dynamic "
"code (section difference reference from section "
"(%.16s,%.16s) relocation entry (%lu) "
"to symbol: %s defined in dylib: %s)",
from_map->s->segname, from_map->s->sectname,
from_reloc_index, merged_symbol->nlist.n_un.n_name,
merged_symbol->definition_object->file_name);
return(FALSE);
}
to_section_type = S_REGULAR;
}
else if((merged_symbol->nlist.n_type & N_TYPE) == N_SECT){
if(merged_symbols_relocated == FALSE)
to_section_type = merged_symbol->definition_object->
section_maps[merged_symbol->nlist.n_sect - 1].s->
flags & SECTION_TYPE;
else
to_section_type =
pass2_nsect_merged_symbol_section_type(
merged_symbol);
}
else{
if(sectdiff_reloc == TRUE && dynamic == TRUE){
if((merged_symbol->nlist.n_type & N_TYPE) == N_ABS){
error_with_cur_obj("illegal reference for -dynamic "
"code (section difference reference from "
"section (%.16s,%.16s) relocation entry (%lu) "
"to absolute symbol: %s)",
from_map->s->segname, from_map->s->sectname,
from_reloc_index,
merged_symbol->nlist.n_un.n_name);
return(FALSE);
}
}
to_section_type = S_REGULAR;
}
}
}
if(dynamic == TRUE && to_section_type == S_COALESCED &&
sectdiff_reloc == TRUE && (from_map != to_map ||
fine_reloc_for_input_offset(from_map, from_offset) !=
fine_reloc_for_input_offset(to_map, to_offset)) &&
fine_reloc_for_input_offset(to_map, to_offset)->local_symbol ==
FALSE){
error_with_cur_obj("malformed object, illegal reference for "
"-dynamic code (reference to a coalesced section (%.16s,"
"%.16s) from section (%.16s,%.16s) relocation entry (%lu))",
to_map->s->segname, to_map->s->sectname, from_map->s->segname,
from_map->s->sectname, from_reloc_index);
return(FALSE);
}
if(to_section_type != S_SYMBOL_STUBS &&
to_section_type != S_LAZY_SYMBOL_POINTERS &&
from_section_type != S_SYMBOL_STUBS &&
from_section_type != S_LAZY_SYMBOL_POINTERS)
return(TRUE);
if(to_section_type == S_SYMBOL_STUBS){
if(from_section_type != S_LAZY_SYMBOL_POINTERS){
if((to_offset % to_map->s->reserved2) != 0){
if(from_section_type == S_SYMBOL_STUBS &&
from_map == to_map &&
from_offset / from_map->s->reserved2 ==
to_offset / to_map->s->reserved2)
return(TRUE);
error_with_cur_obj("malformed object, illegal reference "
"(reference to a symbol stub not at the start of the "
"stub from section (%.16s,%.16s) relocation entry "
"(%lu))", from_map->s->segname, from_map->s->sectname,
from_reloc_index);
return(FALSE);
}
else
return(TRUE);
}
else{
indirect_symtab = (unsigned long *)(cur_obj->obj_addr +
cur_obj->dysymtab->indirectsymoff);
stride = 4;
if(indirect_symtab[from_map->s->reserved1 + from_offset /
stride] !=
indirect_symtab[to_map->s->reserved1 + to_offset /
to_map->s->reserved2]){
error_with_cur_obj("malformed object, illegal reference "
"(reference to symbol stub in section (%.16s,%.16s) "
"at address 0x%x from lazy pointer section "
"(%.16s,%.16s) relocation entry (%lu) with non-"
"matching indirect symbols)", to_map->s->segname,
to_map->s->sectname,
(unsigned int)(to_map->s->addr + to_offset),
from_map->s->segname, from_map->s->sectname,
from_reloc_index);
return(FALSE);
}
else
return(TRUE);
}
}
if(to_section_type == S_LAZY_SYMBOL_POINTERS){
if(from_section_type != S_SYMBOL_STUBS){
error_with_cur_obj("malformed object, illegal reference "
"(reference to a lazy symbol pointer section from section "
"(%.16s,%.16s) relocation entry (%lu) which is not a "
"symbol stub section)", from_map->s->segname,
from_map->s->sectname, from_reloc_index);
return(FALSE);
}
else{
indirect_symtab = (unsigned long *)(cur_obj->obj_addr +
cur_obj->dysymtab->indirectsymoff);
stride = (arch_flag.cputype == CPU_TYPE_POWERPC64 ? 8 : 4);
if(indirect_symtab[from_map->s->reserved1 + from_offset /
from_map->s->reserved2] !=
indirect_symtab[to_map->s->reserved1 + to_offset / stride]){
error_with_cur_obj("malformed object, illegal reference "
"(reference to lazy symbol pointer section "
"(%.16s,%.16s) at address 0x%x from symbol stub "
"section (%.16s,%.16s) relocation entry (%lu) with "
"non-matching indirect symbols)",
to_map->s->segname, to_map->s->sectname,
(unsigned int)(to_map->s->addr + to_offset),
from_map->s->segname, from_map->s->sectname,
from_reloc_index);
return(FALSE);
}
else
return(TRUE);
}
}
if(from_section_type == S_SYMBOL_STUBS){
return(TRUE);
}
#endif
return(TRUE);
}
#ifndef SA_RLD
__private_extern__
void
output_indirect_symbols(
void)
{
unsigned long i, nindirect_symbols;
uint32_t *indirect_symbols;
struct merged_segment **p, *msg;
struct merged_section **content, *ms;
struct indirect_section_data *data;
struct indirect_item_block **q, *indirect_item_block;
struct indirect_item *indirect_item;
if(nindirectsyms == 0)
return;
if(strip_level == STRIP_ALL)
fatal("can't use -s with input files containing indirect symbols "
"(output file must contain at least global symbols, for "
"maximum stripping use -x)");
indirect_symbols = (uint32_t *)(output_addr +
output_dysymtab_info.dysymtab_command.indirectsymoff);
nindirect_symbols = 0;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->s.flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
(ms->s.flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
(ms->s.flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS){
data = (struct indirect_section_data *)ms->literal_data;
ms->s.reserved1 = nindirect_symbols;
for(q = &(data->indirect_item_blocks);
*q ;
q = &(indirect_item_block->next)){
indirect_item_block = *q;
for(i = 0; i < indirect_item_block->used; i++){
indirect_item = indirect_item_block->
indirect_items + i;
if(indirect_item->merged_symbol != NULL){
if((ms->s.flags & SECTION_TYPE) ==
S_NON_LAZY_SYMBOL_POINTERS &&
(indirect_item->merged_symbol->
nlist.n_type & N_PEXT) == N_PEXT &&
keep_private_externs == FALSE){
if((indirect_item->merged_symbol->
nlist.n_type & N_TYPE) == N_ABS)
indirect_symbols[nindirect_symbols++] =
INDIRECT_SYMBOL_ABS;
else
indirect_symbols[nindirect_symbols++] =
INDIRECT_SYMBOL_LOCAL;
}
else{
indirect_symbols[nindirect_symbols++] =
merged_symbol_output_index(
indirect_item->merged_symbol);
}
}
else{
if(indirect_item->index ==
INDIRECT_SYMBOL_LOCAL ||
indirect_item->index ==
INDIRECT_SYMBOL_ABS){
indirect_symbols[nindirect_symbols++] =
indirect_item->index;
}
else{
indirect_symbols[nindirect_symbols++] =
local_symbol_output_index(
indirect_item->obj,
indirect_item->index);
}
}
}
}
}
content = &(ms->next);
}
p = &(msg->next);
}
if(nindirect_symbols != nindirectsyms)
fatal("internal error, nindirect_symbols != nindirectsyms in "
"output_indirect_symbols()");
if(host_byte_sex != target_byte_sex)
swap_indirect_symbols(indirect_symbols, nindirect_symbols,
target_byte_sex);
#ifndef RLD
output_flush(output_dysymtab_info.dysymtab_command.indirectsymoff,
nindirect_symbols * sizeof(uint32_t));
#endif
}
#endif