#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 <sys/time.h>
#include "stuff/openstep_mach.h"
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include <mach-o/ppc/reloc.h>
#include <mach-o/hppa/reloc.h>
#include <ar.h>
#include "stuff/arch.h"
#include "stuff/reloc.h"
#include "ld.h"
#include "specs.h"
#include "live_refs.h"
#include "objects.h"
#include "pass1.h"
#include "symbols.h"
#include "sections.h"
#include "cstring_literals.h"
#include "4byte_literals.h"
#include "8byte_literals.h"
#include "literal_pointers.h"
#include "indirect_sections.h"
#include "mod_sections.h"
#include "coalesced_sections.h"
#include "pass2.h"
#include "generic_reloc.h"
#include "i860_reloc.h"
#include "ppc_reloc.h"
#include "m88k_reloc.h"
#include "hppa_reloc.h"
#include "sparc_reloc.h"
#include "arm_reloc.h"
#include "sets.h"
#include "hash_string.h"
#include "layout.h"
#include "dylibs.h"
__private_extern__ struct merged_segment *merged_segments = NULL;
#ifdef RLD
__private_extern__ struct merged_segment *original_merged_segments = NULL;
#endif
__private_extern__ struct merged_segment *debug_merged_segments = NULL;
__private_extern__ unsigned long nreloc = 0;
__private_extern__ enum bool some_non_subsection_via_symbols_objects = FALSE;
static const char *
#ifndef __DYNAMIC__
const
#endif
section_flags[] = {
"S_REGULAR",
"S_ZEROFILL",
"S_CSTRING_LITERALS",
"S_4BYTE_LITERALS",
"S_8BYTE_LITERALS",
"S_LITERAL_POINTERS",
"S_NON_LAZY_SYMBOL_POINTERS",
"S_LAZY_SYMBOL_POINTERS",
"S_SYMBOL_STUBS",
"S_MOD_INIT_FUNC_POINTERS",
"S_MOD_TERM_FUNC_POINTERS",
"S_COALESCED"
};
#ifndef RLD
struct archive_name {
char *archive_name;
struct object_name
*object_names;
unsigned long
nobject_names;
};
static struct archive_name *archive_names = NULL;
static unsigned long narchive_names = 0;
struct object_name {
char *object_name;
unsigned long
index_length;
struct object_file
*object_file;
};
static struct object_name *object_names = NULL;
static unsigned long nobject_names = 0;
struct load_symbol {
char *symbol_name;
char *object_name;
char *archive_name;
unsigned long
index_length;
struct load_order
*load_order;
struct load_symbol
*other_names;
struct load_symbol
*next;
};
#define LOAD_SYMBOL_HASHTABLE_SIZE 10000
static struct load_symbol **load_symbol_hashtable = NULL;
static struct load_symbol *load_symbols = NULL;
static unsigned long load_symbols_size = 0;
static unsigned long load_symbols_used = 0;
static unsigned long ambiguous_specifications = 0;
static void layout_ordered_section(
struct merged_section *ms);
static void create_name_arrays(
void);
static struct archive_name *create_archive_name(
char *archive_name);
static void create_object_name(
struct object_name **object_names,
unsigned long *nobject_names,
char *object_name,
unsigned long index_length,
char *archive_name);
static void free_name_arrays(
void);
static void create_load_symbol_hash_table(
unsigned long nsection_symbols,
struct merged_section *ms);
static void free_load_symbol_hash_table(
void);
static void create_load_symbol_hash_table_for_object(
char *archive_name,
char *object_name,
unsigned long index_length,
struct load_order *load_orders,
unsigned long nload_orders,
struct merged_section *ms);
static struct load_order *lookup_load_order(
char *archive_name,
char *object_name,
char *symbol_name,
struct merged_section *ms,
unsigned long line_number);
static char * trim(
char *name);
static struct section_map *lookup_section_map(
char *archive_name,
char *object_name);
static int qsort_load_order_names(
const struct load_order *load_order1,
const struct load_order *load_order2);
static int bsearch_load_order_names(
char *symbol_name,
const struct load_order *load_order);
static int qsort_load_order_input_offset(
const struct load_order *load_order1,
const struct load_order *load_order2);
static int qsort_archive_names(
const struct archive_name *archive_name1,
const struct archive_name *archive_name2);
static int bsearch_archive_names(
const char *name,
const struct archive_name *archive_name);
static int qsort_object_names(
const struct object_name *object_name1,
const struct object_name *object_name2);
static int bsearch_object_names(
const char *name,
const struct object_name *object_name);
static int qsort_fine_reloc_input_offset(
const struct fine_reloc *fine_reloc1,
const struct fine_reloc *fine_reloc2);
static int qsort_order_load_map_orders(
const struct order_load_map *order_load_map1,
const struct order_load_map *order_load_map2);
static void create_order_load_maps(
struct merged_section *ms,
unsigned long norder_load_maps);
#ifdef DEBUG
static void print_symbol_name_from_order_load_maps(
struct section_map *map,
unsigned long value);
#endif
static void resize_live_section(
struct merged_section *ms);
static void count_relocs(
struct section_map *map,
struct relocation_info *relocs,
unsigned long *nlocrel,
unsigned long *nextrel);
#endif
static void scatter_copy(
struct section_map *map,
char *contents);
#ifndef RLD
static void reloc_output_for_dyld(
struct section_map *map,
struct relocation_info *relocs,
struct relocation_info *output_locrel,
struct relocation_info *output_extrel,
unsigned long *nlocrel,
unsigned long *nextrel);
static enum bool is_merged_section_read_only(
struct merged_section *key);
static unsigned long scatter_copy_relocs(
struct section_map *map,
struct relocation_info *relocs,
struct relocation_info *output_relocs);
static double calculate_time_used(
struct timeval *start,
struct timeval *end);
static void build_references(
void);
static void print_references(
void);
static void setup_references_in_section(
struct merged_section *ms);
static void setup_references(
struct section_map *map,
struct object_file *obj);
static void setup_reference(
struct live_ref *ref,
struct object_file *obj,
struct fine_reloc *self_fine_reloc);
static void mark_all_fine_relocs_live_in_section(
struct merged_section *ms);
enum walk_references_operation {
MARK_LIVE,
SEARCH_FOR_LIVE,
CHECK_FOR_LIVE_TOUCH
};
#ifdef DEBUG
char * walk_references_operation_names[] = {
"MARK_LIVE",
"SEARCH_FOR_LIVE",
"CHECK_FOR_LIVE_TOUCH"
};
#endif
static void walk_references_in_section(
enum walk_references_operation operation,
struct merged_section *ms);
static enum bool walk_references(
enum walk_references_operation operation,
struct fine_reloc *fine_reloc,
struct section_map *map,
struct object_file *obj);
static enum bool ref_operation(
enum walk_references_operation operation,
struct ref *ref,
struct object_file *obj);
#endif
#ifdef DEBUG
static void print_load_symbol_hash_table(
void);
#endif
__private_extern__
void
merge_sections(void)
{
unsigned long i;
struct section *s;
struct merged_section *ms;
struct mach_header *mh;
if(cur_obj != base_obj){
mh = (struct mach_header *)(cur_obj->obj_addr);
if((mh->flags & MH_SUBSECTIONS_VIA_SYMBOLS) !=
MH_SUBSECTIONS_VIA_SYMBOLS){
some_non_subsection_via_symbols_objects = TRUE;
}
}
for(i = 0; i < cur_obj->nsection_maps; i++){
s = cur_obj->section_maps[i].s;
ms = create_merged_section(s);
if(errors)
return;
cur_obj->section_maps[i].output_section = ms;
if((s->flags & S_ATTR_DEBUG) == S_ATTR_DEBUG){
ms->s.flags |= S_ATTR_DEBUG;
output_uuid_info.emit = TRUE;
continue;
}
switch(ms->s.flags & SECTION_TYPE){
case S_REGULAR:
case S_ZEROFILL:
if(cur_obj != base_obj && s->size != 0){
cur_obj->section_maps[i].flush_offset = ms->s.size;
ms->s.size = rnd(ms->s.size, 1 << s->align);
cur_obj->section_maps[i].offset = ms->s.size;
ms->s.size += s->size;
ms->s.nreloc += s->nreloc;
nreloc += s->nreloc;
}
#ifdef KLD
if(cur_obj != base_obj)
#endif
if(s->align > ms->s.align)
ms->s.align = s->align;
if(dynamic == TRUE)
ms->s.flags |= (s->flags & SECTION_ATTRIBUTES);
break;
case S_CSTRING_LITERALS:
case S_4BYTE_LITERALS:
case S_8BYTE_LITERALS:
case S_LITERAL_POINTERS:
case S_SYMBOL_STUBS:
case S_NON_LAZY_SYMBOL_POINTERS:
case S_LAZY_SYMBOL_POINTERS:
case S_MOD_INIT_FUNC_POINTERS:
case S_MOD_TERM_FUNC_POINTERS:
case S_COALESCED:
if(arch_flag.cputype == CPU_TYPE_I860)
error_with_cur_obj("literal section (%.16s,%.16s) "
"not allowed in I860 cputype objects",
ms->s.segname, ms->s.sectname);
#ifdef KLD
if(cur_obj != base_obj)
#endif
if(s->align > ms->s.align)
ms->s.align = s->align;
if(dynamic == TRUE)
ms->s.flags |= (s->flags & SECTION_ATTRIBUTES);
break;
default:
fatal("internal error: merge_section() called "
"with unknown section type (0x%x) for section (%.16s,"
"%.16s)", (unsigned int)(ms->s.flags & SECTION_TYPE),
ms->s.segname, ms->s.sectname);
break;
}
#ifndef RLD
if(filetype == MH_DYLIB &&
strcmp(s->segname, SEG_OBJC) == 0 &&
strcmp(s->sectname, SECT_OBJC_MODULES) == 0){
if((ms->s.flags & SECTION_TYPE) != S_REGULAR)
error_with_cur_obj("for MH_DYLIB output files section "
"(%.16s,%.16s) must have a section type of S_REGULAR",
s->segname, s->sectname);
cur_obj->objc_module_info = cur_obj->section_maps + i;
}
#endif
}
}
__private_extern__
struct merged_section *
create_merged_section(
struct section *s)
{
struct merged_segment **p, *msg;
struct merged_section **q, **r, *ms;
p = &merged_segments;
while(*p){
msg = *p;
if(strncmp(msg->sg.segname, s->segname, sizeof(s->segname)) == 0){
if(msg->debug_only == TRUE &&
(s->flags & S_ATTR_DEBUG) != S_ATTR_DEBUG){
error_with_cur_obj("section's (%.16s,%.16s) does not have "
"have debug attribute (S_ATTR_DEBUG) which does not "
"match previously loaded object's sections for this "
"segment", s->segname, s->sectname);
return(NULL);
}
if(msg->debug_only == FALSE &&
(s->flags & S_ATTR_DEBUG) == S_ATTR_DEBUG){
error_with_cur_obj("section's (%.16s,%.16s) has debug "
"attribute (S_ATTR_DEBUG) which does not match "
"previously loaded object's sections for this segment",
s->segname, s->sectname);
return(NULL);
}
if((s->flags & SECTION_TYPE) == S_ZEROFILL){
q = &(msg->zerofill_sections);
r = &(msg->content_sections);
}
else{
q = &(msg->content_sections);
r = &(msg->zerofill_sections);
}
while(*q){
ms = *q;
if(strncmp(ms->s.sectname, s->sectname,
sizeof(s->sectname)) == 0){
if((ms->s.flags & SECTION_TYPE) !=
(s->flags & SECTION_TYPE)){
error_with_cur_obj("section's (%.16s,%.16s) type "
"%s does not match previous objects type %s",
s->segname, s->sectname,
section_flags[s->flags & SECTION_TYPE],
section_flags[ms->s.flags & SECTION_TYPE]);
return(NULL);
}
if((ms->s.flags & SECTION_TYPE) == S_SYMBOL_STUBS &&
ms->s.reserved2 != s->reserved2){
error_with_cur_obj("section's (%.16s,%.16s) sizeof "
"stub %u does not match previous objects "
"sizeof stub %u", s->segname, s->sectname,
s->reserved2, ms->s.reserved2);
return(NULL);
}
return(ms);
}
q = &(ms->next);
}
while(*r){
ms = *r;
if(strncmp(ms->s.sectname, s->sectname,
sizeof(s->sectname)) == 0){
error_with_cur_obj("section's (%.16s,%.16s) type %s "
"does not match previous objects type %s",
s->segname, s->sectname,
section_flags[s->flags & SECTION_TYPE],
section_flags[ms->s.flags & SECTION_TYPE]);
return(NULL);
}
r = &(ms->next);
}
msg->sg.nsects++;
*q = allocate(sizeof(struct merged_section));
ms = *q;
memset(ms, '\0', sizeof(struct merged_section));
strncpy(ms->s.sectname, s->sectname, sizeof(s->sectname));
strncpy(ms->s.segname, s->segname, sizeof(s->segname));
ms->output_sectnum = 1;
if(dynamic != TRUE)
ms->s.flags = (s->flags & ~SECTION_ATTRIBUTES);
else
ms->s.flags = s->flags;
if((ms->s.flags & SECTION_TYPE) == S_CSTRING_LITERALS){
ms->literal_data = allocate(sizeof(struct cstring_data));
memset(ms->literal_data, '\0', sizeof(struct cstring_data));
ms->literal_merge = cstring_merge;
ms->literal_order = cstring_order;
ms->literal_reset_live = cstring_reset_live;
ms->literal_output = cstring_output;
ms->literal_free = cstring_free;
}
else if((ms->s.flags & SECTION_TYPE) == S_4BYTE_LITERALS){
ms->literal_data = allocate(sizeof(struct literal4_data));
memset(ms->literal_data, '\0',sizeof(struct literal4_data));
ms->literal_merge = literal4_merge;
ms->literal_order = literal4_order;
ms->literal_reset_live = literal4_reset_live;
ms->literal_output = literal4_output;
ms->literal_free = literal4_free;
}
else if((ms->s.flags & SECTION_TYPE) == S_8BYTE_LITERALS){
ms->literal_data = allocate(sizeof(struct literal8_data));
memset(ms->literal_data, '\0',sizeof(struct literal8_data));
ms->literal_merge = literal8_merge;
ms->literal_order = literal8_order;
ms->literal_reset_live = literal8_reset_live;
ms->literal_output = literal8_output;
ms->literal_free = literal8_free;
}
else if((ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS){
ms->literal_data =
allocate(sizeof(struct literal_pointer_data));
memset(ms->literal_data, '\0',
sizeof(struct literal_pointer_data));
ms->literal_merge = literal_pointer_merge;
ms->literal_order = literal_pointer_order;
ms->literal_reset_live = literal_pointer_reset_live;
ms->literal_output = literal_pointer_output;
ms->literal_free = literal_pointer_free;
}
#ifndef SA_RLD
else 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){
ms->literal_data =
allocate(sizeof(struct indirect_section_data));
memset(ms->literal_data, '\0',
sizeof(struct indirect_section_data));
ms->literal_merge = indirect_section_merge;
ms->literal_order = indirect_section_order;
ms->literal_reset_live = indirect_section_reset_live;
ms->literal_output = NULL;
ms->literal_free = indirect_section_free;
if((ms->s.flags & SECTION_TYPE) == S_SYMBOL_STUBS)
ms->s.reserved2 = s->reserved2;
}
#endif
else if((ms->s.flags & SECTION_TYPE) ==
S_MOD_INIT_FUNC_POINTERS ||
(ms->s.flags & SECTION_TYPE) ==
S_MOD_TERM_FUNC_POINTERS){
ms->literal_data = allocate(sizeof(struct mod_term_data));
memset(ms->literal_data, '\0',
sizeof(struct mod_term_data));
ms->literal_merge = mod_section_merge;
ms->literal_order = mod_section_order;
ms->literal_reset_live = mod_section_reset_live;
ms->literal_output = NULL;
ms->literal_free = mod_section_free;
}
else if((ms->s.flags & SECTION_TYPE) == S_COALESCED){
ms->literal_data = NULL;
ms->literal_merge = coalesced_section_merge;
ms->literal_order = coalesced_section_order;
ms->literal_reset_live = coalesced_section_reset_live;
ms->literal_output = NULL;
ms->literal_free = NULL;
}
#ifdef RLD
ms->set_num = cur_set;
#endif
return(ms);
}
p = &(msg->next);
}
*p = allocate(sizeof(struct merged_segment));
msg = *p;
memset(msg, '\0', sizeof(struct merged_segment));
strncpy(msg->sg.segname, s->segname, sizeof(s->segname));
msg->sg.nsects = 1;
msg->filename = outputfile;
#ifdef RLD
msg->set_num = cur_set;
#endif
if((s->flags & SECTION_TYPE) == S_ZEROFILL)
q = &(msg->zerofill_sections);
else
q = &(msg->content_sections);
*q = allocate(sizeof(struct merged_section));
ms = *q;
memset(ms, '\0', sizeof(struct merged_section));
strncpy(ms->s.sectname, s->sectname, sizeof(s->sectname));
strncpy(ms->s.segname, s->segname, sizeof(s->segname));
ms->output_sectnum = 1;
if(dynamic != TRUE)
ms->s.flags = (s->flags & ~SECTION_ATTRIBUTES);
else
ms->s.flags = s->flags;
if((ms->s.flags & SECTION_TYPE) == S_CSTRING_LITERALS){
ms->literal_data = allocate(sizeof(struct cstring_data));
memset(ms->literal_data, '\0', sizeof(struct cstring_data));
ms->literal_merge = cstring_merge;
ms->literal_order = cstring_order;
ms->literal_reset_live = cstring_reset_live;
ms->literal_output = cstring_output;
ms->literal_free = cstring_free;
}
else if((ms->s.flags & SECTION_TYPE) == S_4BYTE_LITERALS){
ms->literal_data = allocate(sizeof(struct literal4_data));
memset(ms->literal_data, '\0', sizeof(struct literal4_data));
ms->literal_merge = literal4_merge;
ms->literal_order = literal4_order;
ms->literal_reset_live = literal4_reset_live;
ms->literal_output = literal4_output;
ms->literal_free = literal4_free;
}
else if((ms->s.flags & SECTION_TYPE) == S_8BYTE_LITERALS){
ms->literal_data = allocate(sizeof(struct literal8_data));
memset(ms->literal_data, '\0', sizeof(struct literal8_data));
ms->literal_merge = literal8_merge;
ms->literal_order = literal8_order;
ms->literal_reset_live = literal8_reset_live;
ms->literal_output = literal8_output;
ms->literal_free = literal8_free;
}
else if((ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS) {
ms->literal_data = allocate(sizeof(struct literal_pointer_data));
memset(ms->literal_data, '\0', sizeof(struct literal_pointer_data));
ms->literal_merge = literal_pointer_merge;
ms->literal_order = literal_pointer_order;
ms->literal_reset_live = literal_pointer_reset_live;
ms->literal_output = literal_pointer_output;
ms->literal_free = literal_pointer_free;
}
#ifndef SA_RLD
else 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){
ms->literal_data = allocate(sizeof(struct indirect_section_data));
memset(ms->literal_data, '\0',sizeof(struct indirect_section_data));
ms->literal_merge = indirect_section_merge;
ms->literal_order = indirect_section_order;
ms->literal_reset_live = indirect_section_reset_live;
ms->literal_output = NULL;
ms->literal_free = indirect_section_free;
if((ms->s.flags & SECTION_TYPE) == S_SYMBOL_STUBS)
ms->s.reserved2 = s->reserved2;
}
#endif
else if((ms->s.flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
(ms->s.flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS){
ms->literal_data = NULL;
ms->literal_merge = mod_section_merge;
ms->literal_order = mod_section_order;
ms->literal_reset_live = mod_section_reset_live;
ms->literal_output = NULL;
ms->literal_free = NULL;
}
else if((ms->s.flags & SECTION_TYPE) == S_COALESCED){
ms->literal_data = NULL;
ms->literal_merge = coalesced_section_merge;
ms->literal_order = coalesced_section_order;
ms->literal_reset_live = coalesced_section_reset_live;
ms->literal_output = NULL;
ms->literal_free = NULL;
}
#ifdef RLD
ms->set_num = cur_set;
#endif
msg->debug_only = (s->flags & S_ATTR_DEBUG) == S_ATTR_DEBUG;
return(ms);
}
__private_extern__
struct merged_segment *
lookup_merged_segment(
char *segname)
{
struct merged_segment **p, *msg;
p = &merged_segments;
while(*p){
msg = *p;
if(strncmp(msg->sg.segname, segname, sizeof(msg->sg.segname)) == 0)
return(msg);
p = &(msg->next);
}
return(NULL);
}
__private_extern__
struct merged_section *
lookup_merged_section(
char *segname,
char *sectname)
{
struct merged_segment **p, *msg;
struct merged_section **q, *ms;
p = &merged_segments;
while(*p){
msg = *p;
if(strncmp(msg->sg.segname, segname, sizeof(msg->sg.segname)) == 0){
q = &(msg->content_sections);
while(*q){
ms = *q;
if(strncmp(ms->s.sectname, sectname,
sizeof(ms->s.sectname)) == 0){
return(ms);
}
q = &(ms->next);
}
q = &(msg->zerofill_sections);
while(*q){
ms = *q;
if(strncmp(ms->s.sectname, sectname,
sizeof(ms->s.sectname)) == 0){
return(ms);
}
q = &(ms->next);
}
return(NULL);
}
p = &(msg->next);
}
return(NULL);
}
__private_extern__
void
remove_debug_segments(
void)
{
struct merged_segment **p, **q, *msg;
struct merged_section **c, *ms;
p = &merged_segments;
q = &debug_merged_segments;
while(*p){
msg = *p;
if(msg->debug_only == TRUE){
*q = msg;
q = &(msg->next);
*p = msg->next;
c = &(msg->content_sections);
while(*c){
ms = *c;
ms->output_sectnum = MAX_SECT + 1;
c = &(ms->next);
}
}
p = &(msg->next);
}
if(*q != NULL){
*q = NULL;
}
}
__private_extern__
void
merge_literal_sections(
enum bool redo_live)
{
unsigned long i, j;
struct object_list *object_list, **p;
struct merged_section *ms;
#ifndef RLD
struct merged_segment **q, *msg;
struct merged_section **content;
q = &merged_segments;
while(*q){
msg = *q;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->s.flags & SECTION_TYPE) == S_CSTRING_LITERALS ||
(ms->s.flags & SECTION_TYPE) == S_4BYTE_LITERALS ||
(ms->s.flags & SECTION_TYPE) == S_8BYTE_LITERALS ||
(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 ||
(ms->s.flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
(ms->s.flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS ||
(ms->s.flags & SECTION_TYPE) == S_COALESCED){
if(redo_live == FALSE){
if(ms->order_filename != NULL)
(*ms->literal_order)(ms->literal_data, ms);
}
else
(*ms->literal_reset_live)(ms->literal_data, ms);
}
content = &(ms->next);
}
q = &(msg->next);
}
#endif
for(p = &objects; *p; p = &(object_list->next)){
object_list = *p;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
#ifdef RLD
if(cur_obj->set_num != cur_set)
continue;
#endif
for(j = 0; j < cur_obj->nsection_maps; j++){
ms = cur_obj->section_maps[j].output_section;
if((ms->s.flags & SECTION_TYPE) == S_CSTRING_LITERALS ||
(ms->s.flags & SECTION_TYPE) == S_4BYTE_LITERALS ||
(ms->s.flags & SECTION_TYPE) == S_8BYTE_LITERALS ||
(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 ||
(ms->s.flags & SECTION_TYPE) ==
S_MOD_INIT_FUNC_POINTERS ||
(ms->s.flags & SECTION_TYPE) ==
S_MOD_TERM_FUNC_POINTERS ||
(ms->s.flags & SECTION_TYPE) == S_COALESCED)
(*ms->literal_merge)(ms->literal_data, ms,
cur_obj->section_maps[j].s,
&(cur_obj->section_maps[j]),
redo_live);
}
}
}
#ifndef RLD
q = &merged_segments;
while(*q){
msg = *q;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS){
if(redo_live == FALSE){
if(ms->order_filename != NULL)
(*ms->literal_order)(ms->literal_data, ms);
}
else{
(*ms->literal_reset_live)(ms->literal_data, ms);
}
}
content = &(ms->next);
}
q = &(msg->next);
}
#endif
for(p = &objects; *p; p = &(object_list->next)){
object_list = *p;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
#ifdef RLD
if(cur_obj->set_num != cur_set)
continue;
#endif
for(j = 0; j < cur_obj->nsection_maps; j++){
ms = cur_obj->section_maps[j].output_section;
if((ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS)
(*ms->literal_merge)(ms->literal_data, ms,
cur_obj->section_maps[j].s,
&(cur_obj->section_maps[j]),
redo_live);
}
}
}
}
#ifndef RLD
__private_extern__
void
layout_ordered_sections(void)
{
enum bool ordered_sections;
struct merged_segment **p, *msg;
struct merged_section **content, **zerofill, *ms;
struct object_file *last_object;
ordered_sections = FALSE;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->order_filename != NULL){
ordered_sections = TRUE;
break;
}
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
if(ms->order_filename != NULL){
ordered_sections = TRUE;
break;
}
zerofill = &(ms->next);
}
if(ordered_sections == TRUE)
break;
p = &(msg->next);
}
if(ordered_sections == FALSE && dead_strip == FALSE)
return;
last_object = add_last_object_file(&link_edit_common_object);
create_name_arrays();
#ifdef DEBUG
if(debug & (1 << 13))
print_name_arrays();
#endif
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->order_filename == NULL && dead_strip == FALSE) ||
ms->contents_filename != NULL){
content = &(ms->next);
continue;
}
if((ms->s.flags & SECTION_TYPE) == S_REGULAR)
layout_ordered_section(ms);
if(errors != 0)
return;
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
if(ms->order_filename == NULL && dead_strip == FALSE){
zerofill = &(ms->next);
continue;
}
layout_ordered_section(ms);
if(errors != 0)
return;
zerofill = &(ms->next);
}
p = &(msg->next);
}
free_load_symbol_hash_table();
if(load_map == FALSE)
free_name_arrays();
remove_last_object_file(last_object);
}
static
void
layout_ordered_section(
struct merged_section *ms)
{
unsigned long i, j, k, l;
struct object_list *object_list, **q;
unsigned long nsect, nload_orders, nsection_symbols;
struct load_order *load_orders;
enum bool start_section, any_order;
struct nlist *object_symbols;
char *object_strings;
unsigned long n, order, output_offset, line_number, line_length;
unsigned long unused_specifications, no_specifications;
char *line, *archive_name, *object_name, *symbol_name;
struct load_order *load_order;
struct section_map *section_map;
kern_return_t r;
struct fine_reloc *fine_relocs;
struct merged_symbol *merged_symbol;
nsection_symbols = 0;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
cur_obj->cur_section_map = NULL;
for(j = 0; j < cur_obj->nsection_maps; j++){
if(cur_obj->section_maps[j].output_section != ms)
continue;
if(cur_obj->section_maps[j].s->size == 0)
continue;
if(cur_obj->cur_section_map != NULL){
error_with_cur_obj("can't use -sectorder or -dead_strip"
" with objects that contain more than one section "
"with the same name (section %d and %ld are both "
"named (%.16s,%.16s))", cur_obj->cur_section_map -
cur_obj->section_maps + 1, j + 1, ms->s.segname,
ms->s.sectname);
return;
}
cur_obj->cur_section_map = &(cur_obj->section_maps[j]);
object_symbols = (struct nlist *)(cur_obj->obj_addr
+ cur_obj->symtab->symoff);
object_strings = (char *)(cur_obj->obj_addr +
cur_obj->symtab->stroff);
nsect = j + 1;
nload_orders = 0;
start_section = FALSE;
for(k = 0; k < cur_obj->symtab->nsyms; k++){
if(object_symbols[k].n_sect == nsect &&
(object_symbols[k].n_type & N_STAB) == 0){
nload_orders++;
if(object_symbols[k].n_value ==
cur_obj->section_maps[j].s->addr)
start_section = TRUE;
}
}
if(start_section == FALSE)
nload_orders++;
load_orders = allocate(sizeof(struct load_order) *
nload_orders);
memset(load_orders, '\0',
sizeof(struct load_order) * nload_orders);
cur_obj->section_maps[j].nload_orders= nload_orders;
cur_obj->section_maps[j].load_orders = load_orders;
cur_obj->cur_section_map =
&(cur_obj->section_maps[j]);
cur_obj->cur_section_map->start_section = start_section;
l = 0;
if(start_section == FALSE){
load_orders[l].name = ".section_start";
load_orders[l].value =
cur_obj->section_maps[j].s->addr;
l++;
}
for(k = 0; k < cur_obj->symtab->nsyms; k++){
if(object_symbols[k].n_sect == nsect &&
(object_symbols[k].n_type & N_STAB) == 0){
load_orders[l].name = object_strings +
object_symbols[k].n_un.n_strx;
load_orders[l].value =
object_symbols[k].n_value;
load_orders[l].index = k;
l++;
}
}
#ifdef DEBUG
if(debug & (1 << 14))
print_load_order(load_orders, nload_orders, ms,
cur_obj, "names and values");
#endif
qsort(load_orders,
nload_orders,
sizeof(struct load_order),
(int (*)(const void *, const void *))
qsort_load_order_values);
for(l = 0; l < nload_orders - 1; l++){
load_orders[l].input_offset =
load_orders[l].value -
cur_obj->section_maps[j].s->addr;
load_orders[l].input_size =
load_orders[l + 1].value -
load_orders[l].value;
}
load_orders[l].input_offset = load_orders[l].value -
cur_obj->section_maps[j].s->addr;
load_orders[l].input_size =
cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size -
load_orders[l].value;
#ifdef DEBUG
if(debug & (1 << 15))
print_load_order(load_orders, nload_orders, ms,
cur_obj, "sizes and offsets");
#endif
qsort(load_orders,
nload_orders,
sizeof(struct load_order),
(int (*)(const void *, const void *))
qsort_load_order_names);
#ifdef DEBUG
if(debug & (1 << 16))
print_load_order(load_orders, nload_orders, ms,
cur_obj, "sorted by name");
#endif
nsection_symbols += nload_orders;
}
}
}
create_load_symbol_hash_table(nsection_symbols, ms);
ambiguous_specifications = 0;
#ifdef DEBUG
if(debug & (1 << 13))
print_load_symbol_hash_table();
#endif
for(i = 0; i < ms->order_size; i++){
if(ms->order_addr[i] == '\n')
ms->order_addr[i] = '\0';
}
order = 1;
output_offset = 0;
line_number = 1;
unused_specifications = 0;
for(i = 0; i < ms->order_size; ){
line = ms->order_addr + i;
line_length = strlen(line);
if(*line == '#'){
i += line_length + 1;
line_number++;
continue;
}
parse_order_line(line, &archive_name, &object_name, &symbol_name,
ms, line_number);
load_order = lookup_load_order(archive_name, object_name,
symbol_name, ms, line_number);
if(load_order != NULL){
if(load_order->order != 0){
if(archive_name == NULL){
if(*object_name == '\0'){
warning("multiple specification of symbol: %s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s)",
symbol_name, ms->order_filename,
line_number, ms->s.segname,
ms->s.sectname);
}
else{
warning("multiple specification of %s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s)", object_name,
symbol_name, ms->order_filename,
line_number, ms->s.segname,
ms->s.sectname);
}
}
else
warning("multiple specification of %s:%s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s)", archive_name,
object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname);
}
else{
load_order->order = order++;
load_order->line_number = line_number;
output_offset = align_to_input_mod(output_offset,
load_order->input_offset,
ms->s.align);
load_order->output_offset = output_offset;
output_offset += load_order->input_size;
}
}
else{
if(strncmp(symbol_name, ".section_offset",
sizeof(".section_offset") - 1) == 0){
char *p, *endp;
unsigned long offset;
p = symbol_name + sizeof(".section_offset");
offset = strtoul(p, &endp, 0);
if(*endp != '\0')
error("bad specification of .section_offset in "
"-sectorder file: %s line %lu for section "
"(%.16s,%.16s) (junk after offset value)",
ms->order_filename, line_number, ms->s.segname,
ms->s.sectname);
else if(offset < output_offset)
error("bad offset value (0x%x) of .section_offset in "
"-sectorder file: %s line %lu for section "
"(%.16s,%.16s) (value less than current "
"offset 0x%x)", (unsigned int)offset,
ms->order_filename, line_number, ms->s.segname,
ms->s.sectname, (unsigned int)output_offset);
else
output_offset = offset;
}
if(strncmp(symbol_name, ".section_align",
sizeof(".section_align") - 1) == 0){
char *p, *endp;
unsigned long align;
p = symbol_name + sizeof(".section_align");
align = strtoul(p, &endp, 0);
if(*endp != '\0')
error("bad specification of .section_align in "
"-sectorder file: %s line %lu for section "
"(%.16s,%.16s) (junk after align value)",
ms->order_filename, line_number, ms->s.segname,
ms->s.sectname);
else if(align > MAXSECTALIGN)
error("bad align value (%lu) of .section_align in "
"-sectorder file: %s line %lu for section "
"(%.16s,%.16s) (value must be equal to or less "
"than %d)", align, ms->order_filename,
line_number, ms->s.segname, ms->s.sectname,
MAXSECTALIGN);
else
output_offset = rnd(output_offset, 1 << align);
}
else if(strcmp(symbol_name, ".section_all") == 0){
section_map = lookup_section_map(archive_name,
object_name);
if(section_map != NULL){
section_map->no_load_order = TRUE;
section_map->order = order++;
output_offset = rnd(output_offset,
(1 << section_map->s->align));
section_map->offset = output_offset;
output_offset += section_map->s->size;
}
else if(sectorder_detail == TRUE){
if(archive_name == NULL){
warning("specification of %s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s) not used "
"(object with that section not in "
"loaded objects)", object_name,
symbol_name, ms->order_filename,
line_number, ms->s.segname,
ms->s.sectname);
}
else{
warning("specification of %s:%s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s) not used "
"(object with that section not in "
"loaded objects)", archive_name,
object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname);
}
}
else{
unused_specifications++;
}
}
else if(sectorder_detail == TRUE){
if(archive_name == NULL){
warning("specification of %s:%s in -sectorder "
"file: %s line %lu for section (%.16s,"
"%.16s) not found in loaded objects",
object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname);
}
else{
warning("specification of %s:%s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s) not found in "
"loaded objects", archive_name,
object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname);
}
}
else{
unused_specifications++;
}
}
i += line_length + 1;
line_number++;
}
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;
no_specifications = 0;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
if(cur_obj->cur_section_map == NULL)
continue;
#ifdef DEBUG
if(debug & (1 << 17))
print_load_order(
cur_obj->cur_section_map->load_orders,
cur_obj->cur_section_map->nload_orders,
ms, cur_obj, "file orders assigned");
#endif
load_order = cur_obj->cur_section_map->load_orders;
n = cur_obj->cur_section_map->nload_orders;
qsort(load_order, n, sizeof(struct load_order),
(int (*)(const void *, const void *))
qsort_load_order_input_offset);
any_order = FALSE;
for(j = 0; j < n; j++){
if(load_order[j].order != 0){
any_order = TRUE;
break;
}
}
if(any_order == FALSE &&
cur_obj->cur_section_map->no_load_order == FALSE){
if(dead_strip == FALSE ||
(cur_obj->cur_section_map->s->flags &
S_ATTR_NO_DEAD_STRIP) == S_ATTR_NO_DEAD_STRIP ||
(cur_obj->obj_addr != NULL &&
(((struct mach_header *)(cur_obj->obj_addr))->flags &
MH_SUBSECTIONS_VIA_SYMBOLS) !=
MH_SUBSECTIONS_VIA_SYMBOLS)){
cur_obj->cur_section_map->no_load_order = TRUE;
if(cur_obj->cur_section_map->order == 0)
cur_obj->cur_section_map->order = order++;
output_offset = rnd(output_offset,
(1 << cur_obj->cur_section_map->s->align));
cur_obj->cur_section_map->offset = output_offset;
output_offset += cur_obj->cur_section_map->s->size;
if(sectorder_detail == TRUE &&
ms->order_filename != NULL){
if(no_specifications == 0)
warning("no specification for the following "
"symbols in -sectorder file: %s for "
"section (%.16s,%.16s):",
ms->order_filename,
ms->s.segname, ms->s.sectname);
for(j = 0; j < n; j++){
if(cur_obj->ar_hdr == NULL){
if(nowarnings == FALSE)
print("%s:%s\n", cur_obj->file_name,
load_order[j].name);
}
else{
if(nowarnings == FALSE)
print("%s:%.*s:%s\n",
cur_obj->file_name,
(int)cur_obj->ar_name_size,
cur_obj->ar_name,
load_order[j].name);
}
}
}
no_specifications += n;
}
}
for(j = 0; j < n; j++){
if(load_order[j].order == 0){
if(cur_obj->cur_section_map->no_load_order == TRUE)
continue;
load_order[j].order = order++;
output_offset = align_to_input_mod(
output_offset,
load_order[j].input_offset,
ms->s.align);
load_order[j].output_offset = output_offset;
output_offset += load_order[j].input_size;
if(sectorder_detail == TRUE &&
ms->order_filename != NULL){
if(no_specifications == 0)
warning("no specification for the following "
"symbols in -sectorder file: %s for "
"section (%.16s,%.16s):",
ms->order_filename,
ms->s.segname, ms->s.sectname);
if(cur_obj->ar_hdr == NULL){
if(nowarnings == FALSE)
print("%s:%s\n", cur_obj->file_name,
load_order[j].name);
}
else{
if(nowarnings == FALSE)
print("%s:%.*s:%s\n", cur_obj->file_name,
(int)cur_obj->ar_name_size,
cur_obj->ar_name, load_order[j].name);
}
}
no_specifications++;
}
else{
if(cur_obj->cur_section_map->no_load_order == TRUE &&
any_order == TRUE){
if(cur_obj->ar_hdr == NULL){
error("specification for both %s:%s "
"and %s:%s in -sectorder file: "
"%s for section (%.16s,%.16s) "
"(not allowed)",
cur_obj->file_name,
".section_all",
cur_obj->file_name,
load_order[j].name,
ms->order_filename,
ms->s.segname, ms->s.sectname);
}
else{
error("specification for both "
"%s:%.*s:%s and %s:%.*s:%s "
"in -sectorder file: %s for "
"section (%.16s,%.16s) "
"(not allowed)",
cur_obj->file_name,
(int)cur_obj->ar_name_size,
cur_obj->ar_name,
".section_all",
cur_obj->file_name,
(int)cur_obj->ar_name_size,
cur_obj->ar_name,
load_order[j].name,
ms->order_filename,
ms->s.segname, ms->s.sectname);
}
}
}
}
if(cur_obj->cur_section_map->no_load_order == TRUE &&
(load_map == TRUE || dead_strip == TRUE)){
free(cur_obj->cur_section_map->load_orders);
load_order = allocate(sizeof(struct load_order));
n = 1;
cur_obj->cur_section_map->load_orders = load_order;
cur_obj->cur_section_map->nload_orders = n;
load_order->order = cur_obj->cur_section_map->order;
if(dead_strip == TRUE)
load_order->name = ".section_all";
else
load_order->name = NULL;
load_order->value = cur_obj->section_maps->s->addr;
load_order->input_offset = 0;
load_order->output_offset = output_offset;
load_order->input_size = cur_obj->cur_section_map->s->size;
}
#ifdef DEBUG
if(debug & (1 << 18))
print_load_order(
cur_obj->cur_section_map->load_orders,
cur_obj->cur_section_map->nload_orders,
ms, cur_obj, "all orders assigned");
#endif
}
}
if(sectorder_detail == FALSE && ms->order_filename != NULL){
if(unused_specifications != 0)
warning("%lu symbols specified in -sectorder file: %s "
"for section (%.16s,%.16s) not found in "
"loaded objects", unused_specifications,
ms->order_filename, ms->s.segname,
ms->s.sectname);
if(no_specifications != 0)
warning("%lu symbols have no specifications in "
"-sectorder file: %s for section (%.16s,"
"%.16s)",no_specifications, ms->order_filename,
ms->s.segname, ms->s.sectname);
if(ambiguous_specifications != 0)
warning("%lu symbols have ambiguous specifications in "
"-sectorder file: %s for section (%.16s,"
"%.16s)", ambiguous_specifications,
ms->order_filename, ms->s.segname,
ms->s.sectname);
}
if(errors)
return;
ms->s.size = output_offset;
object_symbols = NULL;
object_strings = NULL;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
if(cur_obj->cur_section_map == NULL)
continue;
if(cur_obj->cur_section_map->no_load_order == TRUE ||
(dead_strip == TRUE &&
(cur_obj->cur_section_map->s->flags &
S_ATTR_NO_DEAD_STRIP) == S_ATTR_NO_DEAD_STRIP &&
ms->order_filename == NULL) ){
fine_relocs = allocate(sizeof(struct fine_reloc));
memset(fine_relocs, '\0', sizeof(struct fine_reloc));
cur_obj->cur_section_map->fine_relocs = fine_relocs;
cur_obj->cur_section_map->nfine_relocs = 1;
fine_relocs[0].input_offset = 0;
fine_relocs[0].output_offset =
cur_obj->cur_section_map->offset;
if(dead_strip == TRUE){
load_orders = cur_obj->cur_section_map->load_orders;
load_orders[0].fine_reloc = fine_relocs + 0;
load_orders[0].order = cur_obj->cur_section_map->order;
}
continue;
}
n = cur_obj->cur_section_map->nload_orders;
load_orders = cur_obj->cur_section_map->load_orders;
start_section = cur_obj->cur_section_map->start_section;
fine_relocs = allocate(sizeof(struct fine_reloc) * n);
memset(fine_relocs, '\0', sizeof(struct fine_reloc) * n);
cur_obj->cur_section_map->fine_relocs = fine_relocs;
cur_obj->cur_section_map->nfine_relocs = n;
if(dead_strip == TRUE){
object_symbols = (struct nlist *)(cur_obj->obj_addr
+ cur_obj->symtab->symoff);
object_strings = (char *)(cur_obj->obj_addr +
cur_obj->symtab->stroff);
}
for(j = 0; j < n ; j++){
fine_relocs[j].input_offset =
load_orders[j].input_offset;
fine_relocs[j].output_offset =
load_orders[j].output_offset;
if(dead_strip == TRUE){
if((start_section == TRUE || j != 0) &&
object_symbols[load_orders[j].index].n_type & N_EXT){
merged_symbol = lookup_symbol(object_strings +
object_symbols[load_orders[j].index].
n_un.n_strx);
if(merged_symbol->name_len != 0 &&
merged_symbol->definition_object == cur_obj){
fine_relocs[j].merged_symbol = merged_symbol;
merged_symbol->fine_reloc = fine_relocs + j;
}
}
}
}
qsort(fine_relocs,
n,
sizeof(struct fine_reloc),
(int (*)(const void *, const void *))
qsort_fine_reloc_input_offset);
if(dead_strip == TRUE){
qsort(load_orders, n, sizeof(struct load_order),
(int (*)(const void *, const void *))
qsort_load_order_input_offset);
for(j = 0; j < n ; j++)
load_orders[j].fine_reloc = fine_relocs + j;
}
if(load_map == FALSE && dead_strip == FALSE){
free(cur_obj->cur_section_map->load_orders);
cur_obj->cur_section_map->load_orders = NULL;
cur_obj->cur_section_map->nload_orders = 0;
}
}
}
if(load_map == TRUE || dead_strip == TRUE)
create_order_load_maps(ms, order - 1);
}
#endif
__private_extern__
unsigned long
align_to_input_mod(
unsigned long output_offset,
unsigned long input_offset,
unsigned long align)
{
unsigned long output_mod, input_mod;
output_mod = output_offset % (1 << align);
input_mod = input_offset % (1 << align);
if(output_mod <= input_mod)
return(output_offset + (input_mod - output_mod));
else
return(rnd(output_offset, (1 << align)) + input_mod);
}
#ifndef RLD
__private_extern__
enum bool
is_literal_output_offset_live(
struct merged_section *ms,
unsigned long output_offset)
{
unsigned long i, j, k, n;
struct object_list *object_list, **q;
struct fine_reloc *fine_relocs;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
for(j = 0; j < cur_obj->nsection_maps; j++){
if(cur_obj->section_maps[j].output_section != ms)
continue;
fine_relocs = cur_obj->section_maps[j].fine_relocs;
n = cur_obj->section_maps[j].nfine_relocs;
for(k = 0; k < n ; k++){
if(fine_relocs[k].output_offset == output_offset &&
fine_relocs[k].live == TRUE)
return(TRUE);
}
break;
}
}
}
return(FALSE);
}
__private_extern__
void
parse_order_line(
char *line,
char **archive_name,
char **object_name,
char **symbol_name,
struct merged_section *ms,
unsigned long line_number)
{
unsigned long line_length;
char *left_bracket;
line = trim(line);
line_length = strlen(line);
if(line_length == 0){
*archive_name = NULL;
(*object_name) = "";
(*symbol_name) = "";
return;
}
if(line[line_length - 1] == ']'){
left_bracket = strrchr(line, '[');
if(left_bracket == NULL)
fatal("format error in -sectorder file: %s line %lu "
"for section (%.16s,%.16s) (no matching "
"'[' for ending ']' found in symbol name)",
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname);
*left_bracket = '\0';
*symbol_name = strrchr(line, ':');
*left_bracket = '[';
}
else if((left_bracket = strrchr(line, '[')) != NULL){
*left_bracket = '\0';
*symbol_name = strrchr(line, ':');
*left_bracket = '[';
}
else
*symbol_name = strrchr(line, ':');
if(*symbol_name == NULL){
*symbol_name = line;
line = "";
}
else{
**symbol_name = '\0';
(*symbol_name)++;
}
*object_name = strrchr(line, ':');
if(*object_name == NULL){
*object_name = line;
*archive_name = NULL;
}
else{
**object_name = '\0';
(*object_name)++;
*archive_name = line;
}
}
static
void
create_name_arrays(void)
{
unsigned long i;
long j;
struct object_list *object_list, **p;
struct archive_name *ar;
char *ar_name, *last_slash;
for(p = &objects; *p; p = &(object_list->next)){
object_list = *p;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
if(cur_obj->command_line)
continue;
if(cur_obj->ar_hdr != NULL){
ar = create_archive_name(cur_obj->file_name);
ar_name = allocate(cur_obj->ar_name_size + 1);
strncpy(ar_name, cur_obj->ar_name, cur_obj->ar_name_size);
ar_name[cur_obj->ar_name_size] = '\0';
create_object_name(&(ar->object_names),&(ar->nobject_names),
ar_name, strlen(ar_name),
cur_obj->file_name);
}
else{
last_slash = strrchr(cur_obj->file_name, '/');
if(last_slash == NULL)
j = 0;
else
j = last_slash - cur_obj->file_name + 1;
create_object_name(&object_names, &nobject_names,
cur_obj->file_name, j, NULL);
}
}
}
if(narchive_names != 0){
archive_names = reallocate(archive_names,
sizeof(struct archive_name) *
narchive_names);
qsort(archive_names,
narchive_names,
sizeof(struct archive_name),
(int (*)(const void *, const void *))qsort_archive_names);
for(i = 0; i < narchive_names; i++){
archive_names[i].object_names = reallocate(
archive_names[i].object_names,
sizeof(struct object_name) *
archive_names[i].nobject_names);
qsort(archive_names[i].object_names,
archive_names[i].nobject_names,
sizeof(struct object_name),
(int (*)(const void *, const void *))qsort_object_names);
}
}
if(nobject_names != nobjects)
object_names = reallocate(object_names,
sizeof(struct object_name) * nobject_names);
qsort(object_names,
nobject_names,
sizeof(struct object_name),
(int (*)(const void *, const void *))qsort_object_names);
}
static
struct archive_name *
create_archive_name(
char *archive_name)
{
unsigned long i;
struct archive_name *ar;
if(strchr(archive_name, ':') != NULL)
fatal("archive name: %s has a ':' (it can't when -sectorder "
"options are used)", archive_name);
ar = archive_names;
for(i = 0; i < narchive_names; i++){
if(strcmp(ar->archive_name, archive_name) == 0)
return(ar);
ar++;
}
if(archive_names == NULL)
archive_names = allocate(sizeof(struct archive_name) * nobjects);
ar = archive_names + narchive_names;
narchive_names++;
ar->archive_name = archive_name;
ar->object_names = NULL;
ar->nobject_names = 0;
return(ar);
}
static
void
create_object_name(
struct object_name **object_names,
unsigned long *nobject_names,
char *object_name,
unsigned long index_length,
char *archive_name)
{
unsigned long n, i;
struct object_name *o;
if(strchr(object_name, ':') != NULL){
if(archive_name != NULL)
fatal("archive member name: %s(%s) has a ':' in it (it can't "
"when -sectorder options are used)", archive_name,
object_name);
else
fatal("object file name: %s has a ':' in it (it can't when "
"-sectorder options are used)", object_name);
}
o = *object_names;
n = *nobject_names;
for(i = 0; i < n; i++){
if(strcmp(o->object_name, object_name) == 0){
if(archive_name != NULL){
#ifdef notdef
struct ar_hdr ar_hdr;
if(strlen(object_name) != sizeof(ar_hdr.ar_name) &&
strlen(object_name) != sizeof(ar_hdr.ar_name) - 1)
#endif
warning("duplicate archive member name: %s(%s) loaded ("
"could be ambiguous when -sectorder options "
"are used)", archive_name, object_name);
}
else
warning("duplicate object file name: %s loaded (could be "
"ambiguous when -sectorder options are used)",
object_name);
}
o++;
}
if(*object_names == NULL)
*object_names = allocate(sizeof(struct object_name) * nobjects);
o = *object_names + *nobject_names;
(*nobject_names)++;
o->object_name = object_name;
o->object_file = cur_obj;
o->index_length = index_length;
}
static
void
free_name_arrays(void)
{
unsigned long i, j;
if(archive_names != NULL){
for(i = 0; i < narchive_names; i++){
for(j = 0; j < archive_names[i].nobject_names; j++){
free(archive_names[i].object_names[j].object_name);
}
}
free(archive_names);
archive_names = NULL;
narchive_names = 0;
}
if(object_names != NULL){
free(object_names);
object_names = NULL;
nobject_names = 0;
}
}
static
void
create_load_symbol_hash_table(
unsigned long nsection_symbols,
struct merged_section *ms)
{
unsigned long i, j;
if(load_symbol_hashtable == NULL)
load_symbol_hashtable = allocate(sizeof(struct load_symbol *) *
LOAD_SYMBOL_HASHTABLE_SIZE);
memset(load_symbol_hashtable, '\0', sizeof(struct load_symbol *) *
LOAD_SYMBOL_HASHTABLE_SIZE);
if(nsection_symbols > load_symbols_size){
load_symbols_size = nsection_symbols;
load_symbols = reallocate(load_symbols, sizeof(struct load_symbol) *
load_symbols_size);
}
memset(load_symbols, '\0', sizeof(struct load_symbol) *
load_symbols_size);
load_symbols_used = 0;
for(i = 0; i < narchive_names; i++){
for(j = 0; j < archive_names[i].nobject_names; j++){
if(archive_names[i].object_names[j].object_file->
cur_section_map != NULL)
create_load_symbol_hash_table_for_object(
archive_names[i].archive_name,
archive_names[i].object_names[j].object_name,
archive_names[i].object_names[j].index_length,
archive_names[i].object_names[j].object_file->
cur_section_map->load_orders,
archive_names[i].object_names[j].object_file->
cur_section_map->nload_orders,
ms);
}
}
for(j = 0; j < nobject_names; j++){
if(object_names[j].object_file->cur_section_map != NULL)
create_load_symbol_hash_table_for_object(
NULL,
object_names[j].object_name,
object_names[j].index_length,
object_names[j].object_file->cur_section_map->load_orders,
object_names[j].object_file->cur_section_map->nload_orders,
ms);
}
}
static
void
free_load_symbol_hash_table(
void)
{
if(load_symbol_hashtable != NULL)
free(load_symbol_hashtable);
load_symbol_hashtable = NULL;
if(load_symbols != NULL)
free(load_symbols);
load_symbols_size = 0;
load_symbols_used = 0;
}
static
void
create_load_symbol_hash_table_for_object(
char *archive_name,
char *object_name,
unsigned long index_length,
struct load_order *load_orders,
unsigned long nload_orders,
struct merged_section *ms)
{
unsigned long i, hash_index;
struct load_symbol *load_symbol, *hash_load_symbol, *other_name;
for(i = 0; i < nload_orders; i++){
load_symbol = load_symbols + load_symbols_used;
load_symbols_used++;
load_symbol->symbol_name = load_orders[i].name;
load_symbol->object_name = object_name;
load_symbol->archive_name = archive_name;
load_symbol->index_length = index_length;
load_symbol->load_order = &(load_orders[i]);
hash_index = hash_string(load_orders[i].name, NULL) %
LOAD_SYMBOL_HASHTABLE_SIZE;
for(hash_load_symbol = load_symbol_hashtable[hash_index];
hash_load_symbol != NULL;
hash_load_symbol = hash_load_symbol->next){
if(strcmp(load_orders[i].name,
hash_load_symbol->symbol_name) == 0)
break;
}
if(hash_load_symbol == NULL){
load_symbol->other_names = NULL;
load_symbol->next = load_symbol_hashtable[hash_index];
load_symbol_hashtable[hash_index] = load_symbol;
}
else{
for(other_name = hash_load_symbol;
other_name != NULL && ms->order_filename != NULL;
other_name = other_name->other_names){
if(archive_name != NULL){
if(strcmp(other_name->object_name, object_name) == 0 &&
other_name->archive_name != NULL &&
strcmp(other_name->archive_name, archive_name) == 0){
warning("symbol appears more than once in the same "
"file (%s:%s:%s) which is ambiguous when "
"using a -sectorder option",
other_name->archive_name,
other_name->object_name,
other_name->symbol_name);
break;
}
}
else{
if(strcmp(other_name->object_name, object_name) == 0 &&
other_name->archive_name == NULL){
warning("symbol appears more than once in the same "
"file (%s:%s) which is ambiguous when "
"using a -sectorder option",
other_name->object_name,
other_name->symbol_name);
break;
}
}
}
load_symbol->other_names = hash_load_symbol->other_names;
hash_load_symbol->other_names = load_symbol;
load_symbol->next = NULL;
}
}
}
static
struct load_order *
lookup_load_order(
char *archive_name,
char *object_name,
char *symbol_name,
struct merged_section *ms,
unsigned long line_number)
{
struct archive_name *a;
struct object_name *o;
struct load_order *l;
unsigned long n;
unsigned long hash_index, number_of_matches;
struct load_symbol *hash_load_symbol, *other_name, *first_match;
char *last_slash, *base_name, *archive_base_name;
if(archive_name != NULL){
a = bsearch(archive_name, archive_names, narchive_names,
sizeof(struct archive_name),
(int (*)(const void *, const void *))
bsearch_archive_names);
if(a == NULL)
goto no_exact_match;
o = a->object_names;
n = a->nobject_names;
}
else{
o = object_names;
n = nobject_names;
}
o = bsearch(object_name, o, n, sizeof(struct object_name),
(int (*)(const void *, const void *))bsearch_object_names);
if(o == NULL)
goto no_exact_match;
if(o->object_file->cur_section_map == NULL)
goto no_exact_match;
l = o->object_file->cur_section_map->load_orders;
n = o->object_file->cur_section_map->nload_orders;
l = bsearch(symbol_name, l, n, sizeof(struct load_order),
(int (*)(const void *, const void *))
bsearch_load_order_names);
if(l == NULL)
goto no_exact_match;
return(l);
no_exact_match:
archive_name = trim(archive_name);
object_name = trim(object_name);
symbol_name = trim(symbol_name);
hash_index = hash_string(symbol_name, NULL) %
LOAD_SYMBOL_HASHTABLE_SIZE;
for(hash_load_symbol = load_symbol_hashtable[hash_index];
hash_load_symbol != NULL;
hash_load_symbol = hash_load_symbol->next){
if(strcmp(symbol_name, hash_load_symbol->symbol_name) == 0)
break;
}
if(hash_load_symbol == NULL)
return(NULL);
if(hash_load_symbol->other_names == NULL)
return(hash_load_symbol->load_order);
number_of_matches = 0;
first_match = NULL;
for(other_name = hash_load_symbol;
other_name != NULL;
other_name = other_name->other_names){
if(other_name->load_order->order == 0){
if(first_match == NULL)
first_match = other_name;
number_of_matches++;
}
}
if(number_of_matches == 1)
return(first_match->load_order);
if(number_of_matches == 0)
return(NULL);
last_slash = strrchr(object_name, '/');
if(last_slash == NULL)
base_name = object_name;
else
base_name = last_slash + 1;
number_of_matches = 0;
first_match = NULL;
for(other_name = hash_load_symbol;
other_name != NULL;
other_name = other_name->other_names){
if(other_name->load_order->order == 0){
if(other_name->archive_name != NULL){
if(strncmp(base_name, other_name->object_name,
other_name->index_length) == 0){
if(first_match == NULL)
first_match = other_name;
number_of_matches++;
}
}
else{
if(strcmp(base_name, other_name->object_name +
other_name->index_length) == 0){
if(first_match == NULL)
first_match = other_name;
number_of_matches++;
}
}
}
}
if(number_of_matches == 1)
return(first_match->load_order);
if(archive_name != NULL){
last_slash = strrchr(archive_name, '/');
if(last_slash == NULL)
base_name = archive_name;
else
base_name = last_slash + 1;
number_of_matches = 0;
first_match = NULL;
for(other_name = hash_load_symbol;
other_name != NULL;
other_name = other_name->other_names){
if(other_name->load_order->order == 0){
if(other_name->archive_name != NULL){
last_slash = strrchr(other_name->archive_name, '/');
if(last_slash == NULL)
archive_base_name = other_name->archive_name;
else
archive_base_name = last_slash + 1;
if(strcmp(base_name, archive_base_name) == 0){
if(first_match == NULL)
first_match = other_name;
number_of_matches++;
}
}
}
}
if(number_of_matches == 1)
return(first_match->load_order);
}
first_match = NULL;
for(other_name = hash_load_symbol;
other_name != NULL;
other_name = other_name->other_names){
if(other_name->load_order->order == 0){
first_match = other_name;
if(sectorder_detail){
if(archive_name != NULL){
if(other_name->archive_name != NULL)
warning("ambiguous specification of %s:%s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s) using %s:%s:%s",
archive_name, object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname,
other_name->archive_name,
other_name->object_name,
other_name->symbol_name);
else
warning("ambiguous specification of %s:%s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s) using %s:%s",
archive_name, object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname,
other_name->object_name,
other_name->symbol_name);
}
else{
if(other_name->archive_name != NULL)
warning("ambiguous specification of %s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s) using %s:%s:%s",
object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname,
other_name->archive_name,
other_name->object_name,
other_name->symbol_name);
else
warning("ambiguous specification of %s:%s in "
"-sectorder file: %s line %lu for "
"section (%.16s,%.16s) using %s:%s",
object_name, symbol_name,
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname,
other_name->object_name,
other_name->symbol_name);
}
}
break;
}
}
if(sectorder_detail == TRUE){
for(other_name = hash_load_symbol;
other_name != NULL;
other_name = other_name->other_names){
if(other_name->load_order->order == 0 &&
first_match != other_name){
if(archive_name != NULL){
if(other_name->archive_name != NULL)
warning("specification %s:%s:%s ambiguous with "
"%s:%s:%s", archive_name, object_name,
symbol_name, other_name->archive_name,
other_name->object_name,
other_name->symbol_name);
else
warning("specification %s:%s:%s ambiguous with "
"%s:%s", archive_name, object_name,
symbol_name, other_name->object_name,
other_name->symbol_name);
}
else{
if(other_name->archive_name != NULL)
warning("specification %s:%s ambiguous with "
"%s:%s:%s", object_name, symbol_name,
other_name->archive_name,
other_name->object_name,
other_name->symbol_name);
else
warning("specification %s:%s ambiguous with "
"%s:%s", object_name, symbol_name,
other_name->object_name,
other_name->symbol_name);
}
}
}
}
else{
ambiguous_specifications++;
}
return(first_match->load_order);
}
static
char *
trim(
char *name)
{
char *p;
if(name == NULL)
return(name);
while(*name != '\0' && *name == ' ')
name++;
if(*name == '\0')
return(name);
p = name;
while(*p != '\0')
p++;
p--;
while(p != name && *p == ' ')
*p-- = '\0';
return(name);
}
static
struct section_map *
lookup_section_map(
char *archive_name,
char *object_name)
{
struct archive_name *a;
struct object_name *o;
unsigned long n;
if(archive_name != NULL){
a = bsearch(archive_name, archive_names, narchive_names,
sizeof(struct archive_name),
(int (*)(const void *, const void *))
bsearch_archive_names);
if(a == NULL)
return(NULL);
o = a->object_names;
n = a->nobject_names;
}
else{
o = object_names;
n = nobject_names;
}
o = bsearch(object_name, o, n, sizeof(struct object_name),
(int (*)(const void *, const void *))bsearch_object_names);
if(o == NULL)
return(NULL);
return(o->object_file->cur_section_map);
}
#endif
__private_extern__
int
qsort_load_order_values(
const struct load_order *load_order1,
const struct load_order *load_order2)
{
if(load_order1->value == load_order2->value)
return(strcmp(load_order1->name, load_order2->name));
else
return(load_order1->value - load_order2->value);
}
#ifndef RLD
static
int
qsort_load_order_names(
const struct load_order *load_order1,
const struct load_order *load_order2)
{
return(strcmp(load_order1->name, load_order2->name));
}
static
int
bsearch_load_order_names(
char *symbol_name,
const struct load_order *load_order)
{
return(strcmp(symbol_name, load_order->name));
}
static
int
qsort_load_order_input_offset(
const struct load_order *load_order1,
const struct load_order *load_order2)
{
if(load_order1->input_offset == load_order2->input_offset)
return(strcmp(load_order1->name, load_order2->name));
else
return(load_order1->input_offset - load_order2->input_offset);
}
static
int
qsort_archive_names(
const struct archive_name *archive_name1,
const struct archive_name *archive_name2)
{
return(strcmp(archive_name1->archive_name,
archive_name2->archive_name));
}
static
int
bsearch_archive_names(
const char *name,
const struct archive_name *archive_name)
{
return(strcmp(name, archive_name->archive_name));
}
static
int
qsort_object_names(
const struct object_name *object_name1,
const struct object_name *object_name2)
{
return(strcmp(object_name1->object_name,
object_name2->object_name));
}
static
int
bsearch_object_names(
const char *name,
const struct object_name *object_name)
{
return(strcmp(name, object_name->object_name));
}
static
int
qsort_fine_reloc_input_offset(
const struct fine_reloc *fine_reloc1,
const struct fine_reloc *fine_reloc2)
{
return(fine_reloc1->input_offset - fine_reloc2->input_offset);
}
static
int
qsort_order_load_map_orders(
const struct order_load_map *order_load_map1,
const struct order_load_map *order_load_map2)
{
return(order_load_map1->order - order_load_map2->order);
}
static
void
create_order_load_maps(
struct merged_section *ms,
unsigned long norder_load_maps)
{
unsigned long i, j, k, l, m, n;
struct order_load_map *order_load_maps;
struct load_order *load_orders;
order_load_maps = allocate(sizeof(struct order_load_map) *
norder_load_maps);
ms->order_load_maps = order_load_maps;
ms->norder_load_maps = norder_load_maps;
l = 0;
for(i = 0; i < narchive_names; i++){
for(j = 0; j < archive_names[i].nobject_names; j++){
cur_obj = archive_names[i].object_names[j].object_file;
for(m = 0; m < cur_obj->nsection_maps; m++){
if(cur_obj->section_maps[m].output_section != ms)
continue;
n = cur_obj->section_maps[m].nload_orders;
load_orders = cur_obj->section_maps[m].load_orders;
for(k = 0; k < n ; k++){
order_load_maps[l].archive_name =
archive_names[i].archive_name;
order_load_maps[l].object_name =
archive_names[i].object_names[j].object_name;
order_load_maps[l].symbol_name = load_orders[k].name;
order_load_maps[l].value = load_orders[k].value;
order_load_maps[l].section_map =
&(cur_obj->section_maps[m]);
order_load_maps[l].size = load_orders[k].input_size;
order_load_maps[l].order = load_orders[k].order;
order_load_maps[l].load_order = load_orders + k;
l++;
}
break;
}
}
}
for(j = 0; j < nobject_names; j++){
cur_obj = object_names[j].object_file;
for(m = 0; m < cur_obj->nsection_maps; m++){
if(cur_obj->section_maps[m].output_section != ms)
continue;
n = cur_obj->section_maps[m].nload_orders;
load_orders = cur_obj->section_maps[m].load_orders;
for(k = 0; k < n ; k++){
order_load_maps[l].archive_name = NULL;
order_load_maps[l].object_name =
object_names[j].object_name;
order_load_maps[l].symbol_name = load_orders[k].name;
order_load_maps[l].value = load_orders[k].value;
order_load_maps[l].section_map =
&(cur_obj->section_maps[m]);
order_load_maps[l].size = load_orders[k].input_size;
order_load_maps[l].order = load_orders[k].order;
order_load_maps[l].load_order = load_orders + k;
l++;
}
}
}
#ifdef DEBUG
if(debug & (1 << 19)){
for(i = 0; i < norder_load_maps; i++){
if(order_load_maps[i].archive_name != NULL)
print("%s:", order_load_maps[i].archive_name);
if(order_load_maps[i].symbol_name != NULL)
print("%s:%s\n", order_load_maps[i].object_name,
order_load_maps[i].symbol_name);
else
print("%s\n", order_load_maps[i].object_name);
}
}
#endif
qsort(order_load_maps,
norder_load_maps,
sizeof(struct order_load_map),
(int (*)(const void *, const void *))qsort_order_load_map_orders);
}
#ifdef DEBUG
static
void
print_symbol_name_from_order_load_maps(
struct section_map *map,
unsigned long value)
{
unsigned int i, n;
struct order_load_map *order_load_maps;
order_load_maps = map->output_section->order_load_maps;
n = map->output_section->norder_load_maps;
for(i = 0; i < n; i++){
if(order_load_maps[i].value == value){
print(":%s", order_load_maps[i].symbol_name);
return;
}
}
}
#endif
__private_extern__
void
resize_live_sections(
void)
{
struct merged_segment **p, *msg;
struct merged_section **content, **zerofill, *ms;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->s.flags & SECTION_TYPE) == S_REGULAR &&
ms->contents_filename == NULL)
resize_live_section(ms);
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
resize_live_section(ms);
zerofill = &(ms->next);
}
p = &(msg->next);
}
}
static
void
resize_live_section(
struct merged_section *ms)
{
unsigned long n, i, output_offset;
struct order_load_map *order_load_maps;
struct load_order *load_order;
struct fine_reloc *fine_reloc;
output_offset = 0;
n = ms->norder_load_maps;
order_load_maps = ms->order_load_maps;
for(i = 0; i < n; i++){
if(order_load_maps[i].load_order->fine_reloc->live == FALSE){
if(ms->order_filename != NULL &&
sectorder_detail == TRUE &&
order_load_maps[i].load_order->line_number != 0)
warning("specification of symbol: %s in -sectorder file: "
"%s line %lu for section (%.16s,%.16s) not used "
"(dead stripped)",
order_load_maps[i].load_order->name,
ms->order_filename,
order_load_maps[i].load_order->line_number,
ms->s.segname, ms->s.sectname);
continue;
}
load_order = order_load_maps[i].load_order;
fine_reloc = load_order->fine_reloc;
output_offset = align_to_input_mod(output_offset,
load_order->input_offset,
ms->s.align);
load_order->output_offset = output_offset;
fine_reloc->output_offset = output_offset;
output_offset += load_order->input_size;
}
ms->s.size = output_offset;
}
__private_extern__
void
relayout_relocs(
void)
{
unsigned long i, j, section_type, nlocrel, nextrel;
struct object_list *object_list, **p;
struct section_map *map;
struct relocation_info *relocs;
struct merged_segment **q, *msg;
struct merged_section **content, *ms;
nlocrel = 0;
nextrel = 0;
for(p = &objects; *p; p = &(object_list->next)){
object_list = *p;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(cur_obj == base_obj)
continue;
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
cur_obj->ilocrel = nlocrel;
cur_obj->iextrel = nextrel;
for(j = 0; j < cur_obj->nsection_maps; j++){
if(cur_obj->section_maps[j].s->flags & S_ATTR_DEBUG)
continue;
section_type = cur_obj->section_maps[j].s->flags &
SECTION_TYPE;
if(section_type == S_REGULAR ||
section_type == S_MOD_INIT_FUNC_POINTERS ||
section_type == S_MOD_TERM_FUNC_POINTERS){
map = cur_obj->section_maps + j;
relocs = (struct relocation_info *)
(cur_obj->obj_addr + map->s->reloff);
count_relocs(map, relocs, &nlocrel, &nextrel);
}
}
for(j = 0; j < cur_obj->nsection_maps; j++){
section_type = cur_obj->section_maps[j].s->flags &
SECTION_TYPE;
if(section_type == S_COALESCED){
map = cur_obj->section_maps + j;
if(map->nextrel != 0){
map->iextrel = nextrel;
nextrel += map->nextrel;
cur_obj->nextrel += map->nextrel;
}
if(map->nlocrel != 0){
map->ilocrel = nlocrel;
nlocrel += map->nlocrel;
cur_obj->nlocrel += map->nlocrel;
}
}
}
}
}
q = &merged_segments;
while(*q){
msg = *q;
content = &(msg->content_sections);
while(*content){
ms = *content;
section_type = ms->s.flags & SECTION_TYPE;
if(section_type == S_LITERAL_POINTERS ||
section_type == S_SYMBOL_STUBS ||
section_type == S_LAZY_SYMBOL_POINTERS){
if(ms->nlocrel != 0){
ms->ilocrel = nlocrel;
nlocrel += ms->nlocrel;
ms->s.flags |= S_ATTR_LOC_RELOC;
}
if(ms->nextrel != 0){
if(filetype == MH_DYLIB && multi_module_dylib == TRUE)
fatal("internal error: relayout_relocs() "
"called with external relocation entries for "
"merged section (%.16s,%.16s) for multi module "
"MH_DYLIB output", ms->s.segname, ms->s.sectname);
ms->iextrel = nextrel;
nextrel += ms->nextrel;
ms->s.flags |= S_ATTR_EXT_RELOC;
}
}
content = &(ms->next);
}
q = &(msg->next);
}
output_dysymtab_info.dysymtab_command.nlocrel = nlocrel;
output_dysymtab_info.dysymtab_command.nextrel = nextrel;
}
static
void
count_relocs(
struct section_map *map,
struct relocation_info *relocs,
unsigned long *nlocrel,
unsigned long *nextrel)
{
unsigned long i, j, pair, prev_nlocrel, prev_nextrel;
struct relocation_info reloc, pair_reloc;
struct scattered_relocation_info *sreloc;
unsigned long r_address, r_type, r_extern, r_symbolnum, r_pcrel, r_value,
r_length;
struct undefined_map *undefined_map;
struct merged_symbol *merged_symbol;
struct nlist *nlists;
char *strings;
enum bool defined, pic;
struct section_map *local_map;
struct section_map fake_map;
struct section fake_s;
char fake_contents[4];
struct relocation_info fake_relocs[2];
merged_symbol = NULL;
defined = FALSE;
prev_nlocrel = cur_obj->nlocrel;
prev_nextrel = cur_obj->nextrel;
for(i = 0; i < map->s->nreloc; i++){
reloc = relocs[i];
if(cur_obj->swapped && 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_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_type = sreloc->r_type;
r_length = sreloc->r_length;
r_extern = 0;
r_value = sreloc->r_value;
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){
return;
}
}
}
else{
r_address = reloc.r_address;
r_pcrel = reloc.r_pcrel;
r_type = reloc.r_type;
r_length = reloc.r_length;
r_extern = reloc.r_extern;
r_symbolnum = reloc.r_symbolnum;
}
if(r_extern){
if(r_symbolnum >= cur_obj->symtab->nsyms)
return;
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{
nlists = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
strings = (char *)(cur_obj->obj_addr +
cur_obj->symtab->stroff);
if((nlists[r_symbolnum].n_type & N_EXT) != N_EXT)
return;
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 count_relocs() failed to "
"lookup coalesced symbol %s", strings +
nlists[r_symbolnum].n_un.n_strx);
}
}
else
return;
}
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR &&
merged_symbol->defined_in_dylib == FALSE)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
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{
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 &&
has_dynamic_linker_command == FALSE){
defined = FALSE;
}
else{
defined = TRUE;
}
}
}
if(reloc_has_pair(arch_flag.cputype, r_type))
pair = 1;
else
pair = 0;
if(r_extern == 0){
if(r_symbolnum > cur_obj->nsection_maps)
return;
local_map = &(cur_obj->section_maps[r_symbolnum - 1]);
if(r_symbolnum != NO_SECT &&
(local_map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS &&
local_map->absolute_indirect_defineds == TRUE &&
r_pcrel == 1){
if(r_address >= map->s->size)
return;
if(pair && i == map->s->nreloc - 1)
return;
memcpy(fake_contents,
cur_obj->obj_addr + map->s->offset + r_address,
1 << r_length);
fake_relocs[0] = reloc;
if((reloc.r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)
(&fake_relocs[0]);
sreloc->r_address = 0;
}
else
fake_relocs[0].r_address = 0;
if(pair){
pair_reloc = relocs[i+1];
if(cur_obj->swapped &&
map->input_relocs_already_swapped == FALSE)
swap_relocation_info(&pair_reloc, 1, host_byte_sex);
fake_relocs[1] = pair_reloc;
}
fake_s = *(map->s);
fake_s.nreloc = 1 + pair;
fake_s.size = 1 << r_length;
fake_s.addr += r_address;
fake_map = *map;
fake_map.s = &fake_s;
fake_map.nfine_relocs = 0;
fake_map.fine_relocs = NULL;
if(arch_flag.cputype == CPU_TYPE_MC680x0)
generic_reloc(fake_contents, fake_relocs, &fake_map,
FALSE, NULL, 0);
else if(arch_flag.cputype == CPU_TYPE_I386)
generic_reloc(fake_contents, fake_relocs, &fake_map,
TRUE, NULL, 0);
else if(arch_flag.cputype == CPU_TYPE_POWERPC ||
arch_flag.cputype == CPU_TYPE_VEO)
ppc_reloc(fake_contents, fake_relocs, &fake_map,
NULL, 0);
else if(arch_flag.cputype == CPU_TYPE_MC88000)
m88k_reloc(fake_contents, fake_relocs, &fake_map);
else if(arch_flag.cputype == CPU_TYPE_HPPA)
hppa_reloc(fake_contents, fake_relocs, &fake_map);
else if(arch_flag.cputype == CPU_TYPE_SPARC)
sparc_reloc(fake_contents, fake_relocs, &fake_map);
#ifndef RLD
else if(arch_flag.cputype == CPU_TYPE_I860)
i860_reloc(fake_contents, fake_relocs, map);
#endif
else if(arch_flag.cputype == CPU_TYPE_ARM)
arm_reloc(fake_contents, fake_relocs, &fake_map,
NULL, 0);
r_symbolnum = fake_relocs[0].r_symbolnum;
}
else if(r_symbolnum != NO_SECT &&
(local_map->s->flags & SECTION_TYPE) == S_COALESCED){
;
}
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((arch_flag.cputype == CPU_TYPE_POWERPC &&
r_type == PPC_RELOC_JBSR) ||
(arch_flag.cputype == CPU_TYPE_HPPA &&
r_type == HPPA_RELOC_JBSR)){
i += pair;
continue;
}
if(dead_strip == TRUE){
if(fine_reloc_offset_in_output(map, r_address) == FALSE){
i += pair;
continue;
}
}
if(output_for_dyld == FALSE){
if(save_reloc == TRUE){
if(r_extern == TRUE && defined == FALSE){
(*nextrel) += 1 + pair;
cur_obj->nextrel += 1 + pair;
}
else{
(*nlocrel) += 1 + pair;
cur_obj->nlocrel += 1 + pair;
}
}
i += pair;
continue;
}
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
if(r_extern && (merged_symbol->nlist.n_type & N_PEXT) == 0){
(*nextrel) += 1 + pair;
cur_obj->nextrel += 1 + pair;
}
else if(pic == FALSE){
(*nlocrel) += 1 + pair;
cur_obj->nlocrel += 1 + pair;
}
}
else if(has_dynamic_linker_command){
if(r_extern){
if(defined == FALSE){
(*nextrel) += 1 + pair;
cur_obj->nextrel += 1 + pair;
}
}
}
else{
if(r_extern && (merged_symbol->nlist.n_type & N_PEXT) == 0){
if(defined == FALSE){
(*nextrel) += 1 + pair;
cur_obj->nextrel += 1 + pair;
}
else if(pic == FALSE){
(*nlocrel) += 1 + pair;
cur_obj->nlocrel += 1 + pair;
}
}
else if(pic == FALSE){
(*nlocrel) += 1 + pair;
cur_obj->nlocrel += 1 + pair;
}
}
i += pair;
}
map->nextrel = cur_obj->nextrel - prev_nextrel;
map->nlocrel = cur_obj->nlocrel - prev_nlocrel;
if(prev_nextrel != cur_obj->nextrel)
map->output_section->s.flags |= S_ATTR_EXT_RELOC;
if(prev_nlocrel != cur_obj->nlocrel)
map->output_section->s.flags |= S_ATTR_LOC_RELOC;
}
#endif
__private_extern__
void
output_literal_sections(void)
{
struct merged_segment **p, *msg;
struct merged_section **content, *ms;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->s.flags & SECTION_TYPE) == S_CSTRING_LITERALS ||
(ms->s.flags & SECTION_TYPE) == S_4BYTE_LITERALS ||
(ms->s.flags & SECTION_TYPE) == S_8BYTE_LITERALS ||
(ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS)
(*ms->literal_output)(ms->literal_data, ms);
content = &(ms->next);
}
p = &(msg->next);
}
}
#ifndef RLD
__private_extern__
void
output_sections_from_files(void)
{
struct merged_segment **p, *msg;
struct merged_section **content, *ms;
#ifdef DEBUG
kern_return_t r;
#endif
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->contents_filename != NULL){
memcpy(output_addr + ms->s.offset,
ms->file_addr, ms->file_size);
output_flush(ms->s.offset, ms->s.size);
#ifdef DEBUG
if((r = vm_deallocate(mach_task_self(), (vm_address_t)
ms->file_addr, ms->file_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for file: "
"%s used to create section (%.16s,%.16s)",
ms->contents_filename, ms->s.segname,
ms->s.sectname);
ms->file_addr = NULL;
#endif
}
content = &(ms->next);
}
p = &(msg->next);
}
}
#endif
__private_extern__
void
output_section(
struct section_map *map)
{
char *contents;
struct relocation_info *relocs;
#ifndef RLD
struct relocation_info *output_relocs, *output_locrel, *output_extrel;
unsigned long nlocrel, nextrel;
unsigned long nreloc;
#endif
#ifdef DEBUG
output_relocs = NULL;
#endif
if(map->s->size == 0 && map->s->nreloc == 0)
return;
if(map->nfine_relocs != 0)
contents = allocate(map->s->size);
else{
if(arch_flag.cputype == CPU_TYPE_I386 &&
(map->s->flags & S_ATTR_PURE_INSTRUCTIONS) != 0){
contents = output_addr + map->output_section->s.offset +
map->flush_offset;
memset(contents, 0x90, map->offset - map->flush_offset);
}
contents = output_addr + map->output_section->s.offset +map->offset;
}
memcpy(contents, cur_obj->obj_addr + map->s->offset, map->s->size);
if(map->s->nreloc == 0){
#ifndef RLD
if(map->nfine_relocs != 0){
scatter_copy(map, contents);
free(contents);
}
else
output_flush(map->output_section->s.offset + map->flush_offset,
map->s->size + (map->offset - map->flush_offset));
#endif
return;
}
else
map->output_section->relocated = TRUE;
if(output_for_dyld){
relocs = allocate(map->s->nreloc * sizeof(struct relocation_info));
memcpy(relocs,
cur_obj->obj_addr + map->s->reloff,
map->s->nreloc * sizeof(struct relocation_info));
}
else if(save_reloc){
if((map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
(map->s->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_COALESCED){
relocs = allocate(map->s->nreloc *
sizeof(struct relocation_info));
memcpy(relocs,
cur_obj->obj_addr + map->s->reloff,
map->s->nreloc * sizeof(struct relocation_info));
}
else{
relocs = (struct relocation_info *)(output_addr +
map->output_section->s.reloff +
map->output_section->output_nrelocs *
sizeof(struct relocation_info));
memcpy(relocs,
cur_obj->obj_addr + map->s->reloff,
map->s->nreloc * sizeof(struct relocation_info));
}
}
else{
relocs = (struct relocation_info *)(cur_obj->obj_addr +
map->s->reloff);
}
if(cur_obj->swapped && map->input_relocs_already_swapped == FALSE){
swap_relocation_info(relocs, map->s->nreloc, host_byte_sex);
map->input_relocs_already_swapped = TRUE;
}
if(arch_flag.cputype == CPU_TYPE_MC680x0)
generic_reloc(contents, relocs, map, FALSE, NULL, 0);
else if(arch_flag.cputype == CPU_TYPE_I386)
generic_reloc(contents, relocs, map, TRUE, NULL, 0);
else if(arch_flag.cputype == CPU_TYPE_POWERPC ||
arch_flag.cputype == CPU_TYPE_VEO)
ppc_reloc(contents, relocs, map, NULL, 0);
else if(arch_flag.cputype == CPU_TYPE_MC88000)
m88k_reloc(contents, relocs, map);
else if(arch_flag.cputype == CPU_TYPE_HPPA)
hppa_reloc(contents, relocs, map);
else if(arch_flag.cputype == CPU_TYPE_SPARC)
sparc_reloc(contents, relocs, map);
#ifndef RLD
else if(arch_flag.cputype == CPU_TYPE_I860)
i860_reloc(contents, relocs, map);
#endif
else if(arch_flag.cputype == CPU_TYPE_ARM)
arm_reloc(contents, relocs, map, NULL, 0);
else
fatal("internal error: output_section() called with unknown "
"cputype (%d) set", arch_flag.cputype);
if(errors)
return;
if(map->nfine_relocs != 0){
scatter_copy(map, contents);
free(contents);
}
#ifndef RLD
else
output_flush(map->output_section->s.offset + map->flush_offset,
map->s->size + (map->offset - map->flush_offset));
if(output_for_dyld){
if((map->s->flags & SECTION_TYPE) == S_REGULAR ||
(map->s->flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS){
output_locrel = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.locreloff +
cur_obj->ilocrel * sizeof(struct relocation_info));
output_extrel = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.extreloff +
cur_obj->iextrel * sizeof(struct relocation_info));
}
else if((map->s->flags & SECTION_TYPE) == S_COALESCED){
output_locrel = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.locreloff +
map->ilocrel * sizeof(struct relocation_info));
output_extrel = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.extreloff +
map->iextrel * sizeof(struct relocation_info));
}
else{
output_locrel = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.locreloff +
map->output_section->ilocrel *
sizeof(struct relocation_info));
output_extrel = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.extreloff +
map->output_section->iextrel *
sizeof(struct relocation_info));
}
reloc_output_for_dyld(map, relocs, output_locrel, output_extrel,
&nlocrel, &nextrel);
if((map->s->flags & SECTION_TYPE) == S_REGULAR ||
(map->s->flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_COALESCED){
if(nextrel != map->nextrel)
fatal("internal error: output_section() count of external "
"relocation entries does not match\n");
if(nlocrel != map->nlocrel)
fatal("internal error: output_section() count of local "
"relocation entries does not match\n");
}
if(host_byte_sex != target_byte_sex){
swap_relocation_info(output_locrel, nlocrel, target_byte_sex);
swap_relocation_info(output_extrel, nextrel, target_byte_sex);
}
if((map->s->flags & SECTION_TYPE) == S_REGULAR ||
(map->s->flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS){
output_flush(output_dysymtab_info.dysymtab_command.locreloff +
cur_obj->ilocrel * sizeof(struct relocation_info),
nlocrel * sizeof(struct relocation_info));
cur_obj->ilocrel += nlocrel;
output_flush(output_dysymtab_info.dysymtab_command.extreloff +
cur_obj->iextrel * sizeof(struct relocation_info),
nextrel * sizeof(struct relocation_info));
cur_obj->iextrel += nextrel;
}
else if((map->s->flags & SECTION_TYPE) == S_COALESCED){
output_flush(output_dysymtab_info.dysymtab_command.locreloff +
map->ilocrel * sizeof(struct relocation_info),
nlocrel * sizeof(struct relocation_info));
output_flush(output_dysymtab_info.dysymtab_command.extreloff +
map->iextrel * sizeof(struct relocation_info),
nextrel * sizeof(struct relocation_info));
}
else{
output_flush(output_dysymtab_info.dysymtab_command.locreloff +
map->output_section->ilocrel *
sizeof(struct relocation_info),
nlocrel * sizeof(struct relocation_info));
map->output_section->ilocrel += nlocrel;
output_flush(output_dysymtab_info.dysymtab_command.extreloff +
map->output_section->iextrel *
sizeof(struct relocation_info),
nextrel * sizeof(struct relocation_info));
map->output_section->iextrel += nextrel;
}
free(relocs);
}
else if(save_reloc){
if((map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
(map->s->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_COALESCED){
output_relocs = (struct relocation_info *)(output_addr +
map->output_section->s.reloff +
map->output_section->output_nrelocs *
sizeof(struct relocation_info));
nreloc = scatter_copy_relocs(map, relocs, output_relocs);
free(relocs);
}
else{
nreloc = map->s->nreloc;
output_relocs = relocs;
}
if(host_byte_sex != target_byte_sex)
swap_relocation_info(output_relocs, nreloc, target_byte_sex);
output_flush(map->output_section->s.reloff +
map->output_section->output_nrelocs *
sizeof(struct relocation_info),
nreloc * sizeof(struct relocation_info));
map->output_section->output_nrelocs += nreloc;
}
#endif
}
#ifndef RLD
static
enum bool
is_pass2_merged_symbol_coalesced(
struct merged_symbol *merged_symbol)
{
unsigned long i;
if(merged_symbol == NULL)
return(FALSE);
if((merged_symbol->nlist.n_type & N_TYPE) != N_SECT)
return(FALSE);
for(i = 0; i < merged_symbol->definition_object->nsection_maps; i++){
if(merged_symbol->nlist.n_sect == merged_symbol->definition_object->
section_maps[i].output_section->output_sectnum)
if((merged_symbol->definition_object->section_maps[
i].output_section->s.flags & SECTION_TYPE) == S_COALESCED)
return(TRUE);
}
return(FALSE);
}
#endif
__private_extern__
unsigned long
pass2_nsect_merged_symbol_section_type(
struct merged_symbol *merged_symbol)
{
unsigned long i;
if(merged_symbol == NULL ||
(merged_symbol->nlist.n_type & N_TYPE) != N_SECT)
fatal("internal error, s_pass2_merged_symbol_coalesced() passed "
"a non-N_SECT symbol");
for(i = 0; i < merged_symbol->definition_object->nsection_maps; i++){
if(merged_symbol->nlist.n_sect == merged_symbol->definition_object->
section_maps[i].output_section->output_sectnum)
return(merged_symbol->definition_object->section_maps[i].
output_section->s.flags & SECTION_TYPE);
}
fatal("internal error, s_pass2_merged_symbol_coalesced() failed\n");
return(0);
}
static
void
scatter_copy(
struct section_map *map,
char *contents)
{
unsigned long i;
#ifndef RLD
unsigned long j;
struct nlist *nlists;
unsigned long *indirect_symtab, index, value;
struct undefined_map *undefined_map;
struct merged_symbol *merged_symbol;
char *strings;
struct section_map *section_map;
long delta;
char *jmpEntry;
if((map->s->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
(prebinding == TRUE &&
(map->s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS)){
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;
for(i = 0; i < map->nfine_relocs - 1; i++){
if(map->fine_relocs[i].use_contents == TRUE &&
(dead_strip == FALSE || map->fine_relocs[i].live == TRUE)){
index = indirect_symtab[map->s->reserved1 +
(map->fine_relocs[i].input_offset / 4)];
if(map->fine_relocs[i].indirect_defined == TRUE ||
is_pass2_merged_symbol_coalesced(
map->fine_relocs[i].merged_symbol) == TRUE ||
(prebinding == TRUE &&
(index != INDIRECT_SYMBOL_LOCAL &&
index != INDIRECT_SYMBOL_ABS))){
if(is_pass2_merged_symbol_coalesced(
map->fine_relocs[i].merged_symbol) == TRUE){
value = map->fine_relocs[i].merged_symbol->
nlist.n_value;
if((map->fine_relocs[i].merged_symbol->
nlist.n_desc & N_ARM_THUMB_DEF))
value |= 1;
}
else if(map->fine_relocs[i].local_symbol == FALSE){
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 = lookup_symbol(strings +
nlists[index].n_un.n_strx);
if(merged_symbol->name_len == 0)
fatal("interal error, scatter_copy() failed"
" in looking up external symbol");
}
else
merged_symbol = undefined_map->merged_symbol;
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
value = merged_symbol->nlist.n_value;
if((merged_symbol->nlist.n_desc & N_ARM_THUMB_DEF))
value |= 1;
}
else{
if(nlists[index].n_sect == NO_SECT)
value = nlists[index].n_value;
else{
section_map = &(cur_obj->section_maps[
nlists[index].n_sect -1]);
if(section_map->nfine_relocs == 0)
value = nlists[index].n_value -
section_map->s->addr +
section_map->output_section->s.addr +
section_map->offset;
else
value =
section_map->output_section->s.addr +
fine_reloc_output_offset(section_map,
nlists[index].n_value -
section_map->s->addr);
}
if((nlists[index].n_desc & N_ARM_THUMB_DEF))
value |= 1;
}
if(host_byte_sex != target_byte_sex)
value = SWAP_LONG(value);
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
&value, sizeof(unsigned long));
}
else{
if(index == INDIRECT_SYMBOL_LOCAL){
memcpy(&value, contents +
map->fine_relocs[i].input_offset, 4);
if(cur_obj->swapped)
value = SWAP_LONG(value);
for(j = 0; j < cur_obj->nsection_maps; j++){
if(value >= cur_obj->section_maps[j].s->addr &&
value < cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size){
break;
}
}
if(j >= cur_obj->nsection_maps){
error_with_cur_obj("value of symbol pointer "
"(0x%x) in section (%.16s,%.16s) at index "
"%ld out of range for an indirect symbol "
"table value of INDIRECT_SYMBOL_LOCAL",
(unsigned int)value,
map->output_section->s.segname,
map->output_section->s.sectname, i);
return;
}
section_map = &(cur_obj->section_maps[j]);
if(section_map->nfine_relocs == 0)
value = value -
section_map->s->addr +
section_map->output_section->s.addr +
section_map->offset;
else
value =
section_map->output_section->s.addr +
fine_reloc_output_offset(section_map,
value - section_map->s->addr);
if(host_byte_sex != target_byte_sex)
value = SWAP_LONG(value);
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
&value, sizeof(unsigned long));
}
else{
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
contents + map->fine_relocs[i].input_offset,
map->fine_relocs[i+1].input_offset -
map->fine_relocs[i].input_offset);
}
}
}
}
if(map->fine_relocs[i].use_contents == TRUE &&
(dead_strip == FALSE || map->fine_relocs[i].live == TRUE)){
index = indirect_symtab[map->s->reserved1 +
(map->fine_relocs[i].input_offset / 4)];
if(map->fine_relocs[i].indirect_defined == TRUE ||
is_pass2_merged_symbol_coalesced(
map->fine_relocs[i].merged_symbol) == TRUE ||
(prebinding == TRUE &&
(index != INDIRECT_SYMBOL_LOCAL &&
index != INDIRECT_SYMBOL_ABS))){
if(is_pass2_merged_symbol_coalesced(
map->fine_relocs[i].merged_symbol) == TRUE){
value = map->fine_relocs[i].merged_symbol->
nlist.n_value;
if((map->fine_relocs[i].merged_symbol->
nlist.n_desc & N_ARM_THUMB_DEF))
value |= 1;
}
else if(map->fine_relocs[i].local_symbol == FALSE){
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 = lookup_symbol(strings +
nlists[index].n_un.n_strx);
if(merged_symbol->name_len == 0)
fatal("interal error, scatter_copy() failed"
" in looking up external symbol");
}
else
merged_symbol = undefined_map->merged_symbol;
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
value = merged_symbol->nlist.n_value;
if((merged_symbol->nlist.n_desc & N_ARM_THUMB_DEF))
value |= 1;
}
else{
if(nlists[index].n_sect == NO_SECT)
value = nlists[index].n_value;
else{
section_map = &(cur_obj->section_maps[
nlists[index].n_sect -1]);
if(section_map->nfine_relocs == 0)
value = nlists[index].n_value -
section_map->s->addr +
section_map->output_section->s.addr +
section_map->offset;
else
value =
section_map->output_section->s.addr +
fine_reloc_output_offset(section_map,
nlists[index].n_value -
section_map->s->addr);
}
if((nlists[index].n_desc & N_ARM_THUMB_DEF))
value |= 1;
}
if(host_byte_sex != target_byte_sex)
value = SWAP_LONG(value);
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
&value, sizeof(unsigned long));
}
else{
if(index == INDIRECT_SYMBOL_LOCAL){
memcpy(&value, contents +
map->fine_relocs[i].input_offset, 4);
if(cur_obj->swapped)
value = SWAP_LONG(value);
for(j = 0; j < cur_obj->nsection_maps; j++){
if(value >= cur_obj->section_maps[j].s->addr &&
value < cur_obj->section_maps[j].s->addr +
cur_obj->section_maps[j].s->size){
break;
}
}
if(j >= cur_obj->nsection_maps){
error_with_cur_obj("value of symbol pointer (0x%x) "
"in section (%.16s,%.16s) at index %ld out of "
"range for an indirect symbol table value of "
"INDIRECT_SYMBOL_LOCAL", (unsigned int)value,
map->output_section->s.segname,
map->output_section->s.sectname, i);
return;
}
section_map = &(cur_obj->section_maps[j]);
if(section_map->nfine_relocs == 0)
value = value -
section_map->s->addr +
section_map->output_section->s.addr +
section_map->offset;
else
value =
section_map->output_section->s.addr +
fine_reloc_output_offset(section_map,
value - section_map->s->addr);
if(host_byte_sex != target_byte_sex)
value = SWAP_LONG(value);
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
&value, sizeof(unsigned long));
}
else{
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
contents + map->fine_relocs[i].input_offset,
map->s->size - map->fine_relocs[i].input_offset);
}
}
}
}
else if((map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS &&
prebinding == TRUE &&
arch_flag.cputype == CPU_TYPE_I386 &&
(map->s->flags & S_ATTR_SELF_MODIFYING_CODE) ==
S_ATTR_SELF_MODIFYING_CODE &&
map->s->reserved2 == 5){
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;
for(i = 0; i < map->nfine_relocs; i++){
if(map->fine_relocs[i].use_contents == TRUE &&
(dead_strip == FALSE || map->fine_relocs[i].live == TRUE)){
index = indirect_symtab[map->s->reserved1 +
(map->fine_relocs[i].input_offset / 5)];
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 = lookup_symbol(strings +
nlists[index].n_un.n_strx);
if(merged_symbol->name_len == 0)
fatal("interal error, scatter_copy() failed"
" in looking up external symbol");
}
else
merged_symbol = undefined_map->merged_symbol;
value = merged_symbol->nlist.n_value;
delta = value - (map->output_section->s.addr +
map->fine_relocs[i].output_offset + 5);
jmpEntry = output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset;
if(host_byte_sex != target_byte_sex)
delta = SWAP_LONG(delta);
*jmpEntry = 0xE9;
memcpy(jmpEntry + 1, &delta, sizeof(unsigned long));
}
}
}
else
#endif
if((map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
(map->s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_COALESCED){
for(i = 0; i < map->nfine_relocs - 1; i++){
if(map->fine_relocs[i].use_contents == TRUE &&
(dead_strip == FALSE || map->fine_relocs[i].live == TRUE)){
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
contents + map->fine_relocs[i].input_offset,
map->fine_relocs[i+1].input_offset -
map->fine_relocs[i].input_offset);
}
}
if(map->fine_relocs[i].use_contents == TRUE &&
(dead_strip == FALSE || map->fine_relocs[i].live == TRUE)){
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
contents + map->fine_relocs[i].input_offset,
map->s->size - map->fine_relocs[i].input_offset);
}
}
else{
for(i = 0; i < map->nfine_relocs - 1; i++){
if(dead_strip == FALSE || map->fine_relocs[i].live == TRUE){
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
contents + map->fine_relocs[i].input_offset,
map->fine_relocs[i+1].input_offset -
map->fine_relocs[i].input_offset);
}
}
if(dead_strip == FALSE || map->fine_relocs[i].live == TRUE){
memcpy(output_addr + map->output_section->s.offset +
map->fine_relocs[i].output_offset,
contents + map->fine_relocs[i].input_offset,
map->s->size - map->fine_relocs[i].input_offset);
}
}
}
#ifndef RLD
static
void
reloc_output_for_dyld(
struct section_map *map,
struct relocation_info *relocs,
struct relocation_info *output_locrel,
struct relocation_info *output_extrel,
unsigned long *nlocrel,
unsigned long *nextrel)
{
unsigned long i, addr_adjust, temp, pair;
struct relocation_info *reloc;
struct scattered_relocation_info *sreloc;
unsigned long r_address, r_extern, r_type, r_scattered, r_pcrel,
r_symbolnum, r_value;
enum bool partial_section, sectdiff, pic, has_sect_diff_relocs;
enum bool flag_relocs, first_time;
sreloc = NULL;
first_time = TRUE;
if(read_only_reloc_flag != READ_ONLY_RELOC_SUPPRESS)
flag_relocs = is_merged_section_read_only(map->output_section);
else
flag_relocs = FALSE;
if(flag_relocs == TRUE)
clear_read_only_reloc_flags();
has_sect_diff_relocs = FALSE;
*nlocrel = 0;
*nextrel = 0;
partial_section = (enum bool)
(dead_strip == TRUE ||
(map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
(map->s->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
(map->s->flags & SECTION_TYPE) == S_COALESCED);
if(segs_read_only_addr_specified == TRUE)
addr_adjust = map->output_section->s.addr -
segs_read_write_addr;
else
addr_adjust = map->output_section->s.addr -
merged_segments->sg.vmaddr;
for(i = 0; i < map->s->nreloc; i++){
reloc = relocs + i;
if((relocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)(relocs + i);
r_scattered = 1;
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_type = sreloc->r_type;
r_extern = 0;
r_value = sreloc->r_value;
r_symbolnum = 1;
}
else{
r_scattered = 0;
r_address = reloc->r_address;
r_pcrel = reloc->r_pcrel;
r_type = reloc->r_type;
r_extern = reloc->r_extern;
r_symbolnum = reloc->r_symbolnum;
}
if(reloc_has_pair(arch_flag.cputype, r_type))
pair = 1;
else
pair = 0;
if(partial_section){
if(fine_reloc_offset_in_output_for_output_offset(map,
r_address) == FALSE){
i += pair;
continue;
}
}
if(r_extern == 0){
sectdiff = reloc_is_sectdiff(arch_flag.cputype, r_type);
has_sect_diff_relocs |= sectdiff;
pic = (enum bool)
(sectdiff == TRUE ||
(r_pcrel == 1 && r_symbolnum != NO_SECT));
}
else
pic = FALSE;
if((arch_flag.cputype == CPU_TYPE_POWERPC &&
r_type == PPC_RELOC_JBSR) ||
(arch_flag.cputype == CPU_TYPE_HPPA &&
r_type == HPPA_RELOC_JBSR)){
i += pair;
continue;
}
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
if(r_extern){
reloc->r_address += addr_adjust;
memcpy(output_extrel + *nextrel, reloc,
sizeof(struct relocation_info) * (1 + pair));
(*nextrel) += 1 + pair;
if(flag_relocs == TRUE)
flag_read_only_reloc(map->s, r_symbolnum, &first_time);
}
else if(pic == FALSE){
if(r_scattered)
sreloc->r_address += addr_adjust;
else
reloc->r_address += addr_adjust;
memcpy(output_locrel + *nlocrel, reloc,
sizeof(struct relocation_info) * (1 + pair));
(*nlocrel) += 1 + pair;
}
}
else if(has_dynamic_linker_command){
if(r_extern){
reloc->r_address += addr_adjust;
memcpy(output_extrel + *nextrel, reloc,
sizeof(struct relocation_info) * (1 + pair));
(*nextrel) += 1 + pair;
if(flag_relocs == TRUE)
flag_read_only_reloc(map->s, r_symbolnum, &first_time);
}
else if(save_lazy_symbol_pointer_relocs == TRUE &&
(map->s->flags & SECTION_TYPE) ==
S_LAZY_SYMBOL_POINTERS){
if(r_scattered){
temp = sreloc->r_address + addr_adjust;
sreloc->r_address += addr_adjust;
if(sreloc->r_address != temp)
error_with_cur_obj("can't create relocation entry "
"for prebinding (address of section (%.16s,"
"%.16s) more than 24-bits away from first "
"segment, use -noprebind)",
map->s->segname, map->s->sectname);
}
else
reloc->r_address += addr_adjust;
memcpy(output_locrel + *nlocrel, reloc,
sizeof(struct relocation_info) * (1 + pair));
(*nlocrel) += 1 + pair;
}
}
else{
if(r_extern){
reloc->r_address += addr_adjust;
memcpy(output_extrel + *nextrel, reloc,
sizeof(struct relocation_info) * (1 + pair));
(*nextrel) += 1 + pair;
if(flag_relocs == TRUE)
flag_read_only_reloc(map->s, r_symbolnum, &first_time);
}
else if(pic == FALSE){
if(r_scattered)
sreloc->r_address += addr_adjust;
else
reloc->r_address += addr_adjust;
memcpy(output_locrel + *nlocrel, reloc,
sizeof(struct relocation_info) * (1 + pair));
(*nlocrel) += 1 + pair;
}
}
i += pair;
}
if(flag_relocs == TRUE && *nlocrel != 0){
if(read_only_reloc_flag == READ_ONLY_RELOC_ERROR)
error_with_cur_obj("has local relocation entries in "
"non-writable section (%.16s,%.16s)",
map->s->segname, map->s->sectname);
else
warning_with_cur_obj("has local relocation entries in "
"non-writable section (%.16s,%.16s)",
map->s->segname, map->s->sectname);
}
if(sect_diff_reloc_flag != SECT_DIFF_RELOC_SUPPRESS &&
has_sect_diff_relocs == TRUE){
if(sect_diff_reloc_flag == SECT_DIFF_RELOC_ERROR)
error_with_cur_obj("has section difference relocation entries "
"in section (%.16s,%.16s)", map->s->segname,
map->s->sectname);
else
warning_with_cur_obj("has section difference relocation entries"
" in section (%.16s,%.16s)", map->s->segname,
map->s->sectname);
}
}
static
enum bool
is_merged_section_read_only(
struct merged_section *key)
{
struct merged_segment **p, *msg;
struct merged_section **q, *ms;
p = &merged_segments;
while(*p){
msg = *p;
q = &(msg->content_sections);
while(*q){
ms = *q;
if(ms == key){
if((msg->sg.initprot & VM_PROT_WRITE) == 0)
return(TRUE);
else
return(FALSE);
}
q = &(ms->next);
}
q = &(msg->zerofill_sections);
while(*q){
ms = *q;
if(ms == key){
if((msg->sg.initprot & VM_PROT_WRITE) == 0)
return(TRUE);
else
return(FALSE);
}
q = &(ms->next);
}
p = &(msg->next);
}
fatal("internal error: is_merged_section_read_only() called with "
"bad merged section");
return(FALSE);
}
__private_extern__
enum bool
is_merged_symbol_coalesced(
struct merged_symbol *merged_symbol)
{
struct merged_segment **p, *msg;
struct merged_section **q, *ms;
if((merged_symbol->nlist.n_type & N_TYPE) != N_SECT)
return(FALSE);
p = &merged_segments;
while(*p){
msg = *p;
q = &(msg->content_sections);
while(*q){
ms = *q;
if(ms->output_sectnum == merged_symbol->nlist.n_sect){
if((ms->s.flags & SECTION_TYPE) == S_COALESCED)
return(TRUE);
else
return(FALSE);
}
q = &(ms->next);
}
p = &(msg->next);
}
fatal("internal error: is_merged_symbol_coalesced() called with "
"bad merged symbol");
return(FALSE);
}
static
unsigned long
scatter_copy_relocs(
struct section_map *map,
struct relocation_info *relocs,
struct relocation_info *output_relocs)
{
unsigned long i, nreloc;
struct relocation_info *reloc;
struct scattered_relocation_info *sreloc;
unsigned long r_address, r_type;
nreloc = 0;
for(i = 0; i < map->s->nreloc; i++){
reloc = relocs + i;
if((relocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)(relocs + i);
r_address = sreloc->r_address;
r_type = sreloc->r_type;
}
else{
r_address = reloc->r_address;
r_type = reloc->r_type;
}
if(fine_reloc_offset_in_output_for_output_offset(map, r_address)){
memcpy(output_relocs + nreloc, reloc,
sizeof(struct relocation_info));
nreloc++;
if(reloc_has_pair(arch_flag.cputype, r_type)){
memcpy(output_relocs + nreloc, reloc + 1,
sizeof(struct relocation_info));
nreloc++;
i++;
}
}
else if(reloc_has_pair(arch_flag.cputype, r_type))
i++;
}
return(nreloc);
}
__private_extern__
void
nop_pure_instruction_scattered_sections(void)
{
struct merged_segment **p, *msg;
struct merged_section **content, *ms;
char *contents;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->order_filename != NULL &&
(ms->s.flags & SECTION_TYPE) == S_REGULAR) ||
((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 ||
(ms->s.flags & SECTION_TYPE) == S_COALESCED)){
if(arch_flag.cputype == CPU_TYPE_I386 &&
(ms->s.flags & S_ATTR_PURE_INSTRUCTIONS) != 0){
contents = output_addr + ms->s.offset;
memset(contents, 0x90, ms->s.size);
}
}
content = &(ms->next);
}
p = &(msg->next);
}
}
__private_extern__
void
flush_scatter_copied_sections(void)
{
struct merged_segment **p, *msg;
struct merged_section **content, *ms;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->contents_filename == NULL &&
(ms->order_filename != NULL || dead_strip == TRUE) &&
(ms->s.flags & SECTION_TYPE) == S_REGULAR) ||
((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 ||
(ms->s.flags & SECTION_TYPE) == S_COALESCED)){
output_flush(ms->s.offset, ms->s.size);
}
else if((dead_strip == TRUE) &&
((ms->s.flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
(ms->s.flags & SECTION_TYPE) == S_MOD_TERM_FUNC_POINTERS)){
output_flush(ms->s.offset, ms->s.size);
}
content = &(ms->next);
}
p = &(msg->next);
}
}
__private_extern__
void
live_marking(void)
{
struct merged_symbol *merged_symbol;
enum bool found;
unsigned long i, input_offset, section_type;
struct fine_reloc *fine_reloc;
struct merged_segment *msg, **p;
struct merged_section *ms, **content, **zerofill;
struct timeval t0, t1, t2, t3, t4, t5;
double time_used;
if(dead_strip_times == TRUE)
gettimeofday(&t0, NULL);
build_references();
if(errors)
return;
if(dead_strip_times == TRUE)
gettimeofday(&t1, NULL);
if(filetype != MH_FVMLIB &&
filetype != MH_DYLIB &&
filetype != MH_BUNDLE){
if(entry_point_name != NULL){
merged_symbol = lookup_symbol(entry_point_name);
if(merged_symbol->name_len != 0){
#ifdef DEBUG
if(((debug & (1 << 25)) || (debug & (1 << 26)))){
print("** In live_marking() -e symbol ");
print_obj_name(merged_symbol->definition_object);
print("%s\n", merged_symbol->nlist.n_un.n_name);
}
#endif
merged_symbol->live = TRUE;
fine_reloc = merged_symbol->fine_reloc;
if(fine_reloc != NULL)
fine_reloc->live = TRUE;
}
}
else{
found = FALSE;
for(msg = merged_segments;
msg != NULL && found == FALSE;
msg = msg->next){
for(ms = msg->content_sections;
ms != NULL && found == FALSE;
ms = ms->next){
for(i = 0;
i < ms->norder_load_maps && found == FALSE;
i++){
if(ms->order_load_maps[i].size != 0){
input_offset = ms->order_load_maps[i].value -
ms->order_load_maps[i].section_map->s->addr;
fine_reloc = fine_reloc_for_input_offset(
ms->order_load_maps[i].section_map,
input_offset);
fine_reloc->live = TRUE;
if(fine_reloc->merged_symbol != NULL)
fine_reloc->merged_symbol->live = TRUE;
found = TRUE;
#ifdef DEBUG
if(((debug & (1 << 25)) ||
(debug & (1 << 26)))){
print("** In live_marking() entry point ");
if(ms->order_load_maps[i].archive_name !=
NULL)
print("%s(%s):",
ms->order_load_maps[i].archive_name,
ms->order_load_maps[i].object_name);
else
print("%s:",
ms->order_load_maps[i].object_name);
print("(%.16s,%.16s):0x%x:",
ms->s.segname, ms->s.sectname,
(unsigned int)
(fine_reloc->input_offset));
print("%s\n",
ms->order_load_maps[i].symbol_name);
}
#endif
}
}
}
}
}
}
if(filetype == MH_DYLIB && init_name != NULL){
merged_symbol = lookup_symbol(init_name);
if(merged_symbol->name_len != 0){
#ifdef DEBUG
if(((debug & (1 << 25)) || (debug & (1 << 26)))){
print("** In live_marking() -init symbol ");
print_obj_name(merged_symbol->definition_object);
print("%s\n", merged_symbol->nlist.n_un.n_name);
}
#endif
merged_symbol->live = TRUE;
if(merged_symbol->fine_reloc != NULL)
merged_symbol->fine_reloc->live = TRUE;
}
}
mark_globals_live();
mark_N_NO_DEAD_STRIP_local_symbols_live();
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->s.flags & S_ATTR_NO_DEAD_STRIP)
mark_all_fine_relocs_live_in_section(ms);
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
if(ms->s.flags & S_ATTR_NO_DEAD_STRIP)
mark_all_fine_relocs_live_in_section(ms);
zerofill = &(ms->next);
}
p = &(msg->next);
}
if(no_dead_strip_inits_and_terms == TRUE){
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
section_type = ms->s.flags & SECTION_TYPE;
if(section_type == S_MOD_INIT_FUNC_POINTERS ||
section_type == S_MOD_TERM_FUNC_POINTERS)
mark_all_fine_relocs_live_in_section(ms);
content = &(ms->next);
}
p = &(msg->next);
}
}
if(dead_strip_times == TRUE)
gettimeofday(&t2, NULL);
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
#ifdef DEBUG
if(debug & (1 << 25))
print("In live_marking() for section (%.16s,%.16s)\n",
ms->s.segname, ms->s.sectname);
#endif
walk_references_in_section(MARK_LIVE, ms);
content = &(ms->next);
}
p = &(msg->next);
}
if(dead_strip_times == TRUE)
gettimeofday(&t3, NULL);
if(no_dead_strip_inits_and_terms == FALSE){
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
section_type = ms->s.flags & SECTION_TYPE;
if(section_type == S_MOD_INIT_FUNC_POINTERS ||
section_type == S_MOD_TERM_FUNC_POINTERS)
walk_references_in_section(SEARCH_FOR_LIVE, ms);
content = &(ms->next);
}
p = &(msg->next);
}
}
if(dead_strip_times == TRUE)
gettimeofday(&t4, NULL);
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->s.flags & S_ATTR_LIVE_SUPPORT)
walk_references_in_section(CHECK_FOR_LIVE_TOUCH, ms);
content = &(ms->next);
}
p = &(msg->next);
}
if(dead_strip_times == TRUE){
gettimeofday(&t5, NULL);
time_used = calculate_time_used(&t0, &t1);
print("building of references: %f\n", time_used);
time_used = calculate_time_used(&t1, &t2);
print("mark initial live blocks: %f\n", time_used);
time_used = calculate_time_used(&t2, &t3);
print("mark live blocks referenced: %f\n", time_used);
time_used = calculate_time_used(&t3, &t4);
print("mark live constructors: %f\n", time_used);
time_used = calculate_time_used(&t4, &t5);
print("mark live exception frames: %f\n", time_used);
}
}
static
double
calculate_time_used(
struct timeval *start,
struct timeval *end)
{
double time_used;
time_used = end->tv_sec - start->tv_sec;
if(end->tv_usec >= start->tv_usec)
time_used += ((double)(end->tv_usec - start->tv_usec)) / 1000000.0;
else
time_used += -1.0 +
((double)(1000000 + end->tv_usec - start->tv_usec) / 1000000.0);
return(time_used);
}
static
void
build_references(
void)
{
struct merged_segment *msg, **p;
struct merged_section *ms, **content;
set_fine_relocs_for_merged_symbols();
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
#ifdef DEBUG
if(debug & (1 << 27))
print("In build_references() for section (%.16s,%.16s)\n",
ms->s.segname, ms->s.sectname);
#endif
setup_references_in_section(ms);
if(errors)
return;
content = &(ms->next);
}
p = &(msg->next);
}
#ifdef DEBUG
if(debug & (1 << 28))
print_references();
#endif
}
#ifdef DEBUG
static
void
print_references(
void)
{
unsigned long i, j, k;
struct object_list *object_list, **q;
struct object_file *obj;
struct fine_reloc *fine_relocs, *fine_reloc;
struct section_map *map;
struct ref *ref;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
obj = &(object_list->object_files[i]);
if(obj == base_obj)
continue;
if(obj->dylib)
continue;
if(obj->bundle_loader)
continue;
if(obj->dylinker)
continue;
for(j = 0; j < obj->nsection_maps; j++){
if(obj->section_maps[j].s->size == 0)
continue;
map = &(obj->section_maps[j]);
if(map->nfine_relocs == 0)
continue;
print("references for ");
print_obj_name(obj);
print("in section (%.16s,%.16s)\n",
map->s->segname, map->s->sectname);
fine_relocs = map->fine_relocs;
for(k = 0; k < map->nfine_relocs; k++){
fine_reloc = map->fine_relocs + k;
if(fine_reloc->refs != NULL){
print(" offset:0x%x",
(unsigned int)(fine_reloc->input_offset));
if(fine_reloc->merged_symbol != NULL)
print(":%s", fine_reloc->
merged_symbol->nlist.n_un.n_name);
else
print_symbol_name_from_order_load_maps(map,
map->s->addr + fine_reloc->input_offset);
print("\n");
}
for(ref = fine_reloc->refs;
ref != NULL;
ref = ref->next){
if(ref->merged_symbol != NULL)
print(" %s\n",
ref->merged_symbol->nlist.n_un.n_name);
else{
print(" (%.16s,%.16s):0x%x",
ref->map->s->segname,
ref->map->s->sectname,
(unsigned int)
(ref->fine_reloc->input_offset));
print_symbol_name_from_order_load_maps(
ref->map,
ref->map->s->addr +
ref->fine_reloc->input_offset);
printf("\n");
}
}
}
}
}
}
}
#endif
static
void
setup_references_in_section(
struct merged_section *ms)
{
unsigned long i, j;
struct object_list *object_list, **q;
struct object_file *obj;
struct section_map *map;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
obj = &(object_list->object_files[i]);
if(obj == base_obj)
continue;
if(obj->dylib)
continue;
if(obj->bundle_loader)
continue;
if(obj->dylinker)
continue;
map = NULL;
for(j = 0; j < obj->nsection_maps; j++){
if(obj->section_maps[j].output_section != ms)
continue;
if(obj->section_maps[j].s->size == 0)
continue;
map = &(obj->section_maps[j]);
break;
}
if(map == NULL)
continue;
#ifdef DEBUG
if(debug & (1 << 27)){
print(" In setup_references_in_section() with object ");
print_obj_name(obj);
print("\n");
}
#endif
setup_references(map, obj);
}
}
}
static
void
setup_references(
struct section_map *map,
struct object_file *obj)
{
unsigned long i, pair;
struct relocation_info *relocs, reloc;
struct scattered_relocation_info *sreloc;
unsigned long r_address, r_type;
char *contents;
struct live_refs refs;
struct fine_reloc *fine_reloc;
#ifdef DEBUG
if(debug & (1 << 27)){
print(" In setup_references() ");
print_obj_name(obj);
print("(%.16s,%.16s)\n", map->s->segname, map->s->sectname);
}
#endif
relocs = (struct relocation_info *)(obj->obj_addr + map->s->reloff);
if(obj->swapped && map->input_relocs_already_swapped == FALSE){
swap_relocation_info(relocs, map->s->nreloc, host_byte_sex);
map->input_relocs_already_swapped = TRUE;
}
for(i = 0; i < map->s->nreloc; i++){
reloc = relocs[i];
if((reloc.r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)(&reloc);
r_address = sreloc->r_address;
r_type = sreloc->r_type;
}
else{
r_address = reloc.r_address;
r_type = reloc.r_type;
}
if(reloc_has_pair(arch_flag.cputype, r_type)){
if(i + 1 >= map->s->nreloc)
return;
pair = 1;
}
else
pair = 0;
#ifdef DEBUG
if(debug & (1 << 27)){
print(" reloc entry %lu", i);
if(pair)
print(",%lu", i+1);
print("\n");
}
#endif
cur_obj = obj;
contents = obj->obj_addr + map->s->offset;
if(arch_flag.cputype == CPU_TYPE_POWERPC ||
arch_flag.cputype == CPU_TYPE_VEO)
ppc_reloc(contents, relocs, map, &refs, i);
else if(arch_flag.cputype == CPU_TYPE_MC680x0)
generic_reloc(contents, relocs, map, FALSE, &refs, i);
else if(arch_flag.cputype == CPU_TYPE_I386)
generic_reloc(contents, relocs, map, TRUE, &refs, i);
else if(arch_flag.cputype == CPU_TYPE_ARM)
arm_reloc(contents, relocs, map, &refs, i);
else if(arch_flag.cputype == CPU_TYPE_MC88000 ||
arch_flag.cputype == CPU_TYPE_HPPA ||
arch_flag.cputype == CPU_TYPE_SPARC ||
arch_flag.cputype == CPU_TYPE_I860)
fatal("-dead_strip not supported with cputype (%d)",
arch_flag.cputype);
else
fatal("internal error: setup_references() "
"called with unknown cputype (%d) set",
arch_flag.cputype);
if(errors)
return;
if(refs.ref1.ref_type != LIVE_REF_NONE){
fine_reloc = fine_reloc_for_input_offset(map, r_address);
setup_reference(&refs.ref1, obj, fine_reloc);
}
if(refs.ref2.ref_type != LIVE_REF_NONE){
fine_reloc = fine_reloc_for_input_offset(map, r_address);
setup_reference(&refs.ref2, obj, fine_reloc);
}
i += pair;
}
}
static
void
setup_reference(
struct live_ref *ref,
struct object_file *obj,
struct fine_reloc *self_fine_reloc)
{
unsigned long r_symbolnum;
struct section_map *local_map;
struct fine_reloc *ref_fine_reloc;
struct ref r, *refs, *new_ref;
r.next = NULL;
r.fine_reloc = NULL;
r.map = NULL;
r.obj = NULL;
r.merged_symbol = NULL;
if(ref->ref_type == LIVE_REF_VALUE){
r_symbolnum = r_symbolnum_from_r_value(ref->value, obj);
local_map = &(obj->section_maps[r_symbolnum - 1]);
ref_fine_reloc = fine_reloc_for_input_offset(local_map,
ref->value - local_map->s->addr);
#ifdef DEBUG
if(debug & (1 << 27)){
print(" ref ");
print("(%.16s,%.16s):0x%x", local_map->s->segname,
local_map->s->sectname,
(unsigned int)(ref_fine_reloc->input_offset));
print_symbol_name_from_order_load_maps(local_map,
local_map->s->addr + ref_fine_reloc->input_offset);
printf("\n");
}
#endif
if(self_fine_reloc == ref_fine_reloc)
return;
r.fine_reloc = ref_fine_reloc;
r.map = local_map;
r.obj = obj;
r.merged_symbol = NULL;
}
else if(ref->ref_type == LIVE_REF_SYMBOL){
r.merged_symbol = ref->merged_symbol;
r.fine_reloc = NULL;
r.map = NULL;
r.obj = NULL;
#ifdef DEBUG
if(debug & (1 << 27)){
print(" ref ");
print("%s", ref->merged_symbol->nlist.n_un.n_name);
printf("\n");
}
#endif
}
for(refs = self_fine_reloc->refs ; refs != NULL ; refs = refs->next){
if(r.fine_reloc == refs->fine_reloc &&
r.map == refs->map &&
r.obj == refs->obj &&
r.merged_symbol == refs->merged_symbol)
return;
}
new_ref = allocate(sizeof(struct ref));
*new_ref = r;
new_ref->next = self_fine_reloc->refs;
self_fine_reloc->refs = new_ref;
}
__private_extern__
struct fine_reloc *
get_fine_reloc_for_merged_symbol(
struct merged_symbol *merged_symbol,
struct section_map **local_map)
{
unsigned long n_sect, input_offset, i;
struct section_map *map;
struct fine_reloc *fine_reloc;
if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
if(merged_symbol->defined_in_dylib == FALSE &&
(merged_symbol->nlist.n_type & N_TYPE) == N_SECT){
n_sect = merged_symbol->nlist.n_sect;
map = &(merged_symbol->definition_object->section_maps[n_sect - 1]);
if(map->nfine_relocs != 0){
input_offset = merged_symbol->nlist.n_value - map->s->addr;
fine_reloc = fine_reloc_for_input_offset(map, input_offset);
if(fine_reloc->merged_symbol != merged_symbol){
for(i = 0; i < map->nfine_relocs; i++){
if(map->fine_relocs[i].merged_symbol == merged_symbol){
fine_reloc = map->fine_relocs + i;
break;
}
}
}
if(local_map != NULL)
*local_map = map;
return(fine_reloc);
}
}
return(NULL);
}
static
void
mark_all_fine_relocs_live_in_section(
struct merged_section *ms)
{
unsigned long i, j;
struct object_list *object_list, **q;
struct fine_reloc *fine_relocs;
struct object_file *obj;
struct section_map *map;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
obj = &(object_list->object_files[i]);
if(obj == base_obj)
continue;
if(obj->dylib)
continue;
if(obj->bundle_loader)
continue;
if(obj->dylinker)
continue;
map = NULL;
for(j = 0; j < obj->nsection_maps; j++){
if(obj->section_maps[j].output_section != ms)
continue;
if(obj->section_maps[j].s->size == 0)
continue;
map = &(obj->section_maps[j]);
break;
}
if(map == NULL)
continue;
#ifdef DEBUG
if(debug & (1 << 25)){
print(" mark_all_fine_relocs_live_in_section() with "
"object");
print_obj_name(obj);
print("\n");
}
#endif
fine_relocs = map->fine_relocs;
for(j = 0; j < map->nfine_relocs; j++){
fine_relocs[j].live = TRUE;
}
}
}
}
static
void
walk_references_in_section(
enum walk_references_operation operation,
struct merged_section *ms)
{
unsigned long i, j;
struct object_list *object_list, **q;
struct fine_reloc *fine_relocs;
struct object_file *obj;
struct section_map *map;
enum bool found_live;
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
obj = &(object_list->object_files[i]);
if(obj == base_obj)
continue;
if(obj->dylib)
continue;
if(obj->bundle_loader)
continue;
if(obj->dylinker)
continue;
map = NULL;
for(j = 0; j < obj->nsection_maps; j++){
if(obj->section_maps[j].output_section != ms)
continue;
if(obj->section_maps[j].s->size == 0)
continue;
map = &(obj->section_maps[j]);
break;
}
if(map == NULL)
continue;
#ifdef DEBUG
if(debug & (1 << 25)){
print(" In walk_references_in_section() with object ");
print_obj_name(obj);
print("\n");
}
#endif
fine_relocs = map->fine_relocs;
for(j = 0; j < map->nfine_relocs; j++){
if(operation == MARK_LIVE){
if(fine_relocs[j].live == TRUE &&
fine_relocs[j].refs_marked_live == FALSE){
walk_references(
MARK_LIVE,
fine_relocs + j,
map,
obj);
}
}
else if(operation == SEARCH_FOR_LIVE ||
operation == CHECK_FOR_LIVE_TOUCH){
found_live = FALSE;
if(fine_relocs[j].searched_for_live_refs == FALSE ||
operation == CHECK_FOR_LIVE_TOUCH){
found_live = walk_references(
operation,
fine_relocs + j,
map,
obj);
if(found_live == TRUE){
#ifdef DEBUG
if(debug & (1 << 25)){
print(" In walk_references_in_section("
"%s) with object ",
walk_references_operation_names[
operation]);
print_obj_name(obj);
print("fine_relocs[%lu].input_offset = "
"0x%x found_live == TRUE\n", j,
(unsigned int)
(fine_relocs[j].input_offset) );
}
#endif
fine_relocs[j].live = TRUE;
if(fine_relocs[j].refs_marked_live == FALSE){
walk_references(
MARK_LIVE,
fine_relocs + j,
map,
obj);
}
}
}
}
else{
fatal("internal error: walk_references_in_section() "
"called with unknown operation (%d)", operation);
}
}
}
}
}
static
enum bool
walk_references(
enum walk_references_operation operation,
struct fine_reloc *fine_reloc,
struct section_map *map,
struct object_file *obj)
{
enum bool found_live;
struct ref r, *ref;
#ifdef DEBUG
if(debug & (1 << 25)){
print(" In walk_references(%s) ",
walk_references_operation_names[operation]);
print_obj_name(obj);
print("(%.16s,%.16s):0x%x", map->s->segname, map->s->sectname,
(unsigned int)(fine_reloc->input_offset));
if(fine_reloc->merged_symbol != NULL)
print(":%s", fine_reloc->merged_symbol->nlist.n_un.n_name);
print("\n");
}
#endif
if(operation == MARK_LIVE){
fine_reloc->refs_marked_live = TRUE;
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){
if(indirect_live_ref(fine_reloc, map, obj, &r) == TRUE)
ref_operation(MARK_LIVE, &r, obj);
}
}
else{
fine_reloc->searched_for_live_refs = TRUE;
if(fine_reloc->live == TRUE)
return(TRUE);
}
for(ref = fine_reloc->refs; ref != NULL; ref = ref->next){
if(operation == MARK_LIVE){
ref_operation(MARK_LIVE, ref, obj);
}
else if(operation == SEARCH_FOR_LIVE ||
operation == CHECK_FOR_LIVE_TOUCH){
found_live = ref_operation(operation, ref, obj);
if(found_live == TRUE)
return(TRUE);
}
else{
fatal("internal error: walk_references() called with "
"unknown operation (%d)", operation);
}
}
return(FALSE);
}
static
enum bool
ref_operation(
enum walk_references_operation operation,
struct ref *ref,
struct object_file *obj)
{
unsigned long n_sect;
struct section_map *local_map;
struct merged_symbol *indr_merged_symbol;
enum bool found_live;
struct fine_reloc *ref_fine_reloc;
if(ref->merged_symbol == NULL){
#ifdef DEBUG
if((((debug & (1 << 25)) || (debug & (1 << 26))) &&
ref->fine_reloc->live != TRUE)){
print("** In ref_operation(%s) ",
walk_references_operation_names[operation]);
print_obj_name(obj);
print("(%.16s,%.16s):0x%x", ref->map->s->segname,
ref->map->s->sectname,
(unsigned int)(ref->fine_reloc->input_offset));
if(ref->fine_reloc->merged_symbol != NULL){
print(":%s",
ref->fine_reloc->merged_symbol->nlist.n_un.n_name);
}
else{
print_symbol_name_from_order_load_maps(ref->map,
ref->map->s->addr + ref->fine_reloc->input_offset);
}
print("\n");
}
#endif
if(operation == MARK_LIVE){
ref->fine_reloc->live = TRUE;
if(ref->fine_reloc->merged_symbol != NULL)
ref->fine_reloc->merged_symbol->live = TRUE;
if(ref->fine_reloc->refs_marked_live == FALSE){
walk_references(
MARK_LIVE,
ref->fine_reloc,
ref->map,
ref->obj);
}
}
else if(operation == SEARCH_FOR_LIVE){
if(ref->fine_reloc->live == TRUE)
return(TRUE);
else{
if(ref->fine_reloc->searched_for_live_refs == FALSE){
found_live = walk_references(
SEARCH_FOR_LIVE,
ref->fine_reloc,
ref->map,
ref->obj);
if(found_live == TRUE)
return(TRUE);
}
}
}
else if(operation == CHECK_FOR_LIVE_TOUCH){
if(ref->fine_reloc->live == TRUE &&
(ref->map->s->flags & S_ATTR_LIVE_SUPPORT) == 0)
return(TRUE);
else
return(FALSE);
}
else{
fatal("internal error: ref_operation() called with "
"unknown operation (%d)", operation);
}
}
else {
if(operation == MARK_LIVE){
ref->merged_symbol->live = TRUE;
if((ref->merged_symbol->nlist.n_type & N_TYPE) == N_INDR){
indr_merged_symbol = (struct merged_symbol *)
ref->merged_symbol->nlist.n_value;
indr_merged_symbol->live = TRUE;
}
}
else if(operation == SEARCH_FOR_LIVE){
if(ref->merged_symbol->live == TRUE)
return(TRUE);
}
else if(operation == CHECK_FOR_LIVE_TOUCH){
if(ref->merged_symbol->live == TRUE)
return(TRUE);
else
return(FALSE);
}
else{
fatal("internal error: ref_operation() called with "
"unknown operation (%d)", operation);
}
if(ref->merged_symbol->defined_in_dylib == TRUE){
if(operation == MARK_LIVE){
;
}
else{
;
}
}
else {
ref_fine_reloc = ref->merged_symbol->fine_reloc;
if((ref->merged_symbol->nlist.n_type & N_TYPE) == N_SECT){
n_sect = ref->merged_symbol->nlist.n_sect;
local_map = &(ref->merged_symbol->definition_object->
section_maps[n_sect - 1]);
}
else
local_map = NULL;
if(ref_fine_reloc != NULL){
#ifdef DEBUG
if((((debug & (1 << 25)) || (debug & (1 << 26))) &&
ref_fine_reloc->live != TRUE)){
print("** In ref_operation(%s) ",
walk_references_operation_names[operation]);
print_obj_name(ref->merged_symbol->definition_object);
if(local_map != NULL)
print("(%.16s,%.16s)", local_map->s->segname,
local_map->s->sectname);
print(":%s\n", ref->merged_symbol->nlist.n_un.n_name);
}
#endif
if(operation == MARK_LIVE){
ref_fine_reloc->live = TRUE;
if(ref_fine_reloc->refs_marked_live == FALSE){
walk_references(
MARK_LIVE,
ref_fine_reloc,
local_map,
ref->merged_symbol->definition_object);
}
}
else{
if(ref_fine_reloc->live == TRUE)
return(TRUE);
if(ref_fine_reloc->searched_for_live_refs == FALSE){
found_live = walk_references(
SEARCH_FOR_LIVE,
ref_fine_reloc,
local_map,
ref->merged_symbol->definition_object);
if(found_live == TRUE)
return(TRUE);
}
}
}
}
}
return(FALSE);
}
__private_extern__
unsigned long
r_symbolnum_from_r_value(
unsigned long r_value,
struct object_file *obj)
{
unsigned i, r_symbolnum;
r_symbolnum = 0;
for(i = 0; i < obj->nsection_maps; i++){
if(r_value >= obj->section_maps[i].s->addr &&
r_value < obj->section_maps[i].s->addr +
obj->section_maps[i].s->size){
r_symbolnum = i + 1;
break;
}
}
if(r_symbolnum == 0){
for(i = 0; i < obj->nsection_maps; i++){
if(r_value == obj->section_maps[i].s->addr +
obj->section_maps[i].s->size){
r_symbolnum = i + 1;
break;
}
}
}
return(r_symbolnum);
}
#endif
#ifdef RLD
__private_extern__
void
reset_merged_sections(void)
{
struct merged_segment *msg;
struct merged_section *ms, *prev_ms;
for(msg = original_merged_segments;
msg != NULL;
){
if(msg->next == NULL)
break;
msg = msg->next;
}
if(msg != NULL)
msg->next = debug_merged_segments;
msg = original_merged_segments;
if(msg != NULL && merged_segments->content_sections != NULL){
ms = merged_segments->content_sections;
while(ms != NULL){
if(strncmp(ms->s.segname, msg->sg.segname,
sizeof(msg->sg.segname)) == 0){
msg->content_sections = ms;
ms->s.size = 0;
prev_ms = ms;
ms = ms->next;
while(ms != NULL && strncmp(ms->s.segname, msg->sg.segname,
sizeof(msg->sg.segname)) == 0){
ms->s.size = 0;
prev_ms = ms;
ms = ms->next;
}
prev_ms->next = NULL;
}
else{
msg = msg->next;
}
}
}
msg = original_merged_segments;
if(msg != NULL && merged_segments->zerofill_sections != NULL){
ms = merged_segments->zerofill_sections;
while(ms != NULL){
if(strncmp(ms->s.segname, msg->sg.segname,
sizeof(msg->sg.segname)) == 0){
msg->zerofill_sections = ms;
ms->s.size = 0;
prev_ms = ms;
ms = ms->next;
while(ms != NULL && strncmp(ms->s.segname, msg->sg.segname,
sizeof(msg->sg.segname)) == 0){
ms->s.size = 0;
prev_ms = ms;
ms = ms->next;
}
prev_ms->next = NULL;
}
else{
msg = msg->next;
}
}
}
merged_segments = original_merged_segments;
original_merged_segments = NULL;
}
__private_extern__
void
zero_merged_sections_sizes(void)
{
struct merged_segment **p, *msg;
struct merged_section **q, *ms;
p = &merged_segments;
while(*p){
msg = *p;
q = &(msg->content_sections);
while(*q){
ms = *q;
ms->s.size = 0;
ms->s.align = 0;
if(ms->literal_data != NULL){
if(ms->literal_free != NULL){
(*ms->literal_free)(ms->literal_data, ms);
}
}
q = &(ms->next);
}
q = &(msg->zerofill_sections);
while(*q){
ms = *q;
ms->s.size = 0;
ms->s.align = 0;
q = &(ms->next);
}
p = &(msg->next);
}
}
__private_extern__
void
remove_merged_sections(void)
{
struct merged_segment *msg, *prev_msg, *next_msg;
struct merged_section *ms, *prev_ms, *next_ms;
prev_msg = NULL;
prev_ms = NULL;
if(original_merged_segments != NULL)
reset_merged_sections();
for(msg = merged_segments; msg != NULL; msg = msg->next){
if(msg->set_num == cur_set){
if(msg == merged_segments)
merged_segments = NULL;
else
prev_msg->next = NULL;
while(msg != NULL){
ms = msg->content_sections;
while(ms != NULL){
if(ms->literal_data != NULL){
if(ms->literal_free != NULL){
(*ms->literal_free)(ms->literal_data, ms);
free(ms->literal_data);
ms->literal_data = NULL;
}
}
next_ms = ms->next;
free(ms);
ms = next_ms;
}
ms = msg->zerofill_sections;
while(ms != NULL){
next_ms = ms->next;
free(ms);
ms = next_ms;
}
next_msg = msg->next;
free(msg);
msg = next_msg;
}
break;
}
else{
for(ms = msg->content_sections; ms != NULL; ms = ms->next){
if(ms->set_num == cur_set){
if(ms == msg->content_sections)
msg->content_sections = NULL;
else
prev_ms->next = NULL;
while(ms != NULL){
msg->sg.nsects--;
if(ms->literal_data != NULL)
free(ms->literal_data);
next_ms = ms->next;
free(ms);
ms = next_ms;
}
break;
}
prev_ms = ms;
}
for(ms = msg->zerofill_sections; ms != NULL; ms = ms->next){
if(ms->set_num == cur_set){
if(ms == msg->zerofill_sections)
msg->zerofill_sections = NULL;
else
prev_ms->next = NULL;
while(ms != NULL){
msg->sg.nsects--;
next_ms = ms->next;
free(ms);
ms = next_ms;
}
break;
}
prev_ms = ms;
}
}
prev_msg = msg;
}
}
#endif
#ifdef DEBUG
__private_extern__
void
print_merged_sections(
char *string)
{
struct merged_segment *msg;
struct merged_section *ms;
print("Merged section list (%s)\n", string);
for(msg = merged_segments; msg ; msg = msg->next){
print(" Segment %.16s\n", msg->sg.segname);
print("\tcmd %u\n", msg->sg.cmd);
print("\tcmdsize %u\n", msg->sg.cmdsize);
print("\tvmaddr 0x%x ", (unsigned int)msg->sg.vmaddr);
print("(addr_set %s)\n", msg->addr_set ? "TRUE" : "FALSE");
print("\tvmsize 0x%x\n", (unsigned int)msg->sg.vmsize);
print("\tfileoff %u\n", msg->sg.fileoff);
print("\tfilesize %u\n", msg->sg.filesize);
print("\tmaxprot ");
print_prot(msg->sg.maxprot);
print(" (prot_set %s)\n", msg->prot_set ? "TRUE" : "FALSE");
print("\tinitprot ");
print_prot(msg->sg.initprot);
print("\n");
print("\tnsects %u\n", msg->sg.nsects);
print("\tflags %u\n", msg->sg.flags);
#ifdef RLD
print("\tset_num %lu\n", msg->set_num);
#endif
print("\tfilename %s\n", msg->filename);
print("\tcontent_sections\n");
for(ms = msg->content_sections; ms ; ms = ms->next){
print("\t Section (%.16s,%.16s)\n",
ms->s.segname, ms->s.sectname);
print("\t\taddr 0x%x\n", (unsigned int)ms->s.addr);
print("\t\tsize %u\n", ms->s.size);
print("\t\toffset %u\n", ms->s.offset);
print("\t\talign %u\n", ms->s.align);
print("\t\tnreloc %u\n", ms->s.nreloc);
print("\t\treloff %u\n", ms->s.reloff);
print("\t\tflags %s\n",
section_flags[ms->s.flags & SECTION_TYPE]);
#ifdef RLD
print("\t\tset_num %d\n", ms->set_num);
#endif
if(ms->relocated == TRUE)
print("\t relocated TRUE\n");
else
print("\t relocated FALSE\n");
if(ms->referenced == TRUE)
print("\t referenced TRUE\n");
else
print("\t referenced FALSE\n");
if(ms->contents_filename){
print("\t contents_filename %s\n",
ms->contents_filename);
print("\t file_addr 0x%x\n",
(unsigned int)ms->file_addr);
print("\t file_size %lu\n", ms->file_size);
}
if(ms->order_filename){
print("\t order_filename %s\n",
ms->order_filename);
print("\t order_addr 0x%x\n",
(unsigned int)ms->order_addr);
print("\t order_size %lu\n", ms->order_size);
}
if((ms->s.flags & SECTION_TYPE) == S_CSTRING_LITERALS)
print_cstring_data(ms->literal_data, "\t ");
if((ms->s.flags & SECTION_TYPE) == S_4BYTE_LITERALS)
print_literal4_data(ms->literal_data, "\t ");
if((ms->s.flags & SECTION_TYPE) == S_8BYTE_LITERALS)
print_literal8_data(ms->literal_data, "\t ");
if((ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS)
print_literal_pointer_data(ms->literal_data, "\t ");
}
print("\tzerofill_sections\n");
for(ms = msg->zerofill_sections; ms ; ms = ms->next){
print("\t Section (%.16s,%.16s)\n",
ms->s.segname, ms->s.sectname);
print("\t\taddr 0x%x\n", (unsigned int)ms->s.addr);
print("\t\tsize %u\n", ms->s.size);
print("\t\toffset %u\n", ms->s.offset);
print("\t\talign %u\n", ms->s.align);
print("\t\tnreloc %u\n", ms->s.nreloc);
print("\t\treloff %u\n", ms->s.reloff);
print("\t\tflags %s\n",
section_flags[ms->s.flags & SECTION_TYPE]);
#ifdef RLD
print("\t\tset_num %lu\n", ms->set_num);
#endif
}
}
}
__private_extern__
void
print_merged_section_stats(void)
{
struct merged_segment *msg;
struct merged_section *ms;
for(msg = merged_segments; msg ; msg = msg->next){
for(ms = msg->content_sections; ms ; ms = ms->next){
if((ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS)
literal_pointer_data_stats(ms->literal_data, ms);
else if((ms->s.flags & SECTION_TYPE) == S_CSTRING_LITERALS)
cstring_data_stats(ms->literal_data, ms);
else if((ms->s.flags & SECTION_TYPE) == S_4BYTE_LITERALS)
literal4_data_stats(ms->literal_data, ms);
else if((ms->s.flags & SECTION_TYPE) == S_8BYTE_LITERALS)
literal8_data_stats(ms->literal_data, ms);
}
}
}
__private_extern__
void
print_load_order(
struct load_order *load_order,
unsigned long nload_order,
struct merged_section *ms,
struct object_file *object_file,
char *string)
{
unsigned long i;
print("Load order 0x%x %lu entries for (%.16s,%.16s) of ",
(unsigned int)load_order, nload_order,
ms->s.segname, ms->s.sectname);
print_obj_name(object_file);
print("(%s)\n", string);
for(i = 0; i < nload_order; i++){
print("entry[%lu]\n", i);
print(" name %s\n", load_order[i].name == NULL ? "null" :
load_order[i].name);
print(" value 0x%08x\n",(unsigned int)load_order[i].value);
print(" order %lu\n", load_order[i].order);
print(" input_offset %lu\n", load_order[i].input_offset);
print(" input_size %lu\n", load_order[i].input_size);
print(" output_offset %lu\n", load_order[i].output_offset);
}
}
__private_extern__
void
print_name_arrays(void)
{
unsigned long i, j;
print("Sorted archive names:\n");
for(i = 0; i < narchive_names; i++){
print(" archive name %s\n", archive_names[i].archive_name);
print(" number of objects %lu\n",archive_names[i].nobject_names);
print(" Sorted object names:\n");
for(j = 0; j < archive_names[i].nobject_names; j++){
print("\tobject name %s\n",
archive_names[i].object_names[j].object_name);
print("\tlength %lu\n",
archive_names[i].object_names[j].index_length);
print("\tobject file 0x%x ", (unsigned int)
(archive_names[i].object_names[j].object_file));
print_obj_name(archive_names[i].object_names[j].object_file);
print("\n");
}
}
print("Sorted object names:\n");
for(j = 0; j < nobject_names; j++){
print("\tobject name %s\n", object_names[j].object_name);
print("\tindex %lu\n", object_names[j].index_length);
print("\tobject file 0x%x ",
(unsigned int)(object_names[j].object_file));
print_obj_name(object_names[j].object_file);
print("\n");
}
}
static
void
print_load_symbol_hash_table(void)
{
unsigned long i;
struct load_symbol *load_symbol, *other_name;
print("load_symbol_hash_table:\n");
if(load_symbol_hashtable == NULL)
return;
for(i = 0; i < LOAD_SYMBOL_HASHTABLE_SIZE; i++){
if(load_symbol_hashtable[i] != NULL)
print("[%lu]\n", i);
for(load_symbol = load_symbol_hashtable[i];
load_symbol != NULL;
load_symbol = load_symbol->next){
print("load symbol: %lu\n", i);
if(load_symbol->archive_name != NULL){
print(" (%s:%s:%s) length %lu\n",
load_symbol->archive_name,
load_symbol->object_name,
load_symbol->symbol_name,
load_symbol->index_length);
}
else{
print(" (%s:%s) index %lu\n",
load_symbol->object_name,
load_symbol->symbol_name,
load_symbol->index_length);
}
print(" load_order 0x%x\n",
(unsigned int)(load_symbol->load_order));
print(" other_names 0x%x\n",
(unsigned int)(load_symbol->other_names));
print(" next 0x%x\n",
(unsigned int)(load_symbol->next));
for(other_name = load_symbol->other_names;
other_name != NULL;
other_name = other_name->other_names){
print("other name\n");
if(other_name->archive_name != NULL){
print(" (%s:%s:%s) length %lu\n",
other_name->archive_name,
other_name->object_name,
other_name->symbol_name,
other_name->index_length);
}
else{
print(" (%s:%s) index %lu\n",
other_name->object_name,
other_name->symbol_name,
other_name->index_length);
}
print(" load_order 0x%x\n",
(unsigned int)(other_name->load_order));
print(" other_names 0x%x\n",
(unsigned int)(other_name->other_names));
print(" next 0x%x\n",
(unsigned int)(load_symbol->next));
}
}
}
}
#endif