#ifdef SHLIB
#include "shlib.h"
#endif SHLIB
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <mach/mach.h>
#else
#include <mach/kern_return.h>
#endif
#include <stdarg.h>
#include <string.h>
#include "stuff/openstep_mach.h"
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include <mach-o/hppa/reloc.h>
#include <ar.h>
#include "stuff/arch.h"
#include "stuff/reloc.h"
#include "ld.h"
#include "specs.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 "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 RLD
__private_extern__ unsigned long nreloc = 0;
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);
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);
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_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 norders);
static void count_relocs(
struct section_map *map,
struct relocation_info *relocs,
unsigned long *nlocrel,
unsigned long *nextrel);
static void scatter_copy(
struct section_map *map,
char *contents);
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);
#endif !defined(RLD)
#ifdef DEBUG
static void print_load_symbol_hash_table(
void);
#endif DEBUG
__private_extern__
void
merge_sections(void)
{
unsigned long i;
struct section *s;
struct merged_section *ms;
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;
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 = round(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 |= (ms->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);
if(s->align > ms->s.align)
ms->s.align = s->align;
if(dynamic != TRUE)
ms->s.flags |= (ms->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((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 %lu does not match previous objects "
"sizeof stub %lu", 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_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_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_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_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_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_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_output = NULL;
ms->literal_free = NULL;
}
#ifdef RLD
ms->set_num = cur_set;
#endif RLD
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 RLD
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_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_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_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_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_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_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_output = NULL;
ms->literal_free = NULL;
}
#ifdef RLD
ms->set_num = cur_set;
#endif RLD
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
merge_literal_sections(void)
{
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->order_filename != NULL &&
((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_order)(ms->literal_data, ms);
}
content = &(ms->next);
}
q = &(msg->next);
}
#endif !defined(RLD)
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 RLD
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]));
}
}
}
#ifndef RLD
q = &merged_segments;
while(*q){
msg = *q;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->order_filename != NULL &&
(ms->s.flags & SECTION_TYPE) == S_LITERAL_POINTERS){
(*ms->literal_order)(ms->literal_data, ms);
}
content = &(ms->next);
}
q = &(msg->next);
}
#endif !defined(RLD)
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 RLD
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]));
}
}
}
}
#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)
return;
last_object = add_last_object_file(&link_edit_common_object);
create_name_arrays();
#ifdef DEBUG
if(debug & (1 << 13))
print_name_arrays();
#endif DEBUG
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->order_filename == NULL){
content = &(ms->next);
continue;
}
if((ms->s.flags & SECTION_TYPE) == S_REGULAR)
layout_ordered_section(ms);
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
if(ms->order_filename == NULL){
zerofill = &(ms->next);
continue;
}
layout_ordered_section(ms);
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 prev_output_offset;
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;
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;
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]);
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;
l++;
}
}
#ifdef DEBUG
if(debug & (1 << 14))
print_load_order(load_orders, nload_orders, ms,
cur_obj, "names and values");
#endif DEBUG
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 DEBUG
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 DEBUG
nsection_symbols += nload_orders;
break;
}
}
}
create_load_symbol_hash_table(nsection_symbols);
ambiguous_specifications = 0;
#ifdef DEBUG
if(debug & (1 << 13))
print_load_symbol_hash_table();
#endif DEBUG
for(i = 0; i < ms->order_size; i++){
if(ms->order_addr[i] == '\n')
ms->order_addr[i] = '\0';
}
order = 1;
output_offset = 0;
prev_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);
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)
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++;
output_offset = round(output_offset,
(1 << ms->s.align));
load_order->output_offset = output_offset;
prev_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 = round(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;
output_offset = round(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 DEBUG
load_order = cur_obj->cur_section_map->load_orders;
n = cur_obj->cur_section_map->nload_orders;
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){
cur_obj->cur_section_map->no_load_order = TRUE;
output_offset = round(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){
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 = round(output_offset,
(1 << ms->s.align));
load_order[j].output_offset = output_offset;
output_offset += load_order[j].input_size;
if(sectorder_detail == TRUE){
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){
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);
}
}
}
}
#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 DEBUG
}
}
if(sectorder_detail == FALSE){
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;
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){
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;
continue;
}
n = cur_obj->cur_section_map->nload_orders;
load_orders = cur_obj->cur_section_map->load_orders;
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;
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;
}
qsort(fine_relocs,
n,
sizeof(struct fine_reloc),
(int (*)(const void *, const void *))
qsort_fine_reloc_input_offset);
if(load_map == 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)
create_order_load_maps(ms, order - 1);
}
__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)
{
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);
}
}
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);
}
}
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)
{
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) %
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;
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) % 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_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 norders)
{
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) * norders);
ms->order_load_maps = order_load_maps;
ms->norder_load_maps = norders;
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;
if(cur_obj->section_maps[m].no_load_order == TRUE){
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;
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;
if(cur_obj->section_maps[m].no_load_order == TRUE)
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;
l++;
}
}
}
#ifdef DEBUG
if(debug & (1 << 19)){
for(i = 0; i < norders; i++){
if(order_load_maps[i].archive_name != NULL)
print("%s:", order_load_maps[i].archive_name);
print("%s:%s\n", order_load_maps[i].object_name,
order_load_maps[i].symbol_name);
}
}
#endif DEBUG
qsort(order_load_maps,
norders,
sizeof(struct order_load_map),
(int (*)(const void *, const void *))qsort_order_load_map_orders);
}
__private_extern__
void
layout_relocs_for_dyld(
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++){
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)
fatal("internal error: layout_relocs_for_dyld() "
"called with external relocation entries for "
"merged section (%.16s,%.16s) for 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, **hash_pointer;
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)
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){
hash_pointer = lookup_symbol(strings +
nlists[r_symbolnum].n_un.n_strx);
if(hash_pointer == NULL){
fatal("internal error, in count_relocs() failed to "
"lookup coalesced symbol %s", strings +
nlists[r_symbolnum].n_un.n_strx);
}
merged_symbol = *hash_pointer;
}
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)
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);
else if(arch_flag.cputype == CPU_TYPE_I386)
generic_reloc(fake_contents, fake_relocs, &fake_map,
TRUE);
else if(arch_flag.cputype == CPU_TYPE_POWERPC)
ppc_reloc(fake_contents, fake_relocs, &fake_map);
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 RLD
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_HPPA && r_type == HPPA_RELOC_JBSR){
i += pair;
continue;
}
if(filetype == MH_DYLIB){
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 !defined(RLD)
__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 DEBUG
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 DEBUG
}
content = &(ms->next);
}
p = &(msg->next);
}
}
#endif !defined(RLD)
__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 !defined(RLD)
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)
swap_relocation_info(relocs, map->s->nreloc, host_byte_sex);
if(arch_flag.cputype == CPU_TYPE_MC680x0)
generic_reloc(contents, relocs, map, FALSE);
else if(arch_flag.cputype == CPU_TYPE_I386)
generic_reloc(contents, relocs, map, TRUE);
else if(arch_flag.cputype == CPU_TYPE_POWERPC)
ppc_reloc(contents, relocs, map);
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 RLD
else
fatal("internal error: output_section() called with unknown "
"cputype (%d) set", arch_flag.cputype);
#ifndef RLD
if(errors != 0)
return;
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));
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 !defined(RLD)
}
#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);
}
static
void
scatter_copy(
struct section_map *map,
char *contents)
{
unsigned long i, 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;
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){
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;
}
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 == NULL)
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;
}
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(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){
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;
}
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 == NULL)
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;
}
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(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 ||
(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){
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){
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++){
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);
}
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);
}
}
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)
((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_HPPA && r_type == HPPA_RELOC_JBSR){
i += pair;
continue;
}
if(filetype == MH_DYLIB){
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->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)){
output_flush(ms->s.offset, ms->s.size);
}
content = &(ms->next);
}
p = &(msg->next);
}
}
#endif !defined(RLD)
#ifdef RLD
__private_extern__
void
reset_merged_sections(void)
{
struct merged_segment *msg;
struct merged_section *ms, *prev_ms;
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;
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;
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 RLD
#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 %lu\n", msg->sg.cmd);
print("\tcmdsize %lu\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 %lu\n", msg->sg.fileoff);
print("\tfilesize %lu\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 %lu\n", msg->sg.nsects);
print("\tflags %lu\n", msg->sg.flags);
#ifdef RLD
print("\tset_num %lu\n", msg->set_num);
#endif RLD
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 %lu\n", ms->s.size);
print("\t\toffset %lu\n", ms->s.offset);
print("\t\talign %lu\n", ms->s.align);
print("\t\tnreloc %lu\n", ms->s.nreloc);
print("\t\treloff %lu\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 RLD
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 %lu\n", ms->s.size);
print("\t\toffset %lu\n", ms->s.offset);
print("\t\talign %lu\n", ms->s.align);
print("\t\tnreloc %lu\n", ms->s.nreloc);
print("\t\treloff %lu\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 RLD
}
}
}
__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 DEBUG