#ifdef SHLIB
#include "shlib.h"
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <ctype.h>
#include <mach/mach.h>
#else
#include <mach/kern_return.h>
#endif
#include <stdarg.h>
#include <string.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/stab.h>
#include <mach-o/ldsyms.h>
#include <ar.h>
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "stuff/macosx_deployment_target.h"
#ifndef RLD
#include "stuff/symbol_list.h"
#endif
#include "ld.h"
#include "specs.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "pass1.h"
#include "symbols.h"
#include "layout.h"
#include "pass2.h"
#include "sets.h"
#include "hash_string.h"
#include "dylibs.h"
#include "mod_sections.h"
#ifdef RLD
__private_extern__ char *base_name;
#endif
__private_extern__ struct merged_symbol_root *merged_symbol_root = NULL;
__private_extern__ unsigned long nmerged_symbols = 0;
__private_extern__ unsigned long nmerged_private_symbols = 0;
__private_extern__ unsigned long nmerged_symbols_referenced_only_from_dylibs =0;
__private_extern__ unsigned long nstripped_merged_symbols = 0;
static unsigned long nstripped_merged_private_symbols = 0;
__private_extern__ struct string_block *merged_string_blocks = NULL;
__private_extern__ unsigned long merged_string_size = 0;
static struct merged_symbol **undefsyms_order = NULL;
static struct merged_symbol **extdefsyms_order = NULL;
static int undef_order = 0;
#ifndef SA_RLD
static int qsort_by_module(
const struct merged_symbol **ms1,
const struct merged_symbol **ms2);
static int qsort_by_name(
const struct merged_symbol **ms1,
const struct merged_symbol **ms2);
static int qsort_by_undef_order(
const struct merged_symbol **ms1,
const struct merged_symbol **ms2);
#endif
__private_extern__ unsigned long nlocal_symbols = 0;
__private_extern__ unsigned long local_string_size = 0;
__private_extern__ struct sect_object_symbols sect_object_symbols = { FALSE };
__private_extern__ struct undefined_list undefined_list = {
NULL, &undefined_list, &undefined_list
};
static struct undefined_list free_list = {
NULL, &free_list, &free_list
};
#define NUNDEF_BLOCKS 680
static struct undefined_block {
struct undefined_list undefineds[NUNDEF_BLOCKS];
struct undefined_block *next;
} *undefined_blocks;
#ifndef RLD
__private_extern__ struct common_load_map common_load_map = { 0 };
static struct nlist undefined_symbol = {
{0},
N_UNDF | N_EXT,
NO_SECT,
0,
0
};
static struct nlist indr_symbol = {
{0},
N_INDR | N_EXT,
NO_SECT,
0,
0
};
static struct nlist pbud_symbol = {
{0},
N_PBUD | N_EXT,
NO_SECT,
REFERENCE_FLAG_UNDEFINED_LAZY,
0
};
static struct nlist pbud_weak_def_symbol = {
{0},
N_PBUD | N_EXT,
NO_SECT,
REFERENCE_FLAG_UNDEFINED_LAZY | N_WEAK_DEF,
0
};
static struct object_file *link_edit_symbols_object = NULL;
static void setup_link_edit_symbols_object(
void);
static enum bool local_NO_DEAD_STRIP_symbols = FALSE;
static void mark_N_NO_DEAD_STRIP_local_symbols_in_section_live(
struct merged_section *ms);
static void removed_dead_local_symbols_in_section(
struct merged_section *ms);
static void remove_dead_N_GSYM_stabs(
void);
static void setup_link_editor_symbol(
char *symbol_name);
static void define_link_editor_dylib_symbol(
unsigned long header_address,
char *symbol_name);
static void exports_list_processing(
char *symbol_name,
struct nlist *symbol);
static char * find_stab_name_end(
char *name);
static char * find_stab_type_end(
char *name_end);
#endif
static enum bool is_type_stab(
unsigned char n_type,
char *symbol_name);
static
#if defined(RLD) && !defined(__DYNAMIC__)
const
#endif
struct section link_edit_common_section = {
SECT_COMMON,
SEG_DATA,
0,
0,
0,
0,
0,
0,
S_ZEROFILL,
0,
0,
};
static
#if defined(RLD) && !defined(__DYNAMIC__)
const
#endif
struct section_map link_edit_section_maps = {
#ifdef RLD
NULL,
#else
&link_edit_common_section,
#endif
NULL,
0,
0,
NULL,
0,
FALSE,
0,
NULL,
0
};
#ifndef RLD
__private_extern__
struct symtab_command link_edit_common_symtab = {
LC_SYMTAB,
sizeof(struct symtab_command),
0,
0,
0,
1
};
#endif
__private_extern__
struct object_file link_edit_common_object = {
"\"link editor\"",
NULL,
0,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
0,
0,
0,
FALSE,
FALSE,
NULL,
NULL,
0,
NULL,
1,
#ifdef RLD
NULL,
NULL,
#else
&link_edit_section_maps,
&link_edit_common_symtab,
#endif
NULL,
NULL,
0,
NULL,
0,
0,
0,
0,
0,
0,
0,
NULL,
NULL
#ifdef RLD
,0,
FALSE
#endif
};
static char **multiple_defs = NULL;
static unsigned long nmultiple_defs = 0;
static unsigned long nindr_symbols = 0;
__private_extern__ struct indr_symbol_pair *indr_symbol_pairs = NULL;
__private_extern__ unsigned long nindr_symbol_pairs = 0;
static enum bool commons_exist = FALSE;
static enum bool noundefs = TRUE;
__private_extern__ enum bool merged_symbols_relocated = FALSE;
static struct merged_symbol *enter_symbol(
struct merged_symbol *hash_pointer,
struct nlist *object_symbol,
char *object_strings,
struct object_file *definition_object);
static void enter_indr_symbol(
struct merged_symbol *merged_symbol,
struct nlist *object_symbol,
char *object_strings,
struct object_file *definition_object);
static char *enter_string(
char *symbol_name,
unsigned long *len_ret);
static void add_to_undefined_list(
struct merged_symbol *merged_symbol);
static void multiply_defined(
struct merged_symbol *merged_symbol,
struct nlist *object_symbol,
char *object_strings);
static void trace_object_symbol(
struct nlist *symbol,
char *strings);
static void trace_symbol(
char *symbol_name,
struct nlist *nlist,
struct object_file *object_file,
char *indr_symbol_name);
#ifndef RLD
static void define_link_editor_symbol(
char *symbol_name,
unsigned char type,
unsigned char sect,
short desc,
unsigned long value);
static void remove_dead_N_GSYM_stabs_for_cur_obj(
struct nlist *object_symbols,
char *object_strings);
#endif
static unsigned long merged_symbol_string_index(
char *symbol_name);
static struct string_block *get_string_block(
char *symbol_name);
static void get_stroff_and_mtime_for_N_OSO(
unsigned long *stroff_for_N_OSO,
unsigned long *mtime);
static
inline
void
check_symbol(
struct nlist *symbol,
char *strings,
unsigned long index)
{
unsigned long section_type, library_ordinal;
if(symbol->n_un.n_strx < 0 ||
(uint32_t)symbol->n_un.n_strx >= cur_obj->symtab->strsize){
error_with_cur_obj("bad string table index (%d) for symbol %lu",
symbol->n_un.n_strx, index);
return;
}
switch(symbol->n_type & N_TYPE){
case N_UNDF:
if((symbol->n_type & N_STAB) == 0 &&
(symbol->n_type & N_EXT) == 0){
error_with_cur_obj("undefined symbol %lu (%s) is not also "
"external symbol (N_EXT)", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
if(symbol->n_type & N_PEXT && symbol->n_value == 0){
error_with_cur_obj("undefined symbol %lu (%s) can't be "
"private external symbol (N_PEXT)", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
if((symbol->n_type & N_STAB) == 0 &&
(((struct mach_header *)(cur_obj->obj_addr))->flags &
MH_TWOLEVEL) == MH_TWOLEVEL){
library_ordinal = GET_LIBRARY_ORDINAL(symbol->n_desc);
if((library_ordinal == EXECUTABLE_ORDINAL &&
((struct mach_header *)(cur_obj->obj_addr))->filetype !=
MH_BUNDLE) ||
(library_ordinal != SELF_LIBRARY_ORDINAL &&
(library_ordinal != DYNAMIC_LOOKUP_ORDINAL ||
cur_obj->nload_dylibs != DYNAMIC_LOOKUP_ORDINAL) &&
library_ordinal-1 >= cur_obj->nload_dylibs) ){
error_with_cur_obj("undefined symbol %lu (%s) has bad "
"library oridinal %lu", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx,
library_ordinal);
return;
}
}
case N_ABS:
if((symbol->n_type & N_STAB) == 0 &&
symbol->n_sect != NO_SECT){
error_with_cur_obj("symbol %lu (%s) must have NO_SECT for "
"its n_sect field given its type", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
break;
case N_PBUD:
if((symbol->n_type & N_STAB) == 0 &&
(symbol->n_type & N_EXT) == 0){
error_with_cur_obj("undefined symbol %lu (%s) is not also "
"external symbol (N_EXT)", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
if((symbol->n_type & N_STAB) == 0 &&
symbol->n_sect != NO_SECT){
error_with_cur_obj("symbol %lu (%s) must have NO_SECT for "
"its n_sect field given its type", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
break;
case N_SECT:
if((symbol->n_type & N_STAB) == 0 &&
symbol->n_sect == NO_SECT){
error_with_cur_obj("symbol %lu (%s) must not have NO_SECT "
"for its n_sect field given its type (N_SECT)",
index, symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
break;
case N_INDR:
if(symbol->n_type & N_EXT){
if(symbol->n_value >= cur_obj->symtab->strsize){
error_with_cur_obj("bad string table index (%u) for "
"indirect name for symbol %lu (%s)",
symbol->n_value, index, symbol->n_un.n_strx == 0 ?
"NULL name" : strings + symbol->n_un.n_strx);
return;
}
}
else if((symbol->n_type & N_STAB) == 0){
error_with_cur_obj("indirect symbol %lu (%s) is not also "
"external symbol (N_EXT)", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
if(symbol->n_type & N_PEXT){
error_with_cur_obj("indirect symbol %lu (%s) can't be "
"private external symbol (N_PEXT)", index,
symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx);
return;
}
break;
default:
if((symbol->n_type & N_STAB) == 0){
error_with_cur_obj("symbol %lu (%s) has unknown n_type field "
"(0x%x)", index, symbol->n_un.n_strx == 0 ?
"NULL name" : strings + symbol->n_un.n_strx,
(unsigned int)(symbol->n_type));
return;
}
break;
}
if((unsigned long)(symbol->n_sect) > cur_obj->nsection_maps){
error_with_cur_obj("symbol %lu (%s)'s n_sect field (%d) is "
"greater than the number of sections in this object (%lu)",
index, symbol->n_un.n_strx == 0 ? "NULL name" : strings +
symbol->n_un.n_strx, symbol->n_sect, cur_obj->nsection_maps);
return;
}
if((symbol->n_type & N_EXT) != 0 &&
(symbol->n_type & N_TYPE) == N_SECT){
section_type = (cur_obj->section_maps[symbol->n_sect - 1].s->flags)
& SECTION_TYPE;
if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_SYMBOL_STUBS){
error_with_cur_obj("external symbol %lu (%s) not allowed in an "
"indirect section", index, symbol->n_un.n_strx == 0 ?
"NULL name" : strings + symbol->n_un.n_strx);
return;
}
}
if((symbol->n_type & N_STAB) == 0 &&
(symbol->n_desc & N_WEAK_DEF) == N_WEAK_DEF){
if((symbol->n_type & N_EXT) == 0 &&
(symbol->n_type & N_PEXT) != N_PEXT){
error_with_cur_obj("non-external symbol %lu (%s) can't be a"
" weak definition", index, symbol->n_un.n_strx == 0 ?
"NULL name" : strings + symbol->n_un.n_strx);
return;
}
if((symbol->n_type & N_TYPE) == N_UNDF ||
(symbol->n_type & N_TYPE) == N_PBUD){
error_with_cur_obj("undefined symbol %lu (%s) can't be a "
"weak definition", index, symbol->n_un.n_strx == 0 ?
"NULL name" : strings + symbol->n_un.n_strx);
return;
}
if((symbol->n_type & N_TYPE) != N_SECT){
error_with_cur_obj("symbol %lu (%s) can't be a weak "
"definition (currently only supported in section of "
"type S_COALESCED)", index, symbol->n_un.n_strx == 0 ?
"NULL name" : strings + symbol->n_un.n_strx);
return;
}
else{
section_type = (cur_obj->section_maps[symbol->n_sect - 1].
s->flags) & SECTION_TYPE;
if(section_type != S_COALESCED){
error_with_cur_obj("symbol %lu (%s) can't be a weak "
"definition (currently only supported in section "
"of type S_COALESCED)", index, symbol->n_un.n_strx
== 0 ? "NULL name" : strings + symbol->n_un.n_strx);
return;
}
}
}
if((symbol->n_type & N_TYPE) == N_SECT &&
((cur_obj->section_maps[symbol->n_sect - 1].s->flags)
& S_ATTR_DEBUG) == S_ATTR_DEBUG){
error_with_cur_obj("malformed object, symbols not allowed in debug "
"sections (symbol %lu (%s) is in debug section (%.16s,%.16s)",
index, symbol->n_un.n_strx == 0 ? "NULL name" :
strings + symbol->n_un.n_strx,
cur_obj->section_maps[symbol->n_sect - 1].s->segname,
cur_obj->section_maps[symbol->n_sect - 1].s->sectname);
return;
}
}
static
inline
void
relocate_symbol(
struct nlist *nlist,
struct object_file *object_file)
{
struct section_map *section_map;
if(nlist->n_sect == NO_SECT)
return;
#ifdef RLD
if(object_file->set_num != cur_set)
return;
#endif
section_map = &(object_file->section_maps[nlist->n_sect - 1]);
#ifndef RLD
nlist->n_sect = section_map->output_section->output_sectnum;
#endif
if(object_file == base_obj)
return;
if(section_map->nfine_relocs == 0)
nlist->n_value += - section_map->s->addr
+ section_map->output_section->s.addr
+ section_map->offset;
else
nlist->n_value = fine_reloc_output_offset(section_map,
nlist->n_value -
section_map->s->addr)
+ section_map->output_section->s.addr;
}
#ifndef RLD
struct include_file {
char *include_file_name;
unsigned long sum;
#ifdef DEBUG
char *object_file_name;
unsigned long index;
#endif
struct include_file *next;
};
#define INCLUDE_HASH_SIZE 1000
static struct include_file *include_file_hash_table[INCLUDE_HASH_SIZE] = { 0 };
static
enum bool
lookup_and_enter_include(
char *include_file_name,
unsigned long sum,
unsigned long index,
enum bool next_eincl)
{
unsigned long hash_index;
struct include_file *include_file, *p, *q;
hash_index = hash_string(include_file_name, NULL) % INCLUDE_HASH_SIZE;
if(include_file_hash_table[hash_index] == NULL){
include_file = allocate(sizeof(struct include_file));
memset(include_file, '\0', sizeof(struct include_file));
include_file_hash_table[hash_index] = include_file;
include_file->include_file_name = include_file_name;
include_file->sum = sum;
#ifdef DEBUG
include_file->object_file_name = cur_obj->file_name;
include_file->index = index;
#endif
include_file_hash_table[hash_index] = include_file;
return(TRUE);
}
p = include_file_hash_table[hash_index];
for(;;){
if(p->sum == sum &&
strcmp(p->include_file_name, include_file_name) == 0)
#ifdef OPTIMISTIC
if(strcmp(p->include_file_name, include_file_name) == 0 &&
(p->sum == sum || (p->sum != 0 && sum != 0)))
#endif
{
#ifdef DEBUG
if(debug & (1 << 24))
printf("include file = %s in object file = %s has same "
"sum as previous object file = %s\n",
include_file_name, cur_obj->file_name,
p->object_file_name);
#endif
return(FALSE);
}
if(p->next == NULL){
#ifdef DEBUG
q = include_file_hash_table[hash_index];
for(;;){
if(debug & (1 << 23) &&
strcmp(q->include_file_name, include_file_name) == 0 &&
q->sum != sum && sum != 0 && q->sum != 0 &&
next_eincl == FALSE){
if(debug & (1 << 23))
printf("include file = %s in object file = %s at "
"index %lu with different sum than previous "
"object file = %s at index %lu\n",
include_file_name, cur_obj->file_name, index,
q->object_file_name, q->index);
break;
}
if(q->next == NULL)
break;
else
q = q->next;
}
#endif
break;
}
else
p = p->next;
}
include_file = allocate(sizeof(struct include_file));
memset(include_file, '\0', sizeof(struct include_file));
p = include_file_hash_table[hash_index];
include_file_hash_table[hash_index] = include_file;
include_file->include_file_name = include_file_name;
include_file->sum = sum;
#ifdef DEBUG
include_file->object_file_name = cur_obj->file_name;
include_file->index = index;
#endif
include_file->next = p;
return(TRUE);
}
#endif
static size_t
count_dwarf_symbols(const struct nlist *sym,
size_t i, const size_t * debug_ptr)
{
size_t cnt;
if ((sym->n_type & (N_TYPE | N_STAB)) != N_SECT
&& ((sym->n_type & (N_TYPE | N_STAB)) != N_UNDF
|| sym->n_value == 0))
return 0;
if ((sym->n_type & (N_TYPE | N_STAB)) == N_SECT
&& (cur_obj->section_maps[sym->n_sect - 1].s->flags &
S_ATTR_STRIP_STATIC_SYMS))
return 0;
if (! debug_ptr || *debug_ptr != i)
return 1;
for (cnt = 0; debug_ptr[cnt + 2] & 0x80000000; cnt++)
;
return cnt + 4;
}
static void
maybe_remove_dwarf_symbol (struct merged_symbol *merged_symbol)
{
struct object_file * mo = merged_symbol->definition_object;
struct object_file * cur_o = cur_obj;
size_t * debug_ptr = mo->dwarf_source_data;
size_t n;
struct nlist * obj_symbols;
char * obj_strings;
size_t i;
if (! merged_symbol->definition_object->dwarf_name)
return;
obj_symbols = (struct nlist *) (mo->obj_addr + mo->symtab->symoff);
obj_strings = mo->obj_addr + mo->symtab->stroff;
i = 0;
while (strcmp (obj_strings + obj_symbols[i].n_un.n_strx,
merged_symbol->nlist.n_un.n_name) != 0)
i++;
if (debug_ptr)
while (*debug_ptr < i)
for (debug_ptr += 2; *debug_ptr & 0x80000000; debug_ptr++)
;
cur_obj = mo;
n = count_dwarf_symbols (obj_symbols + i, i, debug_ptr);
cur_obj = cur_o;
merged_symbol->definition_object->nlocalsym -= n;
nlocal_symbols -= n;
}
__private_extern__
void
merge_symbols(void)
{
unsigned long i, j, object_undefineds, nrefsym, output_strlen;
struct nlist *object_symbols;
char *object_strings;
struct merged_symbol *hash_pointer, *merged_symbol;
enum bool discarded_coalesced_symbol;
enum bool discarded_multiply_defined_symbol;
unsigned short n_desc;
size_t * debug_ptr;
#ifndef RLD
unsigned long nest, sum, k;
enum bool no_exclusion;
char *stab_string, *include_file_name;
struct localsym_block *localsym_block, *temp_localsym_block,
**next_localsym_block, *cur_localsym_block;
#endif
#if defined(DEBUG) || defined(RLD)
merged_symbol = NULL;
#endif
if(cur_obj->symtab == NULL)
return;
object_symbols = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
object_strings = (char *)(cur_obj->obj_addr + cur_obj->symtab->stroff);
if(cur_obj->swapped &&
(((struct mach_header *)cur_obj->obj_addr)->filetype != MH_DYLIB ||
((struct mach_header *)cur_obj->obj_addr)->filetype !=
MH_DYLIB_STUB))
swap_nlist(object_symbols, cur_obj->symtab->nsyms, host_byte_sex);
if(cur_obj->symtab->strsize > 0 &&
object_strings[cur_obj->symtab->strsize - 1] != '\0'){
error_with_cur_obj("string table does not end with a '\\0'");
return;
}
object_undefineds = 0;
for(i = 0; i < cur_obj->symtab->nsyms; i++){
check_symbol(&(object_symbols[i]), object_strings, i);
if(errors)
return;
if((object_symbols[i].n_type & N_EXT) == N_EXT &&
(object_symbols[i].n_type & N_TYPE) == N_UNDF)
object_undefineds++;
#ifndef RLD
if((object_symbols[i].n_type & N_EXT) == N_EXT &&
object_symbols[i].n_type != (N_EXT | N_UNDF))
exports_list_processing(object_strings +
object_symbols[i].n_un.n_strx,
object_symbols + i);
#endif
if((object_symbols[i].n_type & N_EXT) &&
(object_symbols[i].n_type & N_PEXT) &&
(object_symbols[i].n_type & N_TYPE) != N_UNDF){
cur_obj->nprivatesym++;
nmerged_private_symbols++;
}
}
if(cur_obj != base_obj){
cur_obj->nundefineds = object_undefineds;
if(cur_obj->nundefineds != 0)
cur_obj->undefined_maps = allocate(object_undefineds *
sizeof(struct undefined_map));
}
#ifndef RLD
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
for(i = 0; i < cur_obj->symtab->nsyms; i++){
if((object_symbols[i].n_type & N_EXT) == N_EXT &&
(object_symbols[i].n_type & N_PEXT) != N_PEXT &&
(object_symbols[i].n_type & N_TYPE) != N_UNDF)
cur_obj->nextdefsym++;
}
cur_obj->nrefsym = cur_obj->nundefineds + cur_obj->nextdefsym +
cur_obj->nprivatesym;
cur_obj->irefsym =
output_dysymtab_info.dysymtab_command.nextrefsyms;
output_dysymtab_info.dysymtab_command.nextrefsyms +=
cur_obj->nrefsym;
if(cur_obj->nrefsym != 0)
cur_obj->reference_maps = allocate(cur_obj->nrefsym *
sizeof(struct reference_map));
}
#endif
if(sect_object_symbols.specified &&
strip_level != STRIP_ALL &&
strip_level != STRIP_NONGLOBALS &&
(cur_obj != base_obj || strip_base_symbols == FALSE)){
if(sect_object_symbols.ms == NULL)
sect_object_symbols.ms = lookup_merged_section(
sect_object_symbols.segname,
sect_object_symbols.sectname);
if(sect_object_symbols.ms != NULL){
if((sect_object_symbols.ms->s.flags & SECTION_TYPE) ==
S_CSTRING_LITERALS ||
(sect_object_symbols.ms->s.flags & SECTION_TYPE) ==
S_4BYTE_LITERALS ||
(sect_object_symbols.ms->s.flags & SECTION_TYPE) ==
S_8BYTE_LITERALS ||
(sect_object_symbols.ms->s.flags & SECTION_TYPE) ==
S_LITERAL_POINTERS){
warning("section (%s,%s) is a literal section "
"and can't be used with -sectobjectsymbols",
sect_object_symbols.segname,
sect_object_symbols.sectname);
sect_object_symbols.specified = FALSE;
sect_object_symbols.ms = NULL;
}
else if((sect_object_symbols.ms->s.flags & S_ATTR_DEBUG) ==
S_ATTR_DEBUG){
warning("section (%s,%s) is a debug section "
"and can't be used with -sectobjectsymbols",
sect_object_symbols.segname,
sect_object_symbols.sectname);
sect_object_symbols.specified = FALSE;
sect_object_symbols.ms = NULL;
}
else{
for(i = 0; i < cur_obj->nsection_maps; i++){
if(sect_object_symbols.ms ==
cur_obj->section_maps[i].output_section){
cur_obj->nlocalsym++;
nlocal_symbols++;
if(cur_obj->ar_hdr == NULL)
local_string_size +=
strlen(cur_obj->file_name) + 1;
else
local_string_size += cur_obj->ar_name_size + 1;
break;
}
}
}
}
}
if(cur_obj->dwarf_name){
nlocal_symbols += 3;
cur_obj->nlocalsym += 3;
local_string_size += 1 + strlen (cur_obj->dwarf_name);
if (cur_obj->dwarf_comp_dir) {
local_string_size += 2 + strlen (cur_obj->dwarf_comp_dir);
nlocal_symbols++;
cur_obj->nlocalsym++;
}
if(cur_obj->resolved_path == NULL)
set_obj_resolved_path(cur_obj);
local_string_size += 1 + cur_obj->resolved_path_len;
for (i = 0; i < cur_obj->dwarf_num_paths; i++)
if (cur_obj->dwarf_paths[i])
local_string_size += 1 + strlen (cur_obj->dwarf_paths[i]);
}
nrefsym = 0;
object_undefineds = 0;
debug_ptr = cur_obj->dwarf_source_data;
for(i = 0; i < cur_obj->symtab->nsyms; i++){
discarded_coalesced_symbol = FALSE;
discarded_multiply_defined_symbol = FALSE;
if (debug_ptr && *debug_ptr < i) {
for (debug_ptr += 2; *debug_ptr & 0x80000000; debug_ptr++) ;
}
if(object_symbols[i].n_type & N_EXT){
if(ntrace_syms != 0){
for(j = 0; j < ntrace_syms; j++){
if(strcmp(trace_syms[j], object_strings +
object_symbols[i].n_un.n_strx) == 0){
trace_object_symbol(&(object_symbols[i]),
object_strings);
break;
}
}
}
hash_pointer = lookup_symbol(object_strings +
object_symbols[i].n_un.n_strx);
if(hash_pointer->name_len == 0){
if(cur_obj != base_obj ||
(object_symbols[i].n_type != (N_EXT | N_UNDF) &&
object_symbols[i].n_type != (N_EXT | N_INDR) ) ){
merged_symbol = enter_symbol(hash_pointer,
&(object_symbols[i]),
object_strings, cur_obj);
merged_symbol->referenced_in_non_dylib = TRUE;
if(merged_symbol->non_dylib_referenced_obj == NULL)
merged_symbol->non_dylib_referenced_obj = cur_obj;
}
}
else{
merged_symbol = hash_pointer;
if(merged_symbol->referenced_in_non_dylib == FALSE){
merged_symbol->nlist.n_un.n_name =
enter_string(object_strings +
object_symbols[i].n_un.n_strx, NULL);
merged_symbol->referenced_in_non_dylib = TRUE;
if(merged_symbol->non_dylib_referenced_obj == NULL)
merged_symbol->non_dylib_referenced_obj = cur_obj;
}
if(object_symbols[i].n_type == (N_EXT | N_UNDF) &&
object_symbols[i].n_value == 0){
if(((merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
merged_symbol->nlist.n_value == 0) ||
merged_symbol->nlist.n_type == (N_EXT | N_PBUD)) &&
(merged_symbol->nlist.n_desc & REFERENCE_TYPE) ==
REFERENCE_FLAG_UNDEFINED_LAZY &&
(object_symbols[i].n_desc & REFERENCE_TYPE) !=
REFERENCE_FLAG_UNDEFINED_LAZY)
merged_symbol->nlist.n_desc =
(merged_symbol->nlist.n_desc & ~REFERENCE_TYPE) |
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
merged_symbol->nlist.n_desc |=
(object_symbols[i].n_desc & REFERENCED_DYNAMICALLY);
if((merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
merged_symbol->nlist.n_value == 0) ||
merged_symbol->nlist.n_type == (N_EXT | N_PBUD)){
if(merged_symbol->seen_undef == FALSE){
merged_symbol->nlist.n_desc =
(merged_symbol->nlist.n_desc & ~N_WEAK_REF) |
(object_symbols[i].n_desc & N_WEAK_REF);
}
else
if(((merged_symbol->nlist.n_desc & N_WEAK_REF) ==
N_WEAK_REF &&
(object_symbols[i].n_desc & N_WEAK_REF) !=
N_WEAK_REF) ||
((merged_symbol->nlist.n_desc & N_WEAK_REF) !=
N_WEAK_REF &&
(object_symbols[i].n_desc & N_WEAK_REF) ==
N_WEAK_REF)){
if(weak_reference_mismatches ==
WEAK_REFS_MISMATCH_ERROR)
merged_symbol->weak_reference_mismatch =
TRUE;
else if(weak_reference_mismatches ==
WEAK_REFS_MISMATCH_WEAK)
merged_symbol->nlist.n_desc |= N_WEAK_REF;
else if(weak_reference_mismatches ==
WEAK_REFS_MISMATCH_NON_WEAK)
merged_symbol->nlist.n_desc &=
~(N_WEAK_REF);
}
merged_symbol->seen_undef = TRUE;
}
}
else if((object_symbols[i].n_type & N_EXT) == N_EXT &&
(object_symbols[i].n_type & N_TYPE) == N_UNDF &&
object_symbols[i].n_value != 0){
if((merged_symbol->nlist.n_type & N_EXT) == N_EXT &&
(merged_symbol->nlist.n_type & N_TYPE) == N_UNDF){
if(merged_symbol->nlist.n_value != 0){
if((merged_symbol->nlist.n_type & N_PEXT) !=
(object_symbols[i].n_type & N_PEXT)){
warning("common symbol: %s both as an "
"external symbol and a private "
"external symbol", merged_symbol->
nlist.n_un.n_name);
trace_merged_symbol(merged_symbol);
trace_object_symbol(&(object_symbols[i]),
object_strings);
}
if(object_symbols[i].n_value >
merged_symbol->nlist.n_value){
merged_symbol->nlist.n_value =
object_symbols[i].n_value;
merged_symbol->definition_object = cur_obj;
merged_symbol->nlist.n_type =
(merged_symbol->nlist.n_type & ~N_PEXT) |
(object_symbols[i].n_type & N_PEXT);
}
}
else{
merged_symbol->nlist.n_value =
object_symbols[i].n_value;
merged_symbol->definition_object = cur_obj;
}
}
}
else if((merged_symbol->nlist.n_type & N_TYPE) == N_UNDF){
merged_symbol->nlist.n_type = object_symbols[i].n_type;
merged_symbol->nlist.n_sect = object_symbols[i].n_sect;
n_desc = 0;
n_desc |= (merged_symbol->nlist.n_desc &
REFERENCED_DYNAMICALLY);
n_desc |= (object_symbols[i].n_desc & N_ARM_THUMB_DEF);
if((object_symbols[i].n_desc & N_WEAK_DEF) ==
N_WEAK_DEF)
n_desc |= (merged_symbol->nlist.n_desc &
N_WEAK_REF);
merged_symbol->nlist.n_desc =
object_symbols[i].n_desc | n_desc;
if(merged_symbol->nlist.n_type == (N_EXT | N_INDR))
enter_indr_symbol(merged_symbol,
&(object_symbols[i]),
object_strings, cur_obj);
else
merged_symbol->nlist.n_value =
object_symbols[i].n_value;
merged_symbol->definition_object = cur_obj;
}
else if((object_symbols[i].n_desc & N_WEAK_DEF) ==
N_WEAK_DEF &&
(merged_symbol->defined_in_dylib == FALSE ||
! merged_symbol->weak_def_in_dylib)){
discarded_coalesced_symbol = TRUE;
if((object_symbols[i].n_type & N_EXT) &&
(object_symbols[i].n_type & N_PEXT)){
cur_obj->nprivatesym--;
nmerged_private_symbols--;
}
else{
cur_obj->nextdefsym--;
}
}
else if((merged_symbol->nlist.n_desc & N_WEAK_DEF) ==
N_WEAK_DEF ||
(merged_symbol->defined_in_dylib == TRUE &&
merged_symbol->weak_def_in_dylib)){
if(merged_symbol->defined_in_dylib == FALSE){
if((merged_symbol->nlist.n_type & N_EXT) &&
(merged_symbol->nlist.n_type & N_PEXT)){
merged_symbol->definition_object->nprivatesym--;
nmerged_private_symbols--;
}
else{
merged_symbol->definition_object->nextdefsym--;
}
maybe_remove_dwarf_symbol (merged_symbol);
}
#ifndef RLD
if(filetype == MH_DYLIB &&
multi_module_dylib == TRUE &&
merged_symbol->defined_in_dylib == FALSE){
for(j = 0;
j < merged_symbol->definition_object->nrefsym;
j++){
if(merged_symbol->definition_object->
reference_maps[j].merged_symbol ==
merged_symbol){
if(object_symbols[i].n_type & N_PEXT)
merged_symbol->definition_object->
reference_maps[j].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
else
merged_symbol->definition_object->
reference_maps[j].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
break;
}
}
}
#endif
merged_symbol->defined_in_dylib = FALSE;
merged_symbol->coalesced_defined_in_dylib = FALSE;
merged_symbol->weak_def_in_dylib = FALSE;
merged_symbol->nlist.n_type = object_symbols[i].n_type;
merged_symbol->nlist.n_sect = object_symbols[i].n_sect;
if(merged_symbol->nlist.n_desc &
REFERENCED_DYNAMICALLY)
merged_symbol->nlist.n_desc =
object_symbols[i].n_desc |
REFERENCED_DYNAMICALLY
;
else
merged_symbol->nlist.n_desc =
object_symbols[i].n_desc
;
if(merged_symbol->nlist.n_type == (N_EXT | N_INDR))
enter_indr_symbol(merged_symbol,
&(object_symbols[i]),
object_strings, cur_obj);
else
merged_symbol->nlist.n_value =
object_symbols[i].n_value;
merged_symbol->definition_object = cur_obj;
}
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) ||
(merged_symbol->defined_in_dylib == TRUE &&
merged_symbol->coalesced_defined_in_dylib) )
&&
(object_symbols[i].n_type & N_TYPE) == N_SECT &&
((cur_obj->section_maps[object_symbols[i].n_sect - 1].
s->flags) & SECTION_TYPE) == S_COALESCED){
discarded_coalesced_symbol = TRUE;
if((object_symbols[i].n_type & N_EXT) &&
(object_symbols[i].n_type & N_PEXT)){
cur_obj->nprivatesym--;
nmerged_private_symbols--;
}
else{
cur_obj->nextdefsym--;
}
#ifdef COALESCE_DEBUG
printf("symbol: %s is coalesced\n", merged_symbol->nlist.n_un.n_name);
#endif
}
#ifdef KLD
else if((merged_symbol->nlist.n_type & N_TYPE) == N_ABS &&
(object_symbols[i].n_type & N_TYPE) == N_ABS &&
merged_symbol->nlist.n_value ==
object_symbols[i].n_value){
if((object_symbols[i].n_type & N_EXT) &&
(object_symbols[i].n_type & N_PEXT)){
cur_obj->nprivatesym--;
nmerged_private_symbols--;
}
else{
cur_obj->nextdefsym--;
}
}
#endif
else{
discarded_multiply_defined_symbol = TRUE;
multiply_defined(merged_symbol, &(object_symbols[i]),
object_strings);
if(allow_multiply_defined_symbols == TRUE){
if((object_symbols[i].n_type & N_EXT) &&
(object_symbols[i].n_type & N_PEXT)){
cur_obj->nprivatesym--;
nmerged_private_symbols--;
}
}
}
}
if((object_symbols[i].n_type & N_EXT) == N_EXT &&
(object_symbols[i].n_type & N_TYPE) == N_UNDF &&
cur_obj != base_obj){
cur_obj->undefined_maps[object_undefineds].index = i;
cur_obj->undefined_maps[object_undefineds].merged_symbol =
merged_symbol;
object_undefineds++;
}
#ifndef RLD
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
cur_obj->reference_maps[nrefsym].merged_symbol =
merged_symbol;
if(discarded_coalesced_symbol == TRUE){
if(merged_symbol->nlist.n_type & N_PEXT)
cur_obj->reference_maps[nrefsym].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
else
cur_obj->reference_maps[nrefsym].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
}
else if(object_symbols[i].n_type == (N_EXT | N_UNDF))
cur_obj->reference_maps[nrefsym].flags =
object_symbols[i].n_desc & REFERENCE_TYPE;
else if(object_symbols[i].n_type & N_PEXT)
cur_obj->reference_maps[nrefsym].flags =
REFERENCE_FLAG_PRIVATE_DEFINED;
else
cur_obj->reference_maps[nrefsym].flags =
REFERENCE_FLAG_DEFINED;
nrefsym++;
}
#endif
}
else if(cur_obj != base_obj || strip_base_symbols == FALSE){
#ifndef RLD
if(dead_strip &&
(object_symbols[i].n_type & N_STAB) == 0 &&
(object_symbols[i].n_type & N_TYPE) == N_SECT &&
object_symbols[i].n_desc & N_NO_DEAD_STRIP)
local_NO_DEAD_STRIP_symbols = TRUE;
#endif
if(strip_level != STRIP_DUP_INCLS &&
is_output_local_symbol(object_symbols[i].n_type,
object_symbols[i].n_sect, object_symbols[i].n_desc,
cur_obj,
object_symbols[i].n_un.n_strx == 0 ? "" :
object_strings + object_symbols[i].n_un.n_strx,
&output_strlen)){
cur_obj->nlocalsym++;
nlocal_symbols++;
local_string_size += object_symbols[i].n_un.n_strx == 0 ? 0:
output_strlen + 1;
}
}
if (cur_obj->dwarf_name && ! discarded_coalesced_symbol &&
! discarded_multiply_defined_symbol){
size_t n = count_dwarf_symbols (object_symbols + i, i,
debug_ptr);
cur_obj->nlocalsym += n;
nlocal_symbols += n;
}
}
#ifndef RLD
if(strip_level == STRIP_DUP_INCLS){
localsym_block = cur_obj->localsym_blocks;
next_localsym_block = &(cur_obj->localsym_blocks);
for(i = 0; i < cur_obj->symtab->nsyms; i++){
if(localsym_block != NULL && localsym_block->index == i){
i += localsym_block->count - 1;
next_localsym_block = &(localsym_block->next);
localsym_block = localsym_block->next;
continue;
}
if(object_symbols[i].n_type & N_EXT)
continue;
if((object_symbols[i].n_type & N_STAB) == 0 ||
object_symbols[i].n_type != N_BINCL){
cur_obj->nlocalsym++;
nlocal_symbols++;
(void)is_output_local_symbol(object_symbols[i].n_type,
object_symbols[i].n_sect, object_symbols[i].n_desc,
cur_obj,
object_symbols[i].n_un.n_strx == 0 ? "" :
object_strings + object_symbols[i].n_un.n_strx,
&output_strlen);
local_string_size +=
object_symbols[i].n_un.n_strx == 0 ? 0:
output_strlen + 1;
continue;
}
no_exclusion = FALSE;
nest = 0;
sum = 0;
localsym_block = allocate(sizeof(struct localsym_block));
memset(localsym_block, '\0', sizeof(struct localsym_block));
localsym_block->index = i;
localsym_block->state = PARSE_SYMBOLS;
localsym_block->count = 1;
localsym_block->input_N_BINCL_n_value =
object_symbols[i].n_value;
if(localsym_block->input_N_BINCL_n_value != 0)
sum = localsym_block->input_N_BINCL_n_value;
localsym_block->next = *next_localsym_block;
*next_localsym_block = localsym_block;
next_localsym_block = &(localsym_block->next);
cur_localsym_block = localsym_block;
for(j = i + 1; j < cur_obj->symtab->nsyms; j++){
if(object_symbols[j].n_type == N_EINCL){
if(nest == 0){
cur_localsym_block->count++;
break;
}
else{
nest--;
if(nest == 0){
cur_localsym_block->index = j + 1;
}
}
}
else if(object_symbols[j].n_type == N_BINCL ||
object_symbols[j].n_type == N_EXCL){
nest++;
if(cur_localsym_block->count != 0){
temp_localsym_block = allocate(
sizeof(struct localsym_block));
memset(temp_localsym_block, '\0',
sizeof(struct localsym_block));
temp_localsym_block->state = PARSE_SYMBOLS;
temp_localsym_block->next =
cur_localsym_block->next;
cur_localsym_block->next = temp_localsym_block;
cur_localsym_block = temp_localsym_block;
}
if(object_symbols[j].n_type == N_EXCL){
nest--;
if(nest == 0){
cur_localsym_block->index = j + 1;
}
}
}
else if(nest == 0){
if((object_symbols[j].n_type & N_STAB) == 0 ||
object_symbols[j].n_sect != NO_SECT){
no_exclusion = TRUE;
}
if((object_symbols[j].n_type & N_STAB) != 0){
cur_localsym_block->count++;
if(localsym_block->input_N_BINCL_n_value == 0 &&
object_symbols[j].n_un.n_strx != 0){
stab_string = object_strings +
object_symbols[j].n_un.n_strx;
for( ; *stab_string != '\0'; stab_string++){
sum += *stab_string;
if(*stab_string == '('){
stab_string++;
while(isdigit((unsigned char)
*stab_string))
stab_string++;
stab_string--;
}
else if(*stab_string == '.' &&
stab_string[1] != '\0' &&
stab_string[1] == '_'){
stab_string++;
sum += *stab_string;
stab_string++;
while(isdigit((unsigned char)
*stab_string))
stab_string++;
stab_string--;
}
}
}
}
}
}
if(j == cur_obj->symtab->nsyms || no_exclusion == TRUE){
temp_localsym_block = localsym_block;
while(temp_localsym_block != NULL){
cur_obj->nlocalsym += temp_localsym_block->count;
nlocal_symbols += temp_localsym_block->count;
for(k = temp_localsym_block->index;
k < temp_localsym_block->index +
temp_localsym_block->count;
k++){
(void)is_output_local_symbol(
object_symbols[k].n_type,
object_symbols[k].n_sect,
object_symbols[k].n_desc,
cur_obj,
object_symbols[k].n_un.n_strx == 0 ? "" :
object_strings + object_symbols[k].n_un.n_strx,
&output_strlen);
local_string_size +=
object_symbols[k].n_un.n_strx == 0 ? 0:
output_strlen + 1;
}
if(temp_localsym_block == cur_localsym_block)
break;
else
temp_localsym_block = temp_localsym_block->next;
}
i = i + localsym_block->count
- 1;
localsym_block = localsym_block->next;
}
else{
include_file_name = object_strings +
object_symbols[i].n_un.n_strx;
if(lookup_and_enter_include(include_file_name, sum, i,
object_symbols[i+1].n_type == N_EINCL)){
temp_localsym_block = localsym_block;
while(temp_localsym_block != NULL){
cur_obj->nlocalsym += temp_localsym_block->count;
nlocal_symbols += temp_localsym_block->count;
for(k = temp_localsym_block->index;
k < temp_localsym_block->index +
temp_localsym_block->count;
k++){
(void)is_output_local_symbol(
object_symbols[k].n_type,
object_symbols[k].n_sect,
object_symbols[k].n_desc,
cur_obj,
object_symbols[k].n_un.n_strx == 0 ? "" :
object_strings +
object_symbols[k].n_un.n_strx,
&output_strlen);
local_string_size +=
object_symbols[k].n_un.n_strx == 0 ? 0:
output_strlen + 1;
}
if(temp_localsym_block == cur_localsym_block)
break;
else
temp_localsym_block = temp_localsym_block->next;
}
localsym_block->state = BEGIN_INCLUDE;
localsym_block->sum = sum;
i = i + localsym_block->count
- 1;
localsym_block->count = 1;
localsym_block = localsym_block->next;
}
else{
localsym_block->state = EXCLUDED_INCLUDE;
localsym_block->sum = sum;
if(localsym_block != cur_localsym_block){
temp_localsym_block = localsym_block->next;
while(temp_localsym_block != NULL){
temp_localsym_block->state = DISCARD_SYMBOLS;
if(temp_localsym_block == cur_localsym_block)
break;
else
temp_localsym_block =
temp_localsym_block->next;
}
}
cur_obj->nlocalsym += 1;
nlocal_symbols += 1;
i = i + localsym_block->count - 1;
localsym_block = localsym_block->next;
}
}
}
localsym_block = cur_obj->localsym_blocks;
next_localsym_block = &(cur_obj->localsym_blocks);
while(localsym_block != NULL){
if(localsym_block->state == PARSE_SYMBOLS){
temp_localsym_block = localsym_block;
localsym_block = localsym_block->next;
*next_localsym_block = localsym_block;
free(temp_localsym_block);
}
else{
next_localsym_block = &(localsym_block->next);
localsym_block = localsym_block->next;
}
}
}
#endif
}
#ifndef RLD
static
void
exports_list_processing(
char *symbol_name,
struct nlist *symbol)
{
struct symbol_list *sp;
if(save_symbols != NULL){
sp = bsearch(symbol_name, save_symbols, nsave_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
sp->seen = TRUE;
}
else{
if(symbol->n_desc & REFERENCED_DYNAMICALLY){
warning("symbol: %s referenced dynamically and must be "
"exported", symbol_name);
}
else{
symbol->n_type |= N_PEXT;
}
}
}
if(remove_symbols != NULL){
sp = bsearch(symbol_name, remove_symbols, nremove_symbols,
sizeof(struct symbol_list),
(int (*)(const void *, const void *))
symbol_list_bsearch);
if(sp != NULL){
sp->seen = TRUE;
if(symbol->n_desc & REFERENCED_DYNAMICALLY){
warning("symbol: %s referenced dynamically and must be "
"exported", symbol_name);
}
else{
symbol->n_type |= N_PEXT;
}
}
}
}
__private_extern__
struct merged_symbol *
command_line_symbol(
char *symbol_name)
{
unsigned long i;
struct merged_symbol *hash_pointer, *merged_symbol;
struct object_file *command_line_object;
command_line_object = new_object_file();
command_line_object->file_name = "command line";
command_line_object->command_line = TRUE;
if(ntrace_syms != 0){
for(i = 0; i < ntrace_syms; i++){
if(strcmp(trace_syms[i], symbol_name) == 0){
trace_symbol(symbol_name, &(undefined_symbol),
command_line_object, "error in trace_symbol()");
break;
}
}
}
hash_pointer = lookup_symbol(symbol_name);
if(hash_pointer->name_len == 0){
merged_symbol = enter_symbol(hash_pointer, &(undefined_symbol),
symbol_name, command_line_object);
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
command_line_object->reference_maps =
reallocate(command_line_object->reference_maps,
(command_line_object->nrefsym + 1) *
sizeof(struct reference_map));
command_line_object->reference_maps[
command_line_object->nrefsym].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
command_line_object->reference_maps[
command_line_object->nrefsym].merged_symbol =
merged_symbol;
command_line_object->irefsym =
output_dysymtab_info.dysymtab_command.nextrefsyms;
command_line_object->nrefsym += 1;
output_dysymtab_info.dysymtab_command.nextrefsyms += 1;
}
}
else{
merged_symbol = hash_pointer;
if(merged_symbol->referenced_in_non_dylib == FALSE)
merged_symbol->nlist.n_un.n_name = enter_string(symbol_name,
NULL);
}
merged_symbol->referenced_in_non_dylib = TRUE;
if(merged_symbol->non_dylib_referenced_obj == NULL)
merged_symbol->non_dylib_referenced_obj = command_line_object;
return(merged_symbol);
}
__private_extern__
void
command_line_indr_symbol(
char *symbol_name,
char *indr_symbol_name)
{
unsigned long i, j;
enum bool was_traced;
struct merged_symbol *hash_pointer, *merged_symbol, *merged_indr_symbol;
struct object_file *command_line_object;
command_line_object = new_object_file();
command_line_object->file_name = "command line";
command_line_object->command_line = TRUE;
was_traced = FALSE;
if(ntrace_syms != 0){
for(i = 0; i < ntrace_syms; i++){
if(strcmp(trace_syms[i], symbol_name) == 0){
trace_symbol(symbol_name, &(indr_symbol),
command_line_object, indr_symbol_name);
was_traced = TRUE;
break;
}
}
}
hash_pointer = lookup_symbol(symbol_name);
if(hash_pointer->name_len == 0){
merged_symbol = enter_symbol(hash_pointer, &(undefined_symbol),
symbol_name, command_line_object);
merged_symbol->referenced_in_non_dylib = TRUE;
if(merged_symbol->non_dylib_referenced_obj == NULL)
merged_symbol->non_dylib_referenced_obj = command_line_object;
}
else{
merged_symbol = hash_pointer;
if(merged_symbol->referenced_in_non_dylib == FALSE)
merged_symbol->nlist.n_un.n_name = enter_string(symbol_name,
NULL);
merged_symbol->referenced_in_non_dylib = TRUE;
if(merged_symbol->non_dylib_referenced_obj == NULL)
merged_symbol->non_dylib_referenced_obj = command_line_object;
if((merged_symbol->nlist.n_type & N_TYPE) != N_UNDF){
for(i = 0; i < nmultiple_defs; i++){
if(strcmp(multiple_defs[i],
merged_symbol->nlist.n_un.n_name) == 0)
break;
}
for(j = 0; j < ntrace_syms; j++){
if(strcmp(trace_syms[j],
merged_symbol->nlist.n_un.n_name) == 0)
break;
}
if(i == nmultiple_defs){
if(allow_multiply_defined_symbols == TRUE)
warning("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
else
error("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
multiple_defs = reallocate(multiple_defs, (nmultiple_defs +
1) * sizeof(char *));
multiple_defs[nmultiple_defs++] =
merged_symbol->nlist.n_un.n_name;
if(j == ntrace_syms)
trace_merged_symbol(merged_symbol);
}
if(was_traced == FALSE)
trace_symbol(symbol_name, &(indr_symbol),
command_line_object, indr_symbol_name);
return;
}
}
nindr_symbols++;
merged_symbol->nlist.n_type = N_INDR | N_EXT;
merged_symbol->nlist.n_sect = NO_SECT;
merged_symbol->nlist.n_desc = 0;
hash_pointer = lookup_symbol(indr_symbol_name);
if(hash_pointer->name_len == 0){
for(i = 0; i < ntrace_syms; i++){
if(strcmp(trace_syms[i], indr_symbol_name) == 0){
trace_symbol(indr_symbol_name, &(undefined_symbol),
command_line_object, "error in trace_symbol()");
break;
}
}
merged_indr_symbol = enter_symbol(hash_pointer, &(undefined_symbol),
indr_symbol_name, command_line_object);
merged_indr_symbol->referenced_in_non_dylib = TRUE;
if(merged_indr_symbol->non_dylib_referenced_obj == NULL)
merged_indr_symbol->non_dylib_referenced_obj =
command_line_object;
}
else{
merged_indr_symbol = hash_pointer;
if(merged_indr_symbol->referenced_in_non_dylib == FALSE)
merged_indr_symbol->nlist.n_un.n_name =
enter_string(indr_symbol_name, NULL);
merged_indr_symbol->referenced_in_non_dylib = TRUE;
if(merged_indr_symbol->non_dylib_referenced_obj == NULL)
merged_indr_symbol->non_dylib_referenced_obj =
command_line_object;
}
merged_symbol->nlist.n_value = (unsigned long)merged_indr_symbol;
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
command_line_object->nextdefsym = 1;
command_line_object->reference_maps =
reallocate(command_line_object->reference_maps,
(command_line_object->nrefsym + 2) *
sizeof(struct reference_map));
command_line_object->reference_maps[
command_line_object->nrefsym + 0].flags =
REFERENCE_FLAG_DEFINED;
command_line_object->reference_maps[
command_line_object->nrefsym + 0].merged_symbol =
merged_symbol;
command_line_object->reference_maps[
command_line_object->nrefsym + 1].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
command_line_object->reference_maps[
command_line_object->nrefsym + 1].merged_symbol =
merged_indr_symbol;
command_line_object->irefsym =
output_dysymtab_info.dysymtab_command.nextrefsyms;
command_line_object->nrefsym += 2;
output_dysymtab_info.dysymtab_command.nextrefsyms += 2;
}
}
__private_extern__
void
merge_dylib_module_symbols(
struct dynamic_library *dynamic_library)
{
unsigned long i, j, k, l, nundefineds, module_index, library_ordinal;
char *strings, *symbol_name, *name;
struct nlist *symbols, *fake_trace_symbol;
struct dylib_reference *refs;
unsigned long flags;
enum bool was_traced, resolve_flat;
struct merged_symbol *hash_pointer, *merged_symbol;
struct object_file *obj;
struct dylib_table_of_contents *toc;
struct dynamic_library *dep;
strings = cur_obj->obj_addr + cur_obj->symtab->stroff;
symbols = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
refs = (struct dylib_reference *)(cur_obj->obj_addr +
cur_obj->dysymtab->extrefsymoff);
for(i = 0; i < cur_obj->dylib_module->nextdefsym; i++){
j = i + cur_obj->dylib_module->iextdefsym;
symbol_name = strings + symbols[j].n_un.n_strx;
if((symbols[j].n_desc & N_WEAK_DEF) == N_WEAK_DEF)
fake_trace_symbol = &pbud_weak_def_symbol;
else
fake_trace_symbol = &pbud_symbol;
was_traced = FALSE;
if(ntrace_syms != 0){
for(k = 0; k < ntrace_syms; k++){
if(strcmp(trace_syms[k], symbol_name) == 0){
trace_symbol(symbol_name, fake_trace_symbol, cur_obj,
"error in trace_symbol()");
was_traced = TRUE;
break;
}
}
}
hash_pointer = lookup_symbol(symbol_name);
if(hash_pointer->name_len == 0){
merged_symbol = enter_symbol(hash_pointer, &(pbud_symbol),
symbol_name, cur_obj);
}
else{
merged_symbol = hash_pointer;
if((merged_symbol->nlist.n_type != (N_UNDF | N_EXT) ||
merged_symbol->nlist.n_value != 0) &&
(symbols[j].n_desc & N_WEAK_DEF) == N_WEAK_DEF){
continue;
}
if((merged_symbol->nlist.n_desc & N_WEAK_DEF) == N_WEAK_DEF ||
(merged_symbol->defined_in_dylib == TRUE &&
merged_symbol->weak_def_in_dylib)){
if(merged_symbol->defined_in_dylib == FALSE){
if((merged_symbol->nlist.n_type & N_EXT) &&
(merged_symbol->nlist.n_type & N_PEXT)){
merged_symbol->definition_object->nprivatesym--;
nmerged_private_symbols--;
}
else{
merged_symbol->definition_object->nextdefsym--;
}
}
if(filetype == MH_DYLIB &&
multi_module_dylib == TRUE &&
merged_symbol->defined_in_dylib == FALSE){
for(k = 0;
k < merged_symbol->definition_object->nrefsym;
k++){
if(merged_symbol->definition_object->
reference_maps[k].merged_symbol ==
merged_symbol){
if(symbols[k].n_type & N_PEXT)
merged_symbol->definition_object->
reference_maps[k].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
else
merged_symbol->definition_object->
reference_maps[k].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
break;
}
}
}
merged_symbol->coalesced_defined_in_dylib = FALSE;
merged_symbol->weak_def_in_dylib = FALSE;
goto use_symbol_definition_from_this_dylib;
}
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) ||
merged_symbol->coalesced_defined_in_dylib == TRUE) &&
(symbols[j].n_type & N_TYPE) == N_SECT &&
((cur_obj->section_maps[symbols[j].n_sect - 1].
s->flags) & SECTION_TYPE) == S_COALESCED){
continue;
}
if(merged_symbol->nlist.n_type != (N_UNDF | N_EXT)){
if(twolevel_namespace == TRUE &&
dynamic_library->definition_obj->library_ordinal == 0)
continue;
for(k = 0; k < nmultiple_defs; k++){
if(strcmp(multiple_defs[k],
merged_symbol->nlist.n_un.n_name) == 0)
break;
}
for(l = 0; l < ntrace_syms; l++){
if(strcmp(trace_syms[l],
merged_symbol->nlist.n_un.n_name) == 0)
break;
}
if(k == nmultiple_defs){
if(allow_multiply_defined_symbols == TRUE){
warning("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
}
else if((twolevel_namespace == TRUE &&
merged_symbol->defined_in_dylib == FALSE) ||
(force_flat_namespace == FALSE &&
((((struct mach_header *)(cur_obj->obj_addr))->
flags & MH_TWOLEVEL) == MH_TWOLEVEL ||
(merged_symbol->defined_in_dylib == TRUE &&
(((struct mach_header *)(merged_symbol->
definition_object->obj_addr))->flags &
MH_TWOLEVEL) == MH_TWOLEVEL)))){
if(multiply_defined_flag ==
MULTIPLY_DEFINED_WARNING){
warning("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
if(nowarnings == TRUE)
continue;
}
else if(multiply_defined_flag ==
MULTIPLY_DEFINED_ERROR){
error("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
}
else if(multiply_defined_flag ==
MULTIPLY_DEFINED_SUPPRESS)
continue;
}
else{
error("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
}
multiple_defs = reallocate(multiple_defs,
(nmultiple_defs + 1) * sizeof(char *));
multiple_defs[nmultiple_defs++] =
merged_symbol->nlist.n_un.n_name;
if(l == ntrace_syms)
trace_merged_symbol(merged_symbol);
}
if(was_traced == FALSE){
trace_symbol(symbol_name, fake_trace_symbol, cur_obj,
"error in trace_symbol()");
}
continue;
}
}
use_symbol_definition_from_this_dylib:
maybe_remove_dwarf_symbol(merged_symbol);
merged_symbol->nlist.n_type = N_PBUD | N_EXT;
merged_symbol->nlist.n_sect = NO_SECT;
if((symbols[j].n_type & N_TYPE) == N_SECT &&
((cur_obj->section_maps[symbols[j].n_sect - 1].
s->flags) & SECTION_TYPE) == S_COALESCED){
merged_symbol->coalesced_defined_in_dylib = TRUE;
if((symbols[j].n_desc & N_WEAK_DEF) == N_WEAK_DEF)
merged_symbol->weak_def_in_dylib = TRUE;
#ifdef COALESCE_DEBUG
printf("merging in coalesced symbol %s\n", merged_symbol->nlist.n_un.n_name);
#endif
}
if(save_reloc == FALSE &&
twolevel_namespace == TRUE &&
merged_symbol->referenced_in_non_dylib == TRUE &&
dynamic_library->definition_obj->library_ordinal == 0 &&
dynamic_library->indirect_twolevel_ref_flagged == FALSE){
obj = cur_obj;
cur_obj = merged_symbol->definition_object;
error_with_cur_obj("illegal reference to symbol: %s defined in "
"indirectly referenced dynamic library %s", symbol_name,
dynamic_library->dylib_file != NULL ?
dynamic_library->file_name : dynamic_library->dylib_name);
cur_obj = obj;
dynamic_library->indirect_twolevel_ref_flagged = TRUE;
}
merged_symbol->nlist.n_value = symbols[j].n_value;
if(symbols[j].n_desc & N_ARM_THUMB_DEF)
merged_symbol->nlist.n_value |= 1;
merged_symbol->definition_object = cur_obj;
merged_symbol->defined_in_dylib = TRUE;
merged_symbol->definition_library = dynamic_library;
if(dynamic_library->force_weak_dylib &&
merged_symbol->referenced_in_non_dylib == TRUE)
merged_symbol->nlist.n_desc |= N_WEAK_REF;
if((merged_symbol->nlist.n_desc & N_WEAK_REF) == 0 &&
merged_symbol->referenced_in_non_dylib == TRUE)
dynamic_library->some_non_weak_refs = TRUE;
if(merged_symbol->referenced_in_non_dylib == TRUE)
dynamic_library->some_symbols_referenced = TRUE;
if((symbols[j].n_type & N_TYPE) == N_INDR){
merged_symbol->nlist.n_type = N_INDR | N_EXT;
enter_indr_symbol(merged_symbol, symbols + j, strings, cur_obj);
}
if(twolevel_namespace == TRUE){
SET_LIBRARY_ORDINAL(merged_symbol->nlist.n_desc,
dynamic_library->definition_obj->library_ordinal);
if(merged_symbol->itoc == 0){
bsearch_strings = dynamic_library->strings;
bsearch_symbols = dynamic_library->symbols;
toc = bsearch(merged_symbol->nlist.n_un.n_name,
dynamic_library->tocs,
dynamic_library->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
merged_symbol->itoc = toc - dynamic_library->tocs;
}
}
}
if(Yflag && cur_obj->dylib_module->nrefsym != 0){
nundefineds = 0;
for(i = 0; i < cur_obj->dylib_module->nrefsym; i++){
j = i + cur_obj->dylib_module->irefsym;
flags = refs[j].flags;
if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
flags == REFERENCE_FLAG_UNDEFINED_LAZY){
nundefineds++;
}
}
cur_obj->undefined_maps = allocate(nundefineds *
sizeof(struct undefined_map));
cur_obj->nundefineds = nundefineds;
}
nundefineds = 0;
for(i = 0; i < cur_obj->dylib_module->nrefsym; i++){
j = i + cur_obj->dylib_module->irefsym;
flags = refs[j].flags;
if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
flags == REFERENCE_FLAG_UNDEFINED_LAZY){
symbol_name = strings + symbols[refs[j].isym].n_un.n_strx;
if(ntrace_syms != 0){
for(k = 0; k < ntrace_syms; k++){
if(strcmp(trace_syms[k], symbol_name) == 0){
if(force_flat_namespace == TRUE ||
(((struct mach_header *)(cur_obj->obj_addr))->
flags & MH_TWOLEVEL) != MH_TWOLEVEL){
trace_symbol(symbol_name, &(undefined_symbol),
cur_obj, "error in trace_symbol()");
}
else{
print_obj_name(cur_obj);
library_ordinal = GET_LIBRARY_ORDINAL(symbols[
refs[j].isym].n_desc);
if(library_ordinal != 0 &&
library_ordinal != DYNAMIC_LOOKUP_ORDINAL){
dep = dynamic_library->dependent_images[
library_ordinal - 1];
if(dep->umbrella_name != NULL)
name = dep->umbrella_name;
else if(dep->library_name != NULL)
name = dep->library_name;
else
name = dep->dylib_name;
print("reference to undefined %s (from %s)"
"\n", symbol_name, name);
}
else
print("reference to undefined %s\n",
symbol_name);
}
break;
}
}
}
if(force_flat_namespace == TRUE)
resolve_flat = TRUE;
else{
if((((struct mach_header *)(cur_obj->obj_addr))->
flags & MH_TWOLEVEL) == MH_TWOLEVEL){
library_ordinal = GET_LIBRARY_ORDINAL(
symbols[refs[j].isym].n_desc);
if(library_ordinal == DYNAMIC_LOOKUP_ORDINAL)
resolve_flat = TRUE;
else
resolve_flat = FALSE;
}
else{
resolve_flat = TRUE;
}
}
if(resolve_flat == TRUE){
if(twolevel_namespace == TRUE &&
(((struct mach_header *)(cur_obj->obj_addr))->
flags & MH_TWOLEVEL) != MH_TWOLEVEL){
continue;
}
hash_pointer = lookup_symbol(symbol_name);
if(hash_pointer->name_len == 0){
merged_symbol = enter_symbol(hash_pointer,
&(undefined_symbol), symbol_name, cur_obj);
}
else{
merged_symbol = hash_pointer;
}
merged_symbol->nlist.n_desc |= REFERENCED_DYNAMICALLY;
}
else{
library_ordinal = GET_LIBRARY_ORDINAL(
symbols[refs[j].isym].n_desc);
if((library_ordinal != SELF_LIBRARY_ORDINAL) &&
(library_ordinal != DYNAMIC_LOOKUP_ORDINAL)){
dep = dynamic_library->dependent_images[
library_ordinal - 1];
if(dep->definition_obj->library_ordinal == 0)
continue;
}
merged_symbol = allocate(sizeof(struct merged_symbol));
memset(merged_symbol, '\0', sizeof(struct merged_symbol));
merged_symbol->nlist = symbols[refs[j].isym];
merged_symbol->nlist.n_un.n_name = symbol_name;
merged_symbol->definition_object = cur_obj;
merged_symbol->twolevel_reference = TRUE;
merged_symbol->referencing_library = dynamic_library;
add_to_undefined_list(merged_symbol);
}
if(Yflag){
cur_obj->undefined_maps[nundefineds++].merged_symbol =
merged_symbol;
}
}
}
obj = cur_obj;
for(i = 0; i < obj->dylib_module->nrefsym; i++){
j = i + obj->dylib_module->irefsym;
flags = refs[j].flags;
if(flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
for(k = 0; k < obj->dysymtab->nmodtab; k++){
if(refs[j].isym >= dynamic_library->mods[k].ilocalsym &&
refs[j].isym < dynamic_library->mods[k].ilocalsym +
dynamic_library->mods[k].nlocalsym)
break;
}
if(k >= obj->dysymtab->nmodtab){
error_with_cur_obj("isym field (%u) of reference table "
"entry %lu for private reference not in the local "
"symbols for any module", refs[j].isym, j);
return;
}
module_index = k;
if(is_dylib_module_loaded(dynamic_library->mods +
module_index) == FALSE){
cur_obj = new_object_file();
*cur_obj = *(dynamic_library->definition_obj);
cur_obj->dylib_module = dynamic_library->mods +
module_index;
if(dynamic_library->linked_modules != NULL)
dynamic_library->linked_modules[module_index / 8] |=
1 << module_index % 8;
if(whyload){
print_obj_name(cur_obj);
symbol_name = strings +
symbols[refs[j].isym].n_un.n_strx;
print("loaded to resolve private symbol: %s\n",
symbol_name);
}
merge_dylib_module_symbols(dynamic_library);
cur_obj = obj;
}
}
}
}
__private_extern__
void
merge_bundle_loader_symbols(
struct dynamic_library *dynamic_library)
{
unsigned long i, j, k, l;
char *strings, *symbol_name;
struct nlist *symbols, *fake_trace_symbol;
enum bool was_traced;
struct merged_symbol *hash_pointer, *merged_symbol;
strings = cur_obj->obj_addr + cur_obj->symtab->stroff;
symbols = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
for(i = 0; i < cur_obj->dysymtab->nextdefsym; i++){
j = i + cur_obj->dysymtab->iextdefsym;
symbol_name = strings + symbols[j].n_un.n_strx;
if((symbols[j].n_desc & N_WEAK_DEF) == N_WEAK_DEF)
fake_trace_symbol = &pbud_weak_def_symbol;
else
fake_trace_symbol = &pbud_symbol;
was_traced = FALSE;
if(ntrace_syms != 0){
for(k = 0; k < ntrace_syms; k++){
if(strcmp(trace_syms[k], symbol_name) == 0){
trace_symbol(symbol_name, fake_trace_symbol, cur_obj,
"error in trace_symbol()");
was_traced = TRUE;
break;
}
}
}
hash_pointer = lookup_symbol(symbol_name);
if(hash_pointer->name_len == 0){
merged_symbol = enter_symbol(hash_pointer, &(pbud_symbol),
symbol_name, cur_obj);
}
else{
merged_symbol = hash_pointer;
if((merged_symbol->nlist.n_type != (N_UNDF | N_EXT) ||
merged_symbol->nlist.n_value != 0) &&
(symbols[j].n_desc & N_WEAK_DEF) == N_WEAK_DEF){
continue;
}
if(((merged_symbol->nlist.n_desc & N_WEAK_DEF) == N_WEAK_DEF) ||
(merged_symbol->defined_in_dylib == TRUE &&
merged_symbol->weak_def_in_dylib)){
if(merged_symbol->defined_in_dylib == FALSE){
if((merged_symbol->nlist.n_type & N_EXT) &&
(merged_symbol->nlist.n_type & N_PEXT)){
merged_symbol->definition_object->nprivatesym--;
nmerged_private_symbols--;
}
else{
merged_symbol->definition_object->nextdefsym--;
}
}
if(filetype == MH_DYLIB &&
multi_module_dylib == TRUE &&
merged_symbol->defined_in_dylib == FALSE){
for(k = 0;
k < merged_symbol->definition_object->nrefsym;
k++){
if(merged_symbol->definition_object->
reference_maps[k].merged_symbol ==
merged_symbol){
if(symbols[k].n_type & N_PEXT)
merged_symbol->definition_object->
reference_maps[k].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
else
merged_symbol->definition_object->
reference_maps[k].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
break;
}
}
}
merged_symbol->coalesced_defined_in_dylib = FALSE;
merged_symbol->weak_def_in_dylib = FALSE;
goto use_symbol_definition_from_this_bundle_loader;
}
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) ||
merged_symbol->coalesced_defined_in_dylib == TRUE) &&
(symbols[j].n_type & N_TYPE) == N_SECT &&
((cur_obj->section_maps[symbols[j].n_sect - 1].
s->flags) & SECTION_TYPE) == S_COALESCED){
continue;
}
if(merged_symbol->nlist.n_type != (N_UNDF | N_EXT)){
for(k = 0; k < nmultiple_defs; k++){
if(strcmp(multiple_defs[k],
merged_symbol->nlist.n_un.n_name) == 0)
break;
}
for(l = 0; l < ntrace_syms; l++){
if(strcmp(trace_syms[l],
merged_symbol->nlist.n_un.n_name) == 0)
break;
}
if(private_bundle == TRUE)
break;
if(k == nmultiple_defs){
if(allow_multiply_defined_symbols == TRUE){
warning("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
}
else if((twolevel_namespace == TRUE &&
merged_symbol->defined_in_dylib == FALSE) ||
(force_flat_namespace == FALSE &&
((((struct mach_header *)(cur_obj->obj_addr))->
flags & MH_TWOLEVEL) == MH_TWOLEVEL ||
(merged_symbol->defined_in_dylib == TRUE &&
(((struct mach_header *)(merged_symbol->
definition_object->obj_addr))->flags &
MH_TWOLEVEL) == MH_TWOLEVEL)))){
if(multiply_defined_flag ==
MULTIPLY_DEFINED_WARNING)
warning("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
else if(multiply_defined_flag ==
MULTIPLY_DEFINED_ERROR){
error("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
}
else if(multiply_defined_flag ==
MULTIPLY_DEFINED_SUPPRESS)
continue;
}
else{
error("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
}
multiple_defs = reallocate(multiple_defs,
(nmultiple_defs + 1) * sizeof(char *));
multiple_defs[nmultiple_defs++] =
merged_symbol->nlist.n_un.n_name;
if(l == ntrace_syms)
trace_merged_symbol(merged_symbol);
}
if(was_traced == FALSE)
trace_symbol(symbol_name, fake_trace_symbol, cur_obj,
"error in trace_symbol()");
continue;
}
}
use_symbol_definition_from_this_bundle_loader:
maybe_remove_dwarf_symbol(merged_symbol);
merged_symbol->nlist.n_type = N_PBUD | N_EXT;
merged_symbol->nlist.n_sect = NO_SECT;
if((symbols[j].n_type & N_TYPE) == N_SECT &&
((cur_obj->section_maps[symbols[j].n_sect - 1].
s->flags) & SECTION_TYPE) == S_COALESCED){
merged_symbol->coalesced_defined_in_dylib = TRUE;
if((symbols[j].n_desc & N_WEAK_DEF) == N_WEAK_DEF)
merged_symbol->weak_def_in_dylib = TRUE;
#ifdef COALESCE_DEBUG
printf("merging in coalesced symbol %s\n", merged_symbol->nlist.n_un.n_name);
#endif
}
merged_symbol->nlist.n_value = symbols[j].n_value;
merged_symbol->definition_object = cur_obj;
merged_symbol->defined_in_dylib = TRUE;
merged_symbol->definition_library = dynamic_library;
if((symbols[j].n_type & N_TYPE) == N_INDR){
merged_symbol->nlist.n_type = N_INDR | N_EXT;
enter_indr_symbol(merged_symbol, symbols + j, strings, cur_obj);
}
if(twolevel_namespace == TRUE){
SET_LIBRARY_ORDINAL(merged_symbol->nlist.n_desc,
dynamic_library->definition_obj->library_ordinal);
}
}
}
#endif
__private_extern__
enum bool
is_output_local_symbol(
unsigned char n_type,
unsigned char n_sect,
unsigned char n_desc,
struct object_file *obj,
char *symbol_name,
unsigned long *output_strlen)
{
#ifndef RLD
char *end;
#endif
*output_strlen = 0;
switch(strip_level){
case STRIP_NONE:
case STRIP_DUP_INCLS:
if(n_type == N_OSO){
if(n_desc == 1){
if(symbol_name != NULL && *symbol_name == '\0'){
if(obj->resolved_path == NULL)
set_obj_resolved_path(obj);
*output_strlen = cur_obj->resolved_path_len;
}
else{
*output_strlen = strlen(symbol_name);
}
}
else if(n_desc == 0){
*output_strlen = 0;
}
else{
*output_strlen = strlen(symbol_name);
}
}
else{
*output_strlen = strlen(symbol_name);
}
return(TRUE);
case STRIP_ALL:
case STRIP_DYNAMIC_EXECUTABLE:
case STRIP_NONGLOBALS:
return(FALSE);
case STRIP_DEBUG:
if(n_type & N_STAB ||
(*symbol_name == 'L' && (n_type & N_STAB) == 0) ||
(save_reloc == FALSE &&
(n_type & N_TYPE) == N_SECT &&
(obj->section_maps[n_sect - 1].s->flags &
S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS))
return(FALSE);
else{
*output_strlen = strlen(symbol_name);
return(TRUE);
}
case STRIP_MIN_DEBUG:
#ifndef RLD
if(n_type & N_STAB){
switch(n_type){
case N_OSO:
if(n_desc == 1){
if(symbol_name != NULL && *symbol_name == '\0'){
if(obj->resolved_path == NULL)
set_obj_resolved_path(obj);
*output_strlen = cur_obj->resolved_path_len;
}
else{
*output_strlen = strlen(symbol_name);
}
}
else if(n_desc == 0){
if(obj->resolved_path == NULL)
set_obj_resolved_path(obj);
*output_strlen = cur_obj->resolved_path_len;
}
else{
*output_strlen = strlen(symbol_name);
}
return(TRUE);
case N_SO:
case N_SOL:
case N_OPT:
*output_strlen = strlen(symbol_name);
return(TRUE);
case N_LCSYM:
case N_STSYM:
case N_GSYM:
case N_FUN:
end = find_stab_type_end(
find_stab_name_end(symbol_name));
if(end != NULL)
*output_strlen = end - symbol_name;
else
*output_strlen = strlen(symbol_name);
return(TRUE);
default:
return(FALSE);
}
}
else if(*symbol_name == 'L' ||
(save_reloc == FALSE &&
(n_type & N_TYPE) == N_SECT &&
(obj->section_maps[n_sect - 1].s->flags &
S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS))
return(FALSE);
else{
*output_strlen = strlen(symbol_name);
return(TRUE);
}
#endif
case STRIP_L_SYMBOLS:
if(*symbol_name == 'L' && (n_type & N_STAB) == 0)
return(FALSE);
else{
*output_strlen = strlen(symbol_name);
return(TRUE);
}
}
*output_strlen = strlen(symbol_name);
return(TRUE);
}
static
enum bool
is_type_stab(
unsigned char n_type,
char *symbol_name)
#ifdef RLD
{
return(FALSE);
}
#else
{
char *end;
if((n_type & N_STAB) == 0 || n_type != N_LSYM)
return(FALSE);
end = find_stab_name_end(symbol_name);
if(end != NULL && end[1] != '\0' && (end[1] == 'T' || end[1] == 't'))
return(TRUE);
else
return(FALSE);
}
static
char *
find_stab_name_end(
char *name)
{
char *first_colon, *next_colon, *s, *first_lbrac, *first_rbrac;
for(first_colon = strchr(name, ':');
first_colon != NULL &&
first_colon[1] == ':' && first_colon[2] != '\0';
){
next_colon = strchr(&first_colon[2], ':');
if(next_colon != NULL)
first_colon = next_colon;
else
break;
}
if(first_colon == NULL)
return(NULL);
first_lbrac = NULL;
for(s = name; s < first_colon; s++){
if(*s == '['){
first_lbrac = s;
break;
}
}
if(first_lbrac == NULL ||
(first_lbrac == name ||
(first_lbrac[-1] != '-' && first_lbrac[-1] != '+'))){
return first_colon;
}
else{
first_rbrac = strchr(name, ']');
if(first_rbrac == NULL)
return(NULL);
return(strchr(first_rbrac, ':'));
}
}
static
char *
find_stab_type_end(
char *name_end)
{
if(name_end == NULL || name_end[0] != ':')
return(NULL);
if(!isalpha(name_end[1]))
return(NULL);
if(name_end[1] == 'T' && name_end[2] == 't')
return(name_end + 3);
else
return(name_end + 2);
}
#endif
__private_extern__
struct merged_symbol *
lookup_symbol(
char *symbol_name)
{
struct merged_symbol_chunk *p, *q;
struct merged_symbol *sym;
unsigned long hash_index, i, name_len;
hash_index = hash_string(symbol_name, &name_len) %
SYMBOL_LIST_HASH_SIZE;
if(merged_symbol_root == NULL){
merged_symbol_root = allocate(sizeof(struct merged_symbol_root));
memset(merged_symbol_root, 0, sizeof(struct merged_symbol_root));
merged_symbol_root->list =
allocate(sizeof(struct merged_symbol_list));
memset(merged_symbol_root->list, 0,
sizeof(struct merged_symbol_list));
merged_symbol_root->list->used = 0;
merged_symbol_root->list->next = NULL;
return(&merged_symbol_root->chunks[hash_index].symbols[0]);
}
q = NULL;
for(p = &merged_symbol_root->chunks[hash_index]; p != NULL;p = p->next){
for(i = 0; i < SYMBOL_CHUNK_SIZE; i++){
sym = &p->symbols[i];
if(sym->name_len == 0){
return(sym);
}
if(sym->name_len == name_len &&
strcmp(sym->nlist.n_un.n_name, symbol_name) == 0){
return(sym);
}
}
q = p;
}
q->next = allocate(sizeof(struct merged_symbol_chunk));
memset(q->next, 0, sizeof(struct merged_symbol_chunk));
return(&q->next->symbols[0]);
}
#ifndef RLD
__private_extern__
void
hash_instrument(void)
{
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol_chunk *p;
unsigned long n, u, i, j, h, b, c, t;
n = 0;
u = 0;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
u += merged_symbol_list->used;
n++;
}
print("Number of merged_symbol_lists = %lu (containing %d pointers "
"each)\n", n, SYMBOL_LIST_HASH_SIZE);
print("sizeof(struct merged_symbol_list) is %lu (total %lu)\n",
sizeof(struct merged_symbol_list),
n * sizeof(struct merged_symbol_list));
print("Number of used pointers in the lists = %lu (%.2f%%)\n",
u, ((double)u) / ((double)(SYMBOL_LIST_HASH_SIZE * n)) *
100.0);
h = 0;
b = 0;
c = 0;
for(i = 0; i < SYMBOL_LIST_HASH_SIZE; i++){
if(merged_symbol_root->chunks[i].symbols[0].name_len != 0)
h++;
for(p = &merged_symbol_root->chunks[i];
p != NULL;
p = p->next){
if(p != &merged_symbol_root->chunks[i])
c++;
for(j = 0; j < SYMBOL_CHUNK_SIZE; j++){
if(p->symbols[j].name_len != 0)
b++;
}
}
}
print("The SYMBOL_LIST_HASH_SIZE is %d\n", SYMBOL_LIST_HASH_SIZE);
print("sizeof(struct merged_symbol_root) is %lu\n",
sizeof(struct merged_symbol_root));
print("Number of additional chunks: %lu (size of these %lu)\n", c,
c * sizeof(struct merged_symbol_chunk));
print("Number of hash entries used: %lu (%.2f%%) average #buckets "
"%.2f\n", h, ((double)h)/ ((double)SYMBOL_LIST_HASH_SIZE) * 100.0,
((double)b) / ((double)h) );
t = SYMBOL_LIST_HASH_SIZE * SYMBOL_CHUNK_SIZE + c * SYMBOL_CHUNK_SIZE;
print("Number of buckets (merged symbols) used: %lu out of %lu "
"(%.2f%%)\n", b, t, ((double)b)/ ((double)t) * 100.0);
}
#endif
static
void
add_to_symbol_list(
struct merged_symbol *merged_symbol)
{
struct merged_symbol_list *prev, *merged_symbol_list, *new;
prev = NULL;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
if(merged_symbol_list->used != SYMBOL_LIST_HASH_SIZE){
merged_symbol_list->symbols[merged_symbol_list->used] =
merged_symbol;
merged_symbol_list->used += 1;
return;
}
prev = merged_symbol_list;
}
new = allocate(sizeof(struct merged_symbol_list));
prev->next = new;
memset(new, '\0', sizeof(struct merged_symbol_list));
new->symbols[0] = merged_symbol;
new->used = 1;
new->next = NULL;
}
static
struct merged_symbol *
enter_symbol(
struct merged_symbol *hash_pointer,
struct nlist *object_symbol,
char *object_strings,
struct object_file *definition_object)
{
struct merged_symbol *merged_symbol;
if((cur_obj != base_obj || strip_base_symbols == FALSE))
nmerged_symbols++;
merged_symbol = hash_pointer;
memset(merged_symbol, '\0', sizeof(struct merged_symbol));
merged_symbol->nlist = *object_symbol;
#ifdef RLD
if(cur_obj == base_obj && base_name == NULL)
merged_symbol->nlist.n_un.n_name = object_strings +
object_symbol->n_un.n_strx;
else
#endif
merged_symbol->nlist.n_un.n_name = enter_string(object_strings +
object_symbol->n_un.n_strx,
&merged_symbol->name_len);
merged_symbol->definition_object = definition_object;
add_to_symbol_list(merged_symbol);
if(object_symbol->n_type == (N_UNDF | N_EXT) &&
object_symbol->n_value == 0)
add_to_undefined_list(merged_symbol);
merged_symbol->undef_order = undef_order++;
if(object_symbol->n_type == (N_INDR | N_EXT))
enter_indr_symbol(merged_symbol, object_symbol, object_strings,
definition_object);
return(merged_symbol);
}
static
void
enter_indr_symbol(
struct merged_symbol *merged_symbol,
struct nlist *object_symbol,
char *object_strings,
struct object_file *definition_object)
{
struct merged_symbol *hash_pointer, *indr_symbol;
nindr_symbols++;
hash_pointer = lookup_symbol(object_strings + object_symbol->n_value);
if(hash_pointer->name_len != 0){
indr_symbol = hash_pointer;
}
else{
indr_symbol = hash_pointer;
add_to_symbol_list(indr_symbol);
if(cur_obj != base_obj || strip_base_symbols == FALSE)
nmerged_symbols++;
indr_symbol->nlist.n_type = N_UNDF | N_EXT;
indr_symbol->nlist.n_sect = NO_SECT;
if(definition_object != NULL &&
definition_object->dylib_module != NULL)
indr_symbol->nlist.n_desc = REFERENCE_FLAG_UNDEFINED_LAZY;
else
indr_symbol->nlist.n_desc = 0;
indr_symbol->nlist.n_value = 0;
#ifdef RLD
if(cur_obj == base_obj && base_name == NULL)
indr_symbol->nlist.n_un.n_name = object_strings +
object_symbol->n_value;
else
#endif
indr_symbol->nlist.n_un.n_name = enter_string(object_strings +
object_symbol->n_value,
NULL);
indr_symbol->definition_object = definition_object;
add_to_undefined_list(indr_symbol);
}
merged_symbol->nlist.n_value = (unsigned long)indr_symbol;
}
static
char *
enter_string(
char *symbol_name,
unsigned long *len_ret)
{
struct string_block **p, *string_block;
unsigned long len;
char *r;
len = strlen(symbol_name) + 1;
if(len_ret != NULL)
*len_ret = len - 1;
for(p = &(merged_string_blocks); *p; p = &(string_block->next)){
string_block = *p;
if(len > string_block->size - string_block->used)
continue;
#ifdef RLD
if(string_block->set_num != cur_set)
continue;
#endif
if(strip_base_symbols == TRUE &&
((cur_obj == base_obj && string_block->base_strings == FALSE) ||
(cur_obj != base_obj && string_block->base_strings == TRUE) ) )
continue;
if((cur_obj != NULL && cur_obj->dylib_module != NULL &&
string_block->dylib_strings == FALSE) ||
((cur_obj == NULL || cur_obj->dylib_module == NULL) &&
string_block->dylib_strings == TRUE))
continue;
r = strcpy(string_block->strings + string_block->used, symbol_name);
string_block->used += len;
if((strip_base_symbols == FALSE ||
string_block->base_strings == FALSE) &&
string_block->dylib_strings == FALSE)
merged_string_size += len;
return(r);
}
*p = allocate(sizeof(struct string_block));
string_block = *p;
string_block->size = (len > host_pagesize ? len : host_pagesize);
string_block->used = len;
string_block->next = NULL;
string_block->strings = allocate(string_block->size);
string_block->base_strings = cur_obj == base_obj ? TRUE : FALSE;
if(cur_obj != NULL && cur_obj->dylib_module != NULL)
string_block->dylib_strings = TRUE;
else
string_block->dylib_strings = FALSE;
#ifdef RLD
string_block->set_num = cur_set;
#endif
r = strcpy(string_block->strings, symbol_name);
if((strip_base_symbols == FALSE ||
string_block->base_strings == FALSE) &&
string_block->dylib_strings == FALSE)
merged_string_size += len;
return(r);
}
static
void
add_to_undefined_list(
struct merged_symbol *merged_symbol)
{
struct undefined_block **p;
struct undefined_list *new, *undefineds;
unsigned long i;
if(free_list.next == &free_list){
for(p = &(undefined_blocks); *p; p = &((*p)->next))
;
*p = allocate(sizeof(struct undefined_block));
(*p)->next = 0;
undefineds = (*p)->undefineds;
free_list.next = &undefineds[0];
undefineds[0].prev = &free_list;
undefineds[0].next = &undefineds[1];
for(i = 1 ; i < NUNDEF_BLOCKS - 1 ; i++){
undefineds[i].prev = &undefineds[i-1];
undefineds[i].next = &undefineds[i+1];
undefineds[i].merged_symbol = NULL;
}
free_list.prev = &undefineds[i];
undefineds[i].prev = &undefineds[i-1];
undefineds[i].next = &free_list;
}
new = free_list.next;
new->next->prev = &free_list;
free_list.next = new->next;
new->merged_symbol = merged_symbol;
new->prev = undefined_list.prev;
new->next = &undefined_list;
undefined_list.prev->next = new;
undefined_list.prev = new;
}
__private_extern__
void
delete_from_undefined_list(
struct undefined_list *undefined)
{
undefined->prev->next = undefined->next;
undefined->next->prev = undefined->prev;
undefined->prev = free_list.prev;
undefined->next = &free_list;
free_list.prev->next = undefined;
free_list.prev = undefined;
undefined->merged_symbol = NULL;
}
static
void
multiply_defined(
struct merged_symbol *merged_symbol,
struct nlist *object_symbol,
char *object_strings)
{
unsigned long i, j;
if(allow_multiply_defined_symbols == TRUE && nowarnings == TRUE)
return;
for(i = 0; i < nmultiple_defs; i++){
if(strcmp(multiple_defs[i], merged_symbol->nlist.n_un.n_name) == 0)
break;
}
for(j = 0; j < ntrace_syms; j++){
if(strcmp(trace_syms[j], merged_symbol->nlist.n_un.n_name) == 0)
break;
}
if(i == nmultiple_defs){
if(allow_multiply_defined_symbols == TRUE)
warning("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
else{
error("multiple definitions of symbol %s",
merged_symbol->nlist.n_un.n_name);
}
multiple_defs = reallocate(multiple_defs,
(nmultiple_defs + 1) * sizeof(char *));
multiple_defs[nmultiple_defs++] = merged_symbol->nlist.n_un.n_name;
if(j == ntrace_syms)
trace_merged_symbol(merged_symbol);
}
if(j == ntrace_syms)
trace_object_symbol(object_symbol, object_strings);
}
static
void
trace_object_symbol(
struct nlist *symbol,
char *strings)
{
char *indr_symbol_name;
if(symbol->n_type == (N_INDR | N_EXT))
indr_symbol_name = strings + symbol->n_value;
else
indr_symbol_name = "error in trace_symbol()";
trace_symbol(strings + symbol->n_un.n_strx, symbol, cur_obj,
indr_symbol_name);
}
__private_extern__
void
trace_merged_symbol(
struct merged_symbol *merged_symbol)
{
char *indr_symbol_name;
if(merged_symbol->nlist.n_type == (N_INDR | N_EXT))
indr_symbol_name = ((struct merged_symbol *)
(merged_symbol->nlist.n_value))->nlist.n_un.n_name;
else
indr_symbol_name = "error in trace_symbol()";
trace_symbol(merged_symbol->nlist.n_un.n_name, &(merged_symbol->nlist),
merged_symbol->definition_object, indr_symbol_name);
}
static
void
trace_symbol(
char *symbol_name,
struct nlist *nlist,
struct object_file *object_file,
char *indr_symbol_name)
{
print_obj_name(object_file);
if(nlist->n_type & N_PEXT)
print("private external ");
switch(nlist->n_type & N_TYPE){
case N_UNDF:
if(nlist->n_value == 0)
print("%sreference to undefined %s\n",
nlist->n_desc & N_WEAK_REF ? "weak " : "", symbol_name);
else
print("definition of common %s (size %u)\n", symbol_name,
nlist->n_value);
break;
case N_PBUD:
print("%sdefinition of %s\n",
nlist->n_desc & N_WEAK_DEF ? "weak " : "", symbol_name);
break;
case N_ABS:
print("definition of absolute %s (value 0x%x)\n", symbol_name,
(unsigned int)(nlist->n_value));
break;
case N_SECT:
print("%sdefinition of %s in section (%.16s,%.16s)\n",
nlist->n_desc & N_WEAK_DEF ? "weak " : "", symbol_name,
object_file->section_maps[nlist->n_sect - 1].s->segname,
object_file->section_maps[nlist->n_sect - 1].s->sectname);
break;
case N_INDR:
print("definition of %s as indirect for %s\n", symbol_name,
indr_symbol_name);
break;
default:
print("unknown type (0x%x) of %s\n", (unsigned int)nlist->n_type,
symbol_name);
break;
}
}
#ifndef RLD
__private_extern__
void
free_pass1_symbol_data(void)
{
free_undefined_list();
}
#endif
__private_extern__
void
free_undefined_list(void)
{
struct undefined_block *up, *undefined_block;
for(up = undefined_blocks; up; ){
undefined_block = up->next;
free(up);
up = undefined_block;
}
undefined_blocks = NULL;
undefined_list.next = &undefined_list;
undefined_list.prev = &undefined_list;
free_list.next = &free_list;
free_list.prev = &free_list;
}
__private_extern__
void
define_common_symbols(void)
{
struct section_spec *sect_spec;
struct merged_section *ms;
struct section *s;
unsigned long i, j, common_size, align;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
struct common_symbol *common_symbol;
struct object_list *object_list, **q;
struct object_file *object_file;
struct nlist *common_nlist;
char *common_names;
unsigned long n_strx;
#ifndef RLD
struct mach_header *link_edit_common_object_mach_header;
#endif
#if defined(DEBUG) || defined(RLD)
common_symbol = NULL;
common_nlist = NULL;
common_names = NULL;;
n_strx = 0;
#endif
#ifdef RLD
*(sets[cur_set].link_edit_common_object) =
link_edit_common_object;
sets[cur_set].link_edit_common_object->set_num =
cur_set;
sets[cur_set].link_edit_common_object->section_maps =
sets[cur_set].link_edit_section_maps;
*(sets[cur_set].link_edit_section_maps) =
link_edit_section_maps;
sets[cur_set].link_edit_section_maps->s =
sets[cur_set].link_edit_common_section;
*(sets[cur_set].link_edit_common_section) =
link_edit_common_section;
#endif
#ifndef RLD
sect_spec = lookup_section_spec(SEG_DATA, SECT_COMMON);
if(sect_spec != NULL){
if(sect_spec->contents_filename != NULL){
error("section (" SEG_DATA "," SECT_COMMON ") reserved for "
"allocating common symbols and can't be created from the "
"file: %s", sect_spec->contents_filename);
return;
}
sect_spec->processed = TRUE;
}
#else
sect_spec = NULL;
#endif
ms = lookup_merged_section(SEG_DATA, SECT_COMMON);
if(ms != NULL && (ms->s.flags & SECTION_TYPE) != S_ZEROFILL){
error("section (" SEG_DATA "," SECT_COMMON ") reserved for "
"allocating common symbols and exists in the loaded "
"objects not as a zero fill section");
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
object_file = &(object_list->object_files[i]);
if(object_file->dylib)
continue;
if(object_file->bundle_loader)
continue;
if(object_file->dylinker)
continue;
for(j = 0; j < object_file->nsection_maps; j++){
s = object_file->section_maps[j].s;
if(strcmp(s->segname, SEG_DATA) == 0 &&
strcmp(s->sectname, SECT_COMMON) == 0){
print_obj_name(object_file);
print("contains section (" SEG_DATA ","
SECT_COMMON ")\n");
}
}
}
}
return;
}
#ifndef RLD
else{
if(sect_spec != NULL && sect_spec->order_filename != NULL &&
ms != NULL){
ms->order_filename = sect_spec->order_filename;
ms->order_addr = sect_spec->order_addr;
ms->order_size = sect_spec->order_size;
}
}
#endif
commons_exist = FALSE;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if((merged_symbol->nlist.n_type & N_EXT) == N_EXT &&
(merged_symbol->nlist.n_type & N_TYPE) == N_UNDF &&
merged_symbol->nlist.n_value != 0){
if(filetype == MH_FVMLIB)
error("common symbols not allowed with MH_FVMLIB "
"output format");
if(filetype == MH_DYLIB && multi_module_dylib == TRUE)
error("common symbols not allowed with MH_DYLIB "
"output format with the -multi_module option");
commons_exist = TRUE;
#ifndef RLD
if((sect_spec != NULL &&
sect_spec->order_filename != NULL) ||
dead_strip == TRUE){
link_edit_common_symtab.nsyms++;
link_edit_common_symtab.strsize +=
strlen(merged_symbol->nlist.n_un.n_name) + 1;
}
else if(load_map)
common_load_map.ncommon_symbols++;
else
#endif
break;
}
}
}
if(commons_exist == FALSE)
return;
if(define_comldsyms == FALSE && output_for_dyld == FALSE)
return;
if(ms == NULL){
#ifdef RLD
ms = create_merged_section(sets[cur_set].link_edit_common_section);
#else
ms = create_merged_section(&link_edit_common_section);
#endif
if(sect_spec != NULL && sect_spec->align_specified)
ms->s.align = sect_spec->align;
else
ms->s.align = defaultsectalign;
if(sect_spec != NULL && sect_spec->order_filename != NULL){
ms->order_filename = sect_spec->order_filename;
ms->order_addr = sect_spec->order_addr;
ms->order_size = sect_spec->order_size;
}
}
else{
if(sect_spec != NULL && sect_spec->align_specified){
if(ms->s.align > sect_spec->align)
warning("specified alignment (0x%x) for section (" SEG_DATA
"," SECT_COMMON ") not used (less than the "
"required alignment in the input files (0x%x))",
(unsigned int)(1 << sect_spec->align),
(unsigned int)(1 << ms->s.align));
else
ms->s.align = sect_spec->align;
}
if(ms->s.align < defaultsectalign)
ms->s.align = defaultsectalign;
}
#ifndef RLD
if((sect_spec != NULL && sect_spec->order_filename != NULL) ||
dead_strip == TRUE){
link_edit_common_symtab.strsize =
rnd(link_edit_common_symtab.strsize, sizeof(long));
link_edit_common_object.obj_size =
sizeof(struct mach_header) +
link_edit_common_symtab.nsyms * sizeof(struct nlist) +
link_edit_common_symtab.strsize;
link_edit_common_object.obj_addr =
allocate(link_edit_common_object.obj_size);
memset(link_edit_common_object.obj_addr,
'\0',
link_edit_common_object.obj_size);
link_edit_common_object_mach_header = (struct mach_header *)
link_edit_common_object.obj_addr;
link_edit_common_object_mach_header->magic = MH_MAGIC;
link_edit_common_object_mach_header->filetype = MH_OBJECT;
link_edit_common_object_mach_header->flags =
MH_SUBSECTIONS_VIA_SYMBOLS;
link_edit_common_symtab.symoff = sizeof(struct mach_header);
link_edit_common_symtab.stroff = sizeof(struct mach_header) +
link_edit_common_symtab.nsyms *
sizeof(struct nlist);
common_nlist = (struct nlist *)(link_edit_common_object.obj_addr +
link_edit_common_symtab.symoff);
common_names = (char *)(link_edit_common_object.obj_addr +
link_edit_common_symtab.stroff);
n_strx = 1;
}
else if(load_map){
common_load_map.common_ms = ms;
common_load_map.common_symbols = allocate(
common_load_map.ncommon_symbols *
sizeof(struct common_symbol));
common_symbol = common_load_map.common_symbols;
}
#endif
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if((merged_symbol->nlist.n_type & N_EXT) == N_EXT &&
(merged_symbol->nlist.n_type & N_TYPE) == N_UNDF &&
merged_symbol->nlist.n_value != 0){
if(filetype == MH_FVMLIB ||
(filetype == MH_DYLIB && multi_module_dylib == TRUE))
trace_merged_symbol(merged_symbol);
common_size = merged_symbol->nlist.n_value;
align = 0;
while((unsigned long)(1 << align) < common_size &&
align < ms->s.align)
align++;
#ifdef RLD
sets[cur_set].link_edit_common_section->size = rnd(
sets[cur_set].link_edit_common_section->size, 1<< align);
#else
link_edit_common_section.size = rnd(
link_edit_common_section.size, 1 << align);
#endif
merged_symbol->nlist.n_type = N_SECT | N_EXT |
(merged_symbol->nlist.n_type & N_PEXT);
merged_symbol->nlist.n_sect = 1;
#ifdef RLD
merged_symbol->nlist.n_value =
sets[cur_set].link_edit_common_section->size;
merged_symbol->definition_object =
sets[cur_set].link_edit_common_object;
sets[cur_set].link_edit_common_section->size += common_size;
#else
merged_symbol->nlist.n_value =link_edit_common_section.size;
merged_symbol->definition_object =
&link_edit_common_object;
link_edit_common_section.size += common_size;
exports_list_processing(merged_symbol->nlist.n_un.n_name,
&(merged_symbol->nlist));
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT){
link_edit_common_object.nprivatesym++;
nmerged_private_symbols++;
}
#endif
if(ntrace_syms != 0){
for(j = 0; j < ntrace_syms; j++){
if(strcmp(trace_syms[j],
merged_symbol->nlist.n_un.n_name) == 0){
trace_merged_symbol(merged_symbol);
break;
}
}
}
#ifndef RLD
if((sect_spec != NULL &&
sect_spec->order_filename != NULL) ||
dead_strip == TRUE){
common_nlist->n_un.n_strx = n_strx;
common_nlist->n_type = N_SECT | N_EXT;
common_nlist->n_sect = 1;
common_nlist->n_desc = 0;
common_nlist->n_value = merged_symbol->nlist.n_value;
strcpy(common_names + n_strx,
merged_symbol->nlist.n_un.n_name);
common_nlist++;
n_strx += strlen(merged_symbol->nlist.n_un.n_name) + 1;
}
else if(load_map){
common_symbol->merged_symbol = merged_symbol;
common_symbol->common_size = common_size;
common_symbol++;
}
#endif
}
}
}
#ifdef RLD
sets[cur_set].link_edit_common_object->section_maps[0].output_section =
ms;
ms->s.size = rnd(ms->s.size, 1 << ms->s.align);
sets[cur_set].link_edit_common_object->section_maps[0].offset =
ms->s.size;
ms->s.size += sets[cur_set].link_edit_common_section->size;
#else
link_edit_common_object.section_maps[0].output_section = ms;
ms->s.size = rnd(ms->s.size, 1 << ms->s.align);
link_edit_common_object.section_maps[0].offset = ms->s.size;
ms->s.size += link_edit_common_section.size;
#endif
}
#ifndef RLD
__private_extern__
void
define_undefined_symbols_a_way(
void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
merged_symbol->nlist.n_value == 0){
if(dynamic == TRUE &&
filetype != MH_EXECUTE &&
merged_segments != NULL){
define_link_editor_symbol(
merged_symbol->nlist.n_un.n_name,
N_SECT | N_PEXT | N_EXT,
1,
0,
0);
}
else{
define_link_editor_symbol(
merged_symbol->nlist.n_un.n_name,
N_ABS | N_PEXT | N_EXT,
NO_SECT,
0,
0);
}
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT){
link_edit_symbols_object->nprivatesym++;
nmerged_private_symbols++;
}
merged_symbol->define_a_way = 1;
}
}
}
}
static
void
setup_link_edit_symbols_object(
void)
{
if(link_edit_symbols_object == NULL){
link_edit_symbols_object = new_object_file();
link_edit_symbols_object->file_name = "link editor";
}
}
#ifndef RLD
__private_extern__
void
mark_globals_live(void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
enum bool only_referenced_dynamically;
if(filetype == MH_EXECUTE &&
(save_symbols == NULL && remove_symbols == NULL))
only_referenced_dynamically = TRUE;
else
only_referenced_dynamically = FALSE;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if((merged_symbol->nlist.n_desc &
REFERENCED_DYNAMICALLY) == REFERENCED_DYNAMICALLY ||
(merged_symbol->nlist.n_desc &
N_NO_DEAD_STRIP) == N_NO_DEAD_STRIP ||
(((merged_symbol->nlist.n_type & N_TYPE) == N_SECT) &&
(merged_symbol->definition_object->
section_maps[merged_symbol->nlist.n_sect - 1].s->flags &
S_ATTR_NO_DEAD_STRIP) == S_ATTR_NO_DEAD_STRIP) ){
goto mark_it_live;
}
else{
if(merged_symbol->defined_in_dylib == TRUE)
continue;
if((merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
merged_symbol->nlist.n_value == 0) ||
merged_symbol->nlist.n_type == (N_EXT | N_PBUD))
continue;
if((merged_symbol->nlist.n_type & N_EXT) &&
(merged_symbol->nlist.n_type & N_PEXT))
continue;
if(only_referenced_dynamically == TRUE)
continue;
}
#ifdef DEBUG
mark_it_live:
if(((debug & (1 << 25)) || (debug & (1 << 26)))){
print("** In mark_globals_live() ");
if(merged_symbol->nlist.n_desc & N_NO_DEAD_STRIP)
print("no dead strip symbol ");
else
print("exported symbol ");
print_obj_name(merged_symbol->definition_object);
print("%s\n", merged_symbol->nlist.n_un.n_name);
}
#endif
merged_symbol->live = TRUE;
if(merged_symbol->fine_reloc != NULL)
merged_symbol->fine_reloc->live = TRUE;
}
}
}
__private_extern__
void
mark_N_NO_DEAD_STRIP_local_symbols_live(void)
{
struct merged_segment *msg, **r;
struct merged_section *ms, **content, **zerofill;
if(local_NO_DEAD_STRIP_symbols == FALSE)
return;
r = &merged_segments;
while(*r){
msg = *r;
content = &(msg->content_sections);
while(*content){
ms = *content;
mark_N_NO_DEAD_STRIP_local_symbols_in_section_live(ms);
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
mark_N_NO_DEAD_STRIP_local_symbols_in_section_live(ms);
zerofill = &(ms->next);
}
r = &(msg->next);
}
}
static
void
mark_N_NO_DEAD_STRIP_local_symbols_in_section_live(
struct merged_section *ms)
{
unsigned long i, j, k, nsect, input_offset;
struct object_list *object_list, **q;
struct section_map *map;
struct nlist *object_symbols;
char *object_strings;
struct fine_reloc *fine_reloc;
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;
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;
map = &(cur_obj->section_maps[j]);
break;
}
if(map == NULL)
continue;
object_symbols = NULL;
object_strings = NULL;
if(cur_obj->symtab != NULL){
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;
for(k = 0; k < cur_obj->symtab->nsyms; k++){
if((object_symbols[k].n_type & N_EXT) == 0 &&
(object_symbols[k].n_type & N_TYPE) == N_SECT &&
(object_symbols[k].n_type & N_STAB) == 0 &&
object_symbols[k].n_sect == nsect &&
object_symbols[k].n_desc & N_NO_DEAD_STRIP){
input_offset = object_symbols[k].n_value - map->s->addr;
fine_reloc = fine_reloc_for_input_offset(
map, input_offset);
fine_reloc->live = TRUE;
}
}
}
}
}
__private_extern__
void
set_fine_relocs_for_merged_symbols(void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->fine_reloc != NULL)
continue;
if(merged_symbol->defined_in_dylib == TRUE ||
merged_symbol->nlist.n_type == (N_EXT | N_UNDF) ||
(merged_symbol->nlist.n_type & N_TYPE) == N_PBUD)
continue;
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
merged_symbol->fine_reloc = get_fine_reloc_for_merged_symbol(
merged_symbol, NULL);
}
}
}
__private_extern__
void
count_live_symbols(void)
{
unsigned long i, j, nrefsym;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
struct object_list *object_list, **q;
struct object_file *obj;
struct merged_segment *msg, **r;
struct merged_section *ms, **content, **zerofill;
merged_string_blocks = NULL;
merged_string_size = 0;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->live == FALSE){
if(merged_symbol->fine_reloc != NULL &&
merged_symbol->fine_reloc->live == TRUE)
merged_symbol->live = TRUE;
}
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
if(merged_symbol->live == TRUE){
merged_symbol->nlist.n_un.n_name =
enter_string(merged_symbol->nlist.n_un.n_name, NULL);
}
else{
nstripped_merged_symbols++;
if(merged_symbol->defined_in_dylib == TRUE ||
merged_symbol->nlist.n_type == (N_EXT | N_UNDF) ||
(merged_symbol->nlist.n_type & N_TYPE) == N_PBUD)
continue;
if(merged_symbol->nlist.n_type & N_PEXT){
merged_symbol->definition_object->nprivatesym--;
nstripped_merged_private_symbols++;
}
else if(filetype == MH_DYLIB &&
multi_module_dylib == TRUE)
merged_symbol->definition_object->nextdefsym--;
}
}
}
output_dysymtab_info.dysymtab_command.nextrefsyms = 0;
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
obj = &(object_list->object_files[i]);
if(obj->dylib)
continue;
if(obj->bundle_loader)
continue;
if(obj->dylinker)
continue;
nrefsym = 0;
for(j = 0; j < obj->nrefsym; j++){
if(obj->reference_maps[j].merged_symbol->live){
obj->reference_maps[nrefsym] =
obj->reference_maps[j];
nrefsym++;
}
}
obj->nrefsym = nrefsym;
if(nrefsym != 0)
obj->irefsym =
output_dysymtab_info.dysymtab_command.nextrefsyms;
output_dysymtab_info.dysymtab_command.nextrefsyms +=
nrefsym;
}
}
}
r = &merged_segments;
while(*r){
msg = *r;
content = &(msg->content_sections);
while(*content){
ms = *content;
removed_dead_local_symbols_in_section(ms);
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
removed_dead_local_symbols_in_section(ms);
zerofill = &(ms->next);
}
r = &(msg->next);
}
remove_dead_N_GSYM_stabs();
}
static
void
removed_dead_local_symbols_in_section(
struct merged_section *ms)
{
unsigned long i, j;
struct object_list *object_list, **q;
struct section_map *map;
struct nlist *object_symbols;
char *object_strings;
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;
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;
map = &(cur_obj->section_maps[j]);
break;
}
if(map == NULL)
continue;
object_symbols = NULL;
object_strings = NULL;
if(cur_obj->symtab != NULL){
object_symbols = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
object_strings = (char *)(cur_obj->obj_addr +
cur_obj->symtab->stroff);
}
discard_local_symbols_for_section(j + 1,
object_symbols, object_strings,
cur_obj->section_maps[j].s, map);
}
}
}
static
void
remove_dead_N_GSYM_stabs(
void)
{
unsigned long i;
struct object_list *object_list, **q;
struct nlist *object_symbols;
char *object_strings;
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->symtab != NULL){
object_symbols = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
object_strings = (char *)(cur_obj->obj_addr +
cur_obj->symtab->stroff);
remove_dead_N_GSYM_stabs_for_cur_obj(object_symbols,
object_strings);
}
}
}
}
#endif
__private_extern__
void
define_link_editor_execute_symbols(
unsigned long header_address)
{
struct merged_symbol *merged_symbol;
merged_symbol = lookup_symbol(_MH_EXECUTE_SYM);
if(merged_symbol->name_len != 0)
merged_symbol->nlist.n_value = header_address;
merged_symbol = lookup_symbol("___dso_handle");
if(merged_symbol->name_len != 0)
merged_symbol->nlist.n_value = header_address;
}
#ifndef RLD
__private_extern__
void
setup_link_editor_symbols(
void)
{
if(filetype == MH_EXECUTE){
setup_link_editor_symbol(_MH_EXECUTE_SYM);
setup_link_editor_symbol("___dso_handle");
}
else if(filetype == MH_BUNDLE){
setup_link_editor_symbol(_MH_BUNDLE_SYM);
setup_link_editor_symbol("___dso_handle");
}
else if(filetype == MH_DYLIB){
setup_link_editor_symbol(_MH_DYLIB_SYM);
setup_link_editor_symbol("___dso_handle");
}
else{
setup_link_editor_symbol(_MH_DYLINKER_SYM);
setup_link_editor_symbol("___dso_handle");
}
}
static
void
setup_link_editor_symbol(
char *symbol_name)
{
struct merged_symbol *merged_symbol;
unsigned long nsects, i, j, n;
struct section *sections;
struct section_map *section_maps;
struct merged_segment **p, *msg;
struct merged_section **q, *ms;
merged_symbol = lookup_symbol(symbol_name);
if(merged_symbol->name_len == 0)
return;
if(filetype == MH_BUNDLE &&
strcmp(symbol_name, "___dso_handle") == 0 &&
merged_symbol->definition_object->bundle_loader == TRUE &&
merged_symbol->non_dylib_referenced_obj == NULL)
return;
if(filetype == MH_EXECUTE){
define_link_editor_symbol(symbol_name, N_EXT | N_ABS, NO_SECT,
merged_symbol->nlist.n_desc & REFERENCED_DYNAMICALLY, 0);
return;
}
setup_link_edit_symbols_object();
n = link_edit_symbols_object->nprivatesym;
link_edit_symbols_object->nprivatesym += 1;
nmerged_private_symbols++;
link_edit_symbols_object->nrefsym += 1;
if(n == 0)
link_edit_symbols_object->irefsym =
output_dysymtab_info.dysymtab_command.nextrefsyms;
if(filetype == MH_DYLIB)
output_dysymtab_info.dysymtab_command.nextrefsyms += 1;
link_edit_symbols_object->reference_maps =
reallocate(link_edit_symbols_object->reference_maps,
sizeof(struct reference_map) * (n + 1));
link_edit_symbols_object->reference_maps[n].flags =
REFERENCE_FLAG_PRIVATE_DEFINED;
link_edit_symbols_object->reference_maps[n].merged_symbol =
merged_symbol;
nsects = 0;
p = &merged_segments;
while(*p){
msg = *p;
nsects += msg->sg.nsects;
p = &(msg->next);
}
if(nsects > 0 && link_edit_symbols_object->nsection_maps == 0){
sections = allocate(nsects * sizeof(struct section));
memset(sections, '\0', nsects * sizeof(struct section));
section_maps = allocate(nsects * sizeof(struct section_map));
memset(section_maps, '\0', nsects * sizeof(struct section_map));
setup_link_edit_symbols_object();
link_edit_symbols_object->nsection_maps = nsects;
link_edit_symbols_object->section_maps = section_maps;
i = 0;
p = &merged_segments;
while(*p){
msg = *p;
for(j = 0; j < 2 ; j++){
if(j == 0)
q = &(msg->content_sections);
else
q = &(msg->zerofill_sections);
while(*q){
ms = *q;
strncpy(sections[i].sectname, ms->s.sectname,
sizeof(ms->s.sectname));
strncpy(sections[i].segname, ms->s.segname,
sizeof(ms->s.segname));
section_maps[i].s = &(sections[i]);
section_maps[i].output_section = ms;
i++;
q = &(ms->next);
}
}
p = &(msg->next);
}
}
if(nsects > 0)
define_link_editor_symbol(symbol_name, N_SECT | N_PEXT | N_EXT,
1, merged_symbol->nlist.n_desc & REFERENCED_DYNAMICALLY, 0);
else
define_link_editor_symbol(symbol_name, N_ABS | N_PEXT | N_EXT,
NO_SECT, merged_symbol->nlist.n_desc & REFERENCED_DYNAMICALLY, 0);
}
__private_extern__
void
define_link_editor_dylib_symbols(
unsigned long header_address)
{
struct merged_symbol *merged_symbol;
struct merged_symbol_list *merged_symbol_list;
unsigned long i;
if(filetype == MH_BUNDLE)
define_link_editor_dylib_symbol(header_address, _MH_BUNDLE_SYM);
else if(filetype == MH_DYLIB)
define_link_editor_dylib_symbol(header_address, _MH_DYLIB_SYM);
else
define_link_editor_dylib_symbol(header_address, _MH_DYLINKER_SYM);
define_link_editor_dylib_symbol(header_address, "___dso_handle");
if(undefined_flag == UNDEFINED_DEFINE_A_WAY){
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->define_a_way == 1){
if(merged_symbol->nlist.n_sect == NO_SECT)
merged_symbol->nlist.n_value = header_address;
else
merged_symbol->nlist.n_value = header_address -
link_edit_symbols_object->section_maps[0].
output_section->s.addr;
}
}
}
}
}
static
void
define_link_editor_dylib_symbol(
unsigned long header_address,
char *symbol_name)
{
struct merged_symbol *merged_symbol;
merged_symbol = lookup_symbol(symbol_name);
if(merged_symbol->name_len == 0)
return;
if(merged_symbol->nlist.n_sect == NO_SECT)
merged_symbol->nlist.n_value = header_address;
else
merged_symbol->nlist.n_value = header_address -
link_edit_symbols_object->section_maps[0].output_section->s.addr;
}
#endif
__private_extern__
void
define_link_editor_preload_symbols(
enum bool setup)
{
unsigned long nsects, i, j, first_section;
struct section *sections;
struct section_map *section_maps;
struct merged_segment **p, *msg;
struct merged_section **q, *ms;
struct merged_symbol *merged_symbol;
char symbol_name[sizeof(ms->s.segname) + sizeof(ms->s.sectname) +
sizeof("__begin")];
sections = NULL;
section_maps = NULL;
if(setup == TRUE){
nsects = 0;
p = &merged_segments;
while(*p){
msg = *p;
nsects += msg->sg.nsects;
p = &(msg->next);
}
sections = allocate(nsects * sizeof(struct section));
memset(sections, '\0', nsects * sizeof(struct section));
section_maps = allocate(nsects * sizeof(struct section_map));
memset(section_maps, '\0', nsects * sizeof(struct section_map));
setup_link_edit_symbols_object();
link_edit_symbols_object->nsection_maps = nsects;
link_edit_symbols_object->section_maps = section_maps;
}
i = 0;
p = &merged_segments;
while(*p){
msg = *p;
strncpy(symbol_name, msg->sg.segname, sizeof(msg->sg.segname));
strcat(symbol_name, "__begin");
if(setup == TRUE)
define_link_editor_symbol(symbol_name, N_EXT | N_SECT, i+1,0,0);
first_section = i + 1;
for(j = 0; j < 2 ; j++){
if(j == 0)
q = &(msg->content_sections);
else
q = &(msg->zerofill_sections);
while(*q){
ms = *q;
if(setup == TRUE){
strncpy(sections[i].sectname, ms->s.sectname,
sizeof(ms->s.sectname));
strncpy(sections[i].segname, ms->s.segname,
sizeof(ms->s.segname));
section_maps[i].s = &(sections[i]);
section_maps[i].output_section = ms;
}
strncpy(symbol_name, ms->s.segname,
sizeof(ms->s.segname));
strncat(symbol_name, ms->s.sectname,
sizeof(ms->s.sectname));
strcat(symbol_name, "__begin");
if(setup == TRUE)
define_link_editor_symbol(symbol_name, N_EXT | N_SECT,
i+1, 0, 0);
strncpy(symbol_name, ms->s.segname,
sizeof(ms->s.segname));
strncat(symbol_name, ms->s.sectname,
sizeof(ms->s.sectname));
strcat(symbol_name, "__end");
if(setup)
define_link_editor_symbol(symbol_name, N_EXT | N_SECT,
i+1, 0, 0);
else{
merged_symbol = lookup_symbol(symbol_name);
if(merged_symbol->name_len != 0)
merged_symbol->nlist.n_value = ms->s.size;
}
i++;
q = &(ms->next);
}
}
strncpy(symbol_name, msg->sg.segname,
sizeof(msg->sg.segname));
strcat(symbol_name, "__end");
if(setup)
define_link_editor_symbol(symbol_name, N_EXT | N_SECT,
first_section, 0, 0);
else{
merged_symbol = lookup_symbol(symbol_name);
if(merged_symbol->name_len != 0)
merged_symbol->nlist.n_value = msg->sg.vmsize;
}
p = &(msg->next);
}
}
static
void
define_link_editor_symbol(
char *symbol_name,
unsigned char type,
unsigned char sect,
short desc,
unsigned long value)
{
unsigned long i;
struct merged_symbol *merged_symbol;
merged_symbol = lookup_symbol(symbol_name);
if(merged_symbol->name_len == 0)
return;
if((merged_symbol->nlist.n_type & N_EXT) != N_EXT ||
(merged_symbol->nlist.n_type & N_TYPE) != N_UNDF ||
merged_symbol->nlist.n_value != 0){
if(merged_symbol->definition_object != base_obj &&
merged_symbol->definition_object->bundle_loader == FALSE){
error("loaded objects attempt to redefine link editor "
"defined symbol %s", symbol_name);
trace_merged_symbol(merged_symbol);
return;
}
}
if(define_comldsyms == FALSE)
return;
setup_link_edit_symbols_object();
merged_symbol->nlist.n_type = type;
merged_symbol->nlist.n_sect = sect;
merged_symbol->nlist.n_desc = desc;
merged_symbol->nlist.n_value = value;
merged_symbol->definition_object = link_edit_symbols_object;
#ifndef RLD
if((merged_symbol->nlist.n_type & N_PEXT) != N_PEXT){
exports_list_processing(merged_symbol->nlist.n_un.n_name,
&(merged_symbol->nlist));
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT){
merged_symbol->definition_object->nprivatesym++;
nmerged_private_symbols++;
}
}
#endif
if(ntrace_syms != 0){
for(i = 0; i < ntrace_syms; i++){
if(strcmp(trace_syms[i], symbol_name) == 0){
trace_merged_symbol(merged_symbol);
break;
}
}
}
}
#endif
__private_extern__
void
reduce_indr_symbols(void)
{
unsigned long i, j, k, indr_depth, from_dylibs, not_from_dylibs;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol, **indr_symbols, *indr_symbol;
struct indr_symbol_pair *indr_symbol_pair;
indr_symbols = allocate(nindr_symbols * sizeof(struct merged_symbol *));
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->nlist.n_type == (N_EXT | N_INDR) &&
merged_symbol->nlist.n_value != 0){
if(merged_symbol->defined_in_dylib == TRUE){
from_dylibs = 1;
not_from_dylibs = 0;
}
else{
from_dylibs = 0;
not_from_dylibs = 1;
}
indr_symbols[0] = merged_symbol;
indr_depth = 1;
indr_symbol = (struct merged_symbol *)
(merged_symbol->nlist.n_value);
while(indr_symbol->nlist.n_type == (N_EXT | N_INDR) &&
indr_symbol->nlist.n_value != 0){
for(j = 0; j < indr_depth; j++){
if(indr_symbols[j] == indr_symbol)
break;
}
if(j == indr_depth){
if(indr_symbol->defined_in_dylib == TRUE)
from_dylibs++;
else
not_from_dylibs++;
indr_symbols[indr_depth++] = indr_symbol;
indr_symbol = (struct merged_symbol *)
(indr_symbol->nlist.n_value);
}
else{
error("indirect symbol loop:");
for(k = j; k < indr_depth; k++){
trace_merged_symbol(indr_symbols[k]);
indr_symbols[k]->nlist.n_value = 0;
}
indr_symbol->nlist.n_value = 0;
}
}
if(from_dylibs != 0 && not_from_dylibs != 0 &&
indr_symbol->nlist.n_type != (N_EXT | N_INDR)){
for(j = 0; j < indr_depth; j++){
if(indr_symbols[j]->defined_in_dylib == FALSE){
for(k = j + 1; k < indr_depth; k++){
if(indr_symbols[k]->defined_in_dylib)
break;
}
indr_symbol_pairs = reallocate(
indr_symbol_pairs,
sizeof(struct indr_symbol_pair) *
(nindr_symbol_pairs + 1));
indr_symbol_pair = indr_symbol_pairs +
nindr_symbol_pairs;
nindr_symbol_pairs++;
indr_symbol_pair->merged_symbol = merged_symbol;
if(k < indr_depth &&
indr_symbols[k]->defined_in_dylib)
indr_symbol_pair->indr_symbol =
indr_symbols[k];
else
indr_symbol_pair->indr_symbol =
indr_symbol;
}
}
}
if(indr_symbol->nlist.n_type != (N_EXT | N_INDR)){
for(j = 0; j < indr_depth; j++){
indr_symbols[j]->nlist.n_value =
(unsigned long)indr_symbol;
if((indr_symbol->nlist.n_type & N_PEXT) == N_PEXT){
indr_symbols[j]->definition_object->
nprivatesym++;
nmerged_private_symbols++;
}
}
}
}
}
}
free(indr_symbols);
}
__private_extern__
void
layout_merged_symbols(void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
relocate_symbol(&(merged_symbol->nlist),
merged_symbol->definition_object);
}
}
merged_symbols_relocated = TRUE;
if(noundefs == TRUE &&
(define_comldsyms == TRUE || commons_exist == FALSE))
output_mach_header.flags |= MH_NOUNDEFS;
}
__private_extern__
void
discard_local_symbols_for_section(
unsigned long nsect,
struct nlist *object_symbols,
char *object_strings,
struct section *s,
struct section_map *section_map)
{
unsigned long i, j, k, output_strlen;
struct localsym_block *localsym_block, **next_localsym_block;
struct fine_reloc *fine_reloc;
enum bool closed_last_block;
size_t * debug_ptr;
localsym_block = cur_obj->localsym_blocks;
next_localsym_block = &(cur_obj->localsym_blocks);
debug_ptr = cur_obj->dwarf_source_data;
for(i = 0; i < cur_obj->symtab->nsyms; i++){
if (debug_ptr && *debug_ptr < i) {
for (debug_ptr += 2; *debug_ptr & 0x80000000; debug_ptr++) ;
}
if(localsym_block != NULL && localsym_block->index == i){
i += localsym_block->count - 1;
next_localsym_block = &(localsym_block->next);
localsym_block = localsym_block->next;
continue;
}
if((object_symbols[i].n_type & N_EXT) == 0 &&
((object_symbols[i].n_type & N_TYPE) == N_SECT ||
(object_symbols[i].n_type & N_STAB) != 0) &&
object_symbols[i].n_sect == nsect &&
is_output_local_symbol(object_symbols[i].n_type,
object_symbols[i].n_sect,
object_symbols[i].n_desc, cur_obj,
object_symbols[i].n_un.n_strx == 0 ? "" :
object_strings +
object_symbols[i].n_un.n_strx,
&output_strlen)){
if(fine_reloc_offset_in_output(section_map,
object_symbols[i].n_value - s->addr) == FALSE &&
object_symbols[i].n_type != N_SO){
nlocal_symbols--;
cur_obj->nlocalsym--;
local_string_size -=
object_symbols[i].n_un.n_strx == 0 ? 0:
output_strlen + 1;
if (cur_obj->dwarf_name){
size_t n = count_dwarf_symbols (object_symbols + i, i,
debug_ptr);
cur_obj->nlocalsym -= n;
nlocal_symbols -= n;
}
localsym_block = allocate(sizeof(struct localsym_block));
memset(localsym_block, '\0', sizeof(struct localsym_block));
localsym_block->index = i;
localsym_block->state = DISCARD_SYMBOLS;
localsym_block->count = 1;
localsym_block->next = *next_localsym_block;
*next_localsym_block = localsym_block;
next_localsym_block = &(localsym_block->next);
fine_reloc = fine_reloc_for_input_offset(section_map,
object_symbols[i].n_value - s->addr);
if(object_symbols[i].n_type == N_BNSYM &&
i + 1 < cur_obj->symtab->nsyms){
for(j = i + 1; j < cur_obj->symtab->nsyms; j++){
if(localsym_block->next != NULL &&
j >= localsym_block->next->index)
break;
if(object_symbols[j].n_type == N_ENSYM)
break;
if((object_symbols[j].n_type & N_EXT) == N_EXT)
break;
if((object_symbols[j].n_type & N_STAB) == 0)
break;
if(object_symbols[j].n_sect == NO_SECT)
continue;
if(object_symbols[j].n_sect != nsect)
break;
if(fine_reloc != fine_reloc_for_input_offset(
section_map,
object_symbols[j].n_value - s->addr))
break;
}
if(j < cur_obj->symtab->nsyms &&
(localsym_block->next == NULL ||
j < localsym_block->next->index) &&
object_symbols[j].n_type == N_ENSYM &&
object_symbols[j].n_sect == nsect){
closed_last_block = FALSE;
for(k = i + 1; k <= j; k++){
if(is_type_stab(object_symbols[k].n_type,
object_symbols[k].n_un.n_strx == 0 ? "" :
object_strings +
object_symbols[k].n_un.n_strx)){
closed_last_block = TRUE;
}
else{
if(closed_last_block == TRUE){
localsym_block = allocate(
sizeof(struct localsym_block));
memset(localsym_block, '\0',
sizeof(struct localsym_block));
localsym_block->index = k;
localsym_block->state = DISCARD_SYMBOLS;
localsym_block->next =
*next_localsym_block;
*next_localsym_block = localsym_block;
next_localsym_block =
&(localsym_block->next);
closed_last_block = FALSE;
}
localsym_block->count++;
nlocal_symbols--;
cur_obj->nlocalsym--;
local_string_size -=
object_symbols[k].n_un.n_strx == 0 ? 0:
strlen(object_strings +
object_symbols[k].n_un.n_strx) + 1;
}
}
i = j;
}
}
localsym_block = localsym_block->next;
}
else if(object_symbols[i].n_type == N_BNSYM &&
i + 1 < cur_obj->symtab->nsyms){
fine_reloc = fine_reloc_for_input_offset(section_map,
object_symbols[i].n_value - s->addr);
for(j = i + 1; j < cur_obj->symtab->nsyms; j++){
if(localsym_block != NULL &&
j >= localsym_block->index)
break;
if(object_symbols[j].n_type == N_ENSYM)
break;
if((object_symbols[j].n_type & N_EXT) == N_EXT)
break;
if((object_symbols[j].n_type & N_STAB) == 0)
break;
if(object_symbols[j].n_sect == NO_SECT)
continue;
if(object_symbols[j].n_sect != nsect)
break;
if(fine_reloc != fine_reloc_for_input_offset(
section_map,
object_symbols[j].n_value - s->addr))
break;
}
if(j < cur_obj->symtab->nsyms &&
(localsym_block == NULL ||
j < localsym_block->index) &&
object_symbols[j].n_type == N_ENSYM &&
object_symbols[j].n_sect == nsect){
i = j;
}
}
else if(object_symbols[i].n_type == N_SO &&
fine_reloc_offset_in_output(section_map,
object_symbols[i].n_value - s->addr) == FALSE){
object_symbols[i].n_sect = NO_SECT;
object_symbols[i].n_value = 0;
}
}
}
}
#ifndef RLD
static
void
remove_dead_N_GSYM_stabs_for_cur_obj(
struct nlist *object_symbols,
char *object_strings)
{
unsigned long i, len, symbol_name_len;
long output_strlen;
struct localsym_block *localsym_block, **next_localsym_block;
char *stab_name, *symbol_name, *p;
struct merged_symbol *hash_pointer, *merged_symbol;
size_t * debug_ptr;
symbol_name_len = 0;
symbol_name = NULL;
localsym_block = cur_obj->localsym_blocks;
next_localsym_block = &(cur_obj->localsym_blocks);
debug_ptr = cur_obj->dwarf_source_data;
for(i = 0; i < cur_obj->symtab->nsyms; i++){
if (debug_ptr && *debug_ptr < i) {
for (debug_ptr += 2; *debug_ptr & 0x80000000; debug_ptr++) ;
}
if (cur_obj->dwarf_name
&& object_symbols[i].n_type & N_EXT
&& object_symbols[i].n_un.n_strx != 0) {
size_t cnt = count_dwarf_symbols (object_symbols + i, i,
debug_ptr);
if (cnt == 0)
continue;
hash_pointer = lookup_symbol(object_strings
+ object_symbols[i].n_un.n_strx);
if (hash_pointer->name_len == 0
|| hash_pointer->live
|| (object_symbols[i].n_sect != NO_SECT
&& hash_pointer->definition_object != cur_obj))
continue;
cur_obj->nlocalsym -= cnt;
nlocal_symbols -= cnt;
}
if(localsym_block != NULL && localsym_block->index == i){
i += localsym_block->count - 1;
next_localsym_block = &(localsym_block->next);
localsym_block = localsym_block->next;
continue;
}
output_strlen = -1;
if(object_symbols[i].n_type == N_GSYM &&
is_output_local_symbol(object_symbols[i].n_type,
object_symbols[i].n_sect,
object_symbols[i].n_desc, cur_obj,
object_symbols[i].n_un.n_strx == 0 ? "" :
object_strings +
object_symbols[i].n_un.n_strx,
(unsigned long *)&output_strlen)){
if(output_strlen == -1)
output_strlen = object_symbols[i].n_un.n_strx == 0 ? 0:
strlen(object_strings +
object_symbols[i].n_un.n_strx);
if(object_symbols[i].n_un.n_strx == 0)
continue;
stab_name = object_strings + object_symbols[i].n_un.n_strx;
p = strchr(stab_name, ':');
if(p == NULL)
continue;
len = p - stab_name;
if(len == 0)
continue;
if(len + 2 > symbol_name_len){
if(len + 2 < 4096)
symbol_name_len = 4096;
else
symbol_name_len = len + 2;
symbol_name = reallocate(symbol_name, symbol_name_len);
}
strcpy(symbol_name, "_");
strncat(symbol_name, stab_name, len);
hash_pointer = lookup_symbol(symbol_name);
if(hash_pointer->name_len == 0)
continue;
merged_symbol = hash_pointer;
if(merged_symbol->live == FALSE){
nlocal_symbols--;
cur_obj->nlocalsym--;
local_string_size -= output_strlen == 0 ? 0:
output_strlen + 1;
localsym_block = allocate(sizeof(struct localsym_block));
memset(localsym_block, '\0', sizeof(struct localsym_block));
localsym_block->index = i;
localsym_block->state = DISCARD_SYMBOLS;
localsym_block->count = 1;
localsym_block->next = *next_localsym_block;
*next_localsym_block = localsym_block;
next_localsym_block = &(localsym_block->next);
localsym_block = localsym_block->next;
}
}
}
if(symbol_name != NULL)
free(symbol_name);
}
#endif
struct bincl_entry {
unsigned long sum;
unsigned long stroffset;
const char* path;
};
static struct bincl_entry* bincl_entries = NULL;
static unsigned int bincl_entries_used = 0;
static unsigned int bincl_entry_count = 0;
static
void
record_bincl(
unsigned long sum,
const char* path,
unsigned long output_stroffset)
{
struct bincl_entry *tmp;
char *path_copy;
if(bincl_entries == NULL){
bincl_entry_count = 8192;
bincl_entries = allocate(sizeof(struct bincl_entry) *
bincl_entry_count);
}
if(bincl_entries_used == bincl_entry_count){
bincl_entry_count *= 2;
tmp = allocate(sizeof(struct bincl_entry)*bincl_entry_count);
memcpy(tmp, bincl_entries, sizeof(struct bincl_entry) *
bincl_entries_used);
free(bincl_entries);
bincl_entries = tmp;
}
bincl_entries[bincl_entries_used].sum = sum;
bincl_entries[bincl_entries_used].stroffset = output_stroffset;
path_copy = allocate(strlen(path) + 1);
strcpy(path_copy, path);
bincl_entries[bincl_entries_used].path = path_copy;
bincl_entries_used++;
}
static
unsigned long
find_bincl(
unsigned long sum,
const char* path)
{
unsigned long i;
for(i = 0; i < bincl_entries_used; i++){
if(bincl_entries[i].sum == sum &&
strcmp(bincl_entries[i].path, path) == 0){
return(bincl_entries[i].stroffset);
}
}
return(0);
}
static void
add_dwarf_map_entry(struct nlist ** nlist, unsigned long *output_nsyms,
int32_t n_strx, uint8_t n_type, uint8_t n_sect,
int16_t n_desc, uint32_t n_value)
{
(*nlist)->n_un.n_strx = n_strx;
(*nlist)->n_type = n_type;
(*nlist)->n_sect = n_sect;
(*nlist)->n_desc = n_desc;
(*nlist)->n_value = n_value;
(*nlist)++;
(*output_nsyms)++;
}
static void
add_dwarf_map_for_sym(const struct nlist * sym,
size_t i, const size_t * debug_ptr, uint32_t n_strx,
uint16_t old_sect,
struct nlist ** nlist, unsigned long *output_nsyms)
{
size_t j;
if ((sym->n_type & (N_TYPE | N_STAB)) != N_SECT
&& ((sym->n_type & (N_TYPE | N_STAB)) != N_UNDF
|| sym->n_value == 0))
return;
if ((sym->n_type & (N_TYPE | N_STAB)) == N_SECT
&& old_sect != NO_SECT
&& (cur_obj->section_maps[old_sect - 1].s->flags &
S_ATTR_STRIP_STATIC_SYMS))
return;
if (! debug_ptr || *debug_ptr != i)
{
if (sym->n_type & N_EXT)
add_dwarf_map_entry (nlist, output_nsyms, n_strx, N_GSYM, 0, 0, 0);
else
add_dwarf_map_entry (nlist, output_nsyms,
sym->n_un.n_strx, N_STSYM,
sym->n_sect, 0, sym->n_value);
return;
}
add_dwarf_map_entry (nlist, output_nsyms,
0, N_BNSYM, sym->n_sect, 0, sym->n_value);
add_dwarf_map_entry (nlist, output_nsyms,
n_strx, N_FUN, sym->n_sect, 0, sym->n_value);
for (j = 2; debug_ptr[j] & 0x80000000; j++)
add_dwarf_map_entry (nlist, output_nsyms,
(cur_obj->dwarf_paths[debug_ptr[j] & 0x7fffffff]
- output_addr
- output_symtab_info.symtab_command.stroff),
N_SOL, 0, 0, 0);
add_dwarf_map_entry (nlist, output_nsyms, 0, N_FUN, 0, 0, debug_ptr[1]);
add_dwarf_map_entry (nlist, output_nsyms, 0, N_ENSYM,
sym->n_sect, 0, sym->n_value);
}
__private_extern__
void
output_local_symbols(void)
{
unsigned long i, flush_symbol_offset, output_nsyms, flush_string_offset,
start_string_size, mtime, stroff_for_N_OSO;
long output_strlen;
struct nlist *object_symbols, *nlist;
char *object_strings, *string;
struct localsym_block *localsym_block;
size_t * debug_ptr;
if(strip_level == STRIP_ALL)
return;
if(cur_obj->symtab == NULL)
return;
if(cur_obj == base_obj && strip_base_symbols == TRUE)
return;
#ifdef RLD
if(cur_obj->set_num != cur_set)
return;
#endif
object_symbols = (struct nlist *)(cur_obj->obj_addr +
cur_obj->symtab->symoff);
object_strings = (char *)(cur_obj->obj_addr + cur_obj->symtab->stroff);
flush_symbol_offset = output_symtab_info.symtab_command.symoff +
cur_obj->ilocalsym * sizeof(struct nlist);
flush_string_offset = output_symtab_info.symtab_command.stroff +
output_symtab_info.output_local_strsize;
start_string_size = output_symtab_info.output_local_strsize;
output_nsyms = 0;
stroff_for_N_OSO = 0;
nlist = (struct nlist *)(output_addr + flush_symbol_offset);
if(sect_object_symbols.ms != NULL){
for(i = 0; i < cur_obj->nsection_maps; i++){
if(sect_object_symbols.ms ==
cur_obj->section_maps[i].output_section){
nlist->n_value =
cur_obj->section_maps[i].output_section->s.addr +
cur_obj->section_maps[i].offset;
nlist->n_sect =
cur_obj->section_maps[i].output_section->output_sectnum;
nlist->n_type = N_SECT;
nlist->n_desc = 0;
nlist->n_un.n_strx = output_symtab_info.
output_local_strsize;
string = output_addr +
output_symtab_info.symtab_command.stroff +
output_symtab_info.output_local_strsize;
if(cur_obj->ar_hdr == NULL){
strcpy(string, cur_obj->file_name);
output_symtab_info.output_local_strsize +=
strlen(cur_obj->file_name) + 1;
}
else{
strncpy(string, cur_obj->ar_name,cur_obj->ar_name_size);
string[cur_obj->ar_name_size] = '\0';
output_symtab_info.output_local_strsize +=
cur_obj->ar_name_size + 1;
}
nlist++;
output_nsyms++;
break;
}
}
}
if(cur_obj->dwarf_name){
size_t len = strlen (cur_obj->dwarf_name) + 1;
char * strbase = (output_addr
+ output_symtab_info.symtab_command.stroff);
if (cur_obj->dwarf_comp_dir){
size_t len = strlen (cur_obj->dwarf_comp_dir);
add_dwarf_map_entry (&nlist, &output_nsyms,
output_symtab_info.output_local_strsize,
N_SO, 0, 0, 0);
memcpy (strbase + output_symtab_info.output_local_strsize,
cur_obj->dwarf_comp_dir, len);
output_symtab_info.output_local_strsize += len + 2;
strbase[output_symtab_info.output_local_strsize - 2] = '/';
strbase[output_symtab_info.output_local_strsize - 1] = 0;
}
add_dwarf_map_entry (&nlist, &output_nsyms,
output_symtab_info.output_local_strsize,
N_SO, 0, 0, 0);
memcpy (strbase + output_symtab_info.output_local_strsize,
cur_obj->dwarf_name, len);
output_symtab_info.output_local_strsize += len;
get_stroff_and_mtime_for_N_OSO(&stroff_for_N_OSO, &mtime);
add_dwarf_map_entry (&nlist, &output_nsyms,
stroff_for_N_OSO, N_OSO, 0, 1, mtime);
for (i = 0; i < cur_obj->dwarf_num_paths; i++)
if (cur_obj->dwarf_paths[i]){
char * st = strbase + output_symtab_info.output_local_strsize;
size_t len = strlen (cur_obj->dwarf_paths[i]) + 1;
output_symtab_info.output_local_strsize += len;
memcpy (st, cur_obj->dwarf_paths[i], len);
cur_obj->dwarf_paths[i] = st;
}
}
localsym_block = cur_obj->localsym_blocks;
debug_ptr = cur_obj->dwarf_source_data;
for(i = 0; i < cur_obj->symtab->nsyms; i++){
if (debug_ptr && *debug_ptr < i) {
for (debug_ptr += 2; *debug_ptr & 0x80000000; debug_ptr++) ;
}
if(localsym_block != NULL && localsym_block->index == i){
if(localsym_block->state == EXCLUDED_INCLUDE ||
localsym_block->state == BEGIN_INCLUDE){
*nlist = object_symbols[i];
if(localsym_block->state == EXCLUDED_INCLUDE)
nlist->n_type = N_EXCL;
nlist->n_value = localsym_block->sum;
if(object_symbols[i].n_un.n_strx != 0){
int doCopy = 1;
nlist->n_un.n_strx = find_bincl(nlist->n_value,
object_strings + object_symbols[i].n_un.n_strx);
if(nlist->n_un.n_strx != 0){
if(nlist->n_type == N_EXCL){
doCopy = 0;
}
}
else if(nlist->n_type == N_BINCL){
record_bincl(nlist->n_value,
object_strings +
object_symbols[i].n_un.n_strx,
output_symtab_info.output_local_strsize);
}
if(doCopy){
nlist->n_un.n_strx = output_symtab_info.
output_local_strsize;
string = output_addr +
output_symtab_info.symtab_command.stroff +
output_symtab_info.output_local_strsize;
strcpy(string,
object_strings +
object_symbols[i].n_un.n_strx);
output_symtab_info.output_local_strsize +=
strlen(object_strings +
object_symbols[i].n_un.n_strx) + 1;
}
}
output_nsyms++;
nlist++;
}
i += localsym_block->count - 1;
localsym_block = localsym_block->next;
continue;
}
if (cur_obj->dwarf_name
&& (((object_symbols[i].n_type & (N_TYPE | N_STAB | N_EXT))
== (N_SECT | N_EXT))
|| (((object_symbols[i].n_type & (N_TYPE | N_STAB | N_EXT))
== (N_UNDF | N_EXT))
&& object_symbols[i].n_value != 0))){
struct merged_symbol *hash_pointer;
hash_pointer = lookup_symbol(object_strings
+ object_symbols[i].n_un.n_strx);
if (hash_pointer->name_len != 0
&& (! dead_strip || hash_pointer->live)
&& (object_symbols[i].n_sect == NO_SECT
|| hash_pointer->definition_object == cur_obj)){
unsigned long symbol_index;
symbol_index = (output_symtab_info.output_merged_strsize
+ (merged_symbol_string_index
(hash_pointer->nlist.n_un.n_name)));
add_dwarf_map_for_sym (&hash_pointer->nlist, i, debug_ptr,
symbol_index, object_symbols[i].n_sect,
&nlist, &output_nsyms);
}
}
output_strlen = -1;
if((object_symbols[i].n_type & N_EXT) == 0 &&
is_output_local_symbol(object_symbols[i].n_type,
object_symbols[i].n_sect, object_symbols[i].n_desc, cur_obj,
object_symbols[i].n_un.n_strx == 0 ? "" :
object_strings + object_symbols[i].n_un.n_strx,
(unsigned long *)&output_strlen)){
if(output_strlen == -1)
output_strlen = object_symbols[i].n_un.n_strx == 0 ? 0:
strlen(object_strings +
object_symbols[i].n_un.n_strx);
*nlist = object_symbols[i];
relocate_symbol(nlist, cur_obj);
if(save_reloc == FALSE &&
(nlist->n_type & N_TYPE) == N_SECT &&
(nlist->n_type & N_STAB) == 0)
nlist->n_desc = nlist->n_desc & ~(N_NO_DEAD_STRIP);
#ifdef RLD
if(nlist->n_sect != NO_SECT)
nlist->n_sect = cur_obj->section_maps[nlist->n_sect - 1].
output_section->output_sectnum;
#endif
if(nlist->n_type == N_OSO){
if(nlist->n_desc == 1){
if(object_symbols[i].n_un.n_strx != 0 &&
object_strings[object_symbols[i].n_un.n_strx] ==
'\0'){
get_stroff_and_mtime_for_N_OSO(
&stroff_for_N_OSO, &mtime);
nlist->n_un.n_strx = stroff_for_N_OSO;
nlist->n_value = mtime;
}
else{
goto copy_string_to_output_file;
}
}
else if(nlist->n_desc == 0){
if(strip_level == STRIP_MIN_DEBUG){
get_stroff_and_mtime_for_N_OSO(
&stroff_for_N_OSO, &mtime);
nlist->n_un.n_strx = stroff_for_N_OSO;
nlist->n_value = mtime;
}
else{
output_strlen = 0;
goto copy_string_to_output_file;
}
}
else{
goto copy_string_to_output_file;
}
}
else{
copy_string_to_output_file:
if(object_symbols[i].n_un.n_strx != 0){
nlist->n_un.n_strx = output_symtab_info.
output_local_strsize;
string = output_addr +
output_symtab_info.symtab_command.stroff +
output_symtab_info.output_local_strsize;
strncpy(string,
object_strings + object_symbols[i].n_un.n_strx,
output_strlen);
output_symtab_info.output_local_strsize +=
output_strlen + 1;
}
}
output_nsyms++;
nlist++;
if(cur_obj->dwarf_name)
add_dwarf_map_for_sym (nlist - 1, i, debug_ptr,
nlist[-1].n_un.n_strx,
object_symbols[i].n_sect,
&nlist, &output_nsyms);
}
}
if(cur_obj->dwarf_name)
add_dwarf_map_entry (&nlist, &output_nsyms, 0, N_SO, 0, 0, 0);
if(host_byte_sex != target_byte_sex){
nlist = (struct nlist *)(output_addr + flush_symbol_offset);
swap_nlist(nlist, output_nsyms, target_byte_sex);
}
#ifndef RLD
output_flush(flush_symbol_offset, output_nsyms * sizeof(struct nlist));
output_flush(flush_string_offset, output_symtab_info.
output_local_strsize -
start_string_size);
#endif
if(output_nsyms != cur_obj->nlocalsym)
fatal("internal error: output_local_symbols() inconsistent local "
"symbol count");
}
static
void
get_stroff_and_mtime_for_N_OSO(
unsigned long *stroff_for_N_OSO,
unsigned long *mtime)
{
char *string, *endptr;
#if !(defined(KLD) && defined(__STATIC__))
struct stat stat_buf;
#endif
*stroff_for_N_OSO = output_symtab_info.output_local_strsize;
string = output_addr +
output_symtab_info.symtab_command.stroff +
output_symtab_info.output_local_strsize;
strcpy(string, cur_obj->resolved_path);
output_symtab_info.output_local_strsize +=
cur_obj->resolved_path_len + 1;
if(cur_obj->ar_hdr != NULL)
*mtime = strtol(cur_obj->ar_hdr->ar_date, &endptr, 10);
else{
#if !(defined(KLD) && defined(__STATIC__))
if(stat(cur_obj->file_name, &stat_buf) != -1)
*mtime = stat_buf.st_mtime;
else
#endif
*mtime = 0;
}
}
__private_extern__
unsigned long
local_symbol_output_index(
struct object_file *obj,
unsigned long index)
{
unsigned long i, output_nsyms, output_strlen;
struct nlist *object_symbols;
char *object_strings;
struct localsym_block *localsym_block;
object_symbols = (struct nlist *)(obj->obj_addr +
obj->symtab->symoff);
object_strings = (char *)(obj->obj_addr + obj->symtab->stroff);
output_nsyms = 0;
if(sect_object_symbols.ms != NULL){
for(i = 0; i < obj->nsection_maps; i++){
if(sect_object_symbols.ms ==
obj->section_maps[i].output_section){
output_nsyms++;
break;
}
}
}
localsym_block = obj->localsym_blocks;
for(i = 0; i < obj->symtab->nsyms; i++){
if(localsym_block != NULL && localsym_block->index == i){
i += localsym_block->count - 1;
localsym_block = localsym_block->next;
continue;
}
if((object_symbols[i].n_type & N_EXT) == 0 &&
is_output_local_symbol(object_symbols[i].n_type,
object_symbols[i].n_sect, object_symbols[i].n_desc, obj,
object_symbols[i].n_un.n_strx == 0 ? "" :
object_strings + object_symbols[i].n_un.n_strx,
&output_strlen)){
if(i == index)
return(obj->ilocalsym + output_nsyms);
output_nsyms++;
}
}
fatal("internal error: local_symbol_output_index() could not determine "
"output_index");
return(0);
}
__private_extern__
void
set_merged_string_block_indexes(
void)
{
unsigned long index;
struct string_block **q, *string_block;
index = 0;
for(q = &(merged_string_blocks); *q; q = &(string_block->next)){
string_block = *q;
if(strip_base_symbols == TRUE && string_block->base_strings == TRUE)
continue;
if(string_block->dylib_strings == TRUE)
continue;
#ifdef RLD
if(string_block->set_num != cur_set)
continue;
#endif
string_block->index = index,
index += string_block->used;
}
}
__private_extern__
void
output_merged_symbols(void)
{
unsigned long i, j, flush_symbol_offset,
flush_string_offset, start_string_size;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol, *indr_symbol;
struct string_block **q, *string_block;
struct nlist *nlist;
struct twolevel_hint *hint;
if(strip_level == STRIP_ALL)
return;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->nlist.n_type == (N_EXT | N_INDR)){
indr_symbol = NULL;
for(j = 0; j < nindr_symbol_pairs; j++){
if(indr_symbol_pairs[j].merged_symbol == merged_symbol)
indr_symbol = indr_symbol_pairs[j].indr_symbol;
}
if(indr_symbol == NULL)
indr_symbol = (struct merged_symbol *)
(merged_symbol->nlist.n_value);
if(indr_symbol->nlist.n_type != (N_EXT | N_UNDF) &&
indr_symbol->nlist.n_type != (N_EXT | N_PBUD) &&
(filetype != MH_DYLIB ||
(filetype == MH_DYLIB && multi_module_dylib == FALSE) ||
merged_symbol->definition_object ==
indr_symbol->definition_object)){
merged_symbol->nlist.n_type = indr_symbol->nlist.n_type;
merged_symbol->nlist.n_sect = indr_symbol->nlist.n_sect;
merged_symbol->nlist.n_desc = indr_symbol->nlist.n_desc;
merged_symbol->nlist.n_value =
indr_symbol->nlist.n_value;
}
else{
merged_symbol->nlist.n_value =
output_symtab_info.output_merged_strsize +
merged_symbol_string_index(
indr_symbol->nlist.n_un.n_name);
}
}
}
}
if(nmerged_private_symbols != 0 &&
keep_private_externs == FALSE &&
(strip_level != STRIP_NONGLOBALS ||
(filetype == MH_DYLIB && multi_module_dylib == TRUE)) ){
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
if(strip_base_symbols == TRUE &&
merged_symbol->definition_object == base_obj)
continue;
#ifdef RLD
if(merged_symbol->definition_object->set_num != cur_set)
continue;
#endif
if(strip_level == STRIP_DYNAMIC_EXECUTABLE &&
(((merged_symbol->nlist.n_desc &
REFERENCED_DYNAMICALLY) != REFERENCED_DYNAMICALLY) ||
(merged_symbol->nlist.n_type & N_PEXT) == N_PEXT))
continue;
if(dead_strip == TRUE && merged_symbol->live == FALSE)
continue;
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT &&
(merged_symbol->nlist.n_type & N_TYPE) != N_UNDF){
flush_symbol_offset =
output_symtab_info.symtab_command.symoff +
merged_symbol->definition_object->iprivatesym *
sizeof(struct nlist);
merged_symbol->definition_object->iprivatesym++;
nlist = (struct nlist *)(output_addr +
flush_symbol_offset);
*nlist = merged_symbol->nlist;
nlist->n_desc = nlist->n_desc & ~(N_WEAK_REF);
if(save_reloc == FALSE)
nlist->n_desc = nlist->n_desc & ~(N_NO_DEAD_STRIP);
nlist->n_un.n_strx = output_symtab_info.
output_merged_strsize +
merged_symbol_string_index(
merged_symbol->nlist.n_un.n_name);
nlist->n_type &= ~(N_EXT);
#ifdef RLD
if(nlist->n_sect != NO_SECT)
nlist->n_sect = merged_symbol->definition_object->
section_maps[nlist->n_sect - 1].
output_section->output_sectnum;
#endif
if(host_byte_sex != target_byte_sex)
swap_nlist(nlist, 1, target_byte_sex);
#ifndef RLD
output_flush(flush_symbol_offset, sizeof(struct nlist));
#endif
}
}
}
}
flush_symbol_offset = output_symtab_info.symtab_command.symoff +
output_dysymtab_info.dysymtab_command.iextdefsym *
sizeof(struct nlist);
nlist = (struct nlist *)(output_addr + flush_symbol_offset);
for(i = 0; i < output_dysymtab_info.dysymtab_command.nextdefsym; i++){
merged_symbol = extdefsyms_order[i];
*nlist = merged_symbol->nlist;
nlist->n_desc = nlist->n_desc & ~(N_WEAK_REF);
if(save_reloc == FALSE)
nlist->n_desc = nlist->n_desc & ~(N_NO_DEAD_STRIP);
nlist->n_un.n_strx = output_symtab_info.output_merged_strsize +
merged_symbol_string_index(
merged_symbol->nlist.n_un.n_name);
if(nlist->n_desc & N_WEAK_DEF)
output_mach_header.flags |= MH_WEAK_DEFINES | MH_BINDS_TO_WEAK;
#ifdef RLD
if(nlist->n_sect != NO_SECT)
nlist->n_sect = merged_symbol->definition_object->
section_maps[nlist->n_sect - 1].
output_section->output_sectnum;
#endif
nlist++;
}
if(host_byte_sex != target_byte_sex){
nlist = (struct nlist *)(output_addr + flush_symbol_offset);
swap_nlist(nlist, output_dysymtab_info.dysymtab_command.nextdefsym,
target_byte_sex);
}
#ifndef RLD
output_flush(flush_symbol_offset,
output_dysymtab_info.dysymtab_command.nextdefsym *
sizeof(struct nlist));
#endif
if(extdefsyms_order != NULL){
free(extdefsyms_order);
extdefsyms_order = NULL;
}
flush_symbol_offset = output_symtab_info.symtab_command.symoff +
output_dysymtab_info.dysymtab_command.iundefsym *
sizeof(struct nlist);
nlist = (struct nlist *)(output_addr + flush_symbol_offset);
for(i = 0; i < output_dysymtab_info.dysymtab_command.nundefsym; i++){
merged_symbol = undefsyms_order[i];
*nlist = merged_symbol->nlist;
nlist->n_desc = nlist->n_desc & ~(N_WEAK_DEF & N_NO_DEAD_STRIP);
if(merged_symbol->defined_in_dylib == TRUE &&
merged_symbol->weak_def_in_dylib == TRUE){
nlist->n_desc |= N_REF_TO_WEAK;
output_mach_header.flags |= MH_BINDS_TO_WEAK;
}
nlist->n_un.n_strx = output_symtab_info.output_merged_strsize +
merged_symbol_string_index(
merged_symbol->nlist.n_un.n_name);
nlist++;
}
if(host_byte_sex != target_byte_sex){
nlist = (struct nlist *)(output_addr + flush_symbol_offset);
swap_nlist(nlist, output_dysymtab_info.dysymtab_command.nundefsym,
target_byte_sex);
}
#ifndef RLD
output_flush(flush_symbol_offset,
output_dysymtab_info.dysymtab_command.nundefsym *
sizeof(struct nlist));
#endif
flush_string_offset = output_symtab_info.symtab_command.stroff +
output_symtab_info.output_merged_strsize;
start_string_size = output_symtab_info.output_merged_strsize;
for(q = &(merged_string_blocks); *q; q = &(string_block->next)){
string_block = *q;
if(strip_base_symbols == TRUE && string_block->base_strings == TRUE)
continue;
if(string_block->dylib_strings == TRUE)
continue;
#ifdef RLD
if(string_block->set_num != cur_set)
continue;
#endif
memcpy(output_addr + output_symtab_info.symtab_command.stroff +
output_symtab_info.output_merged_strsize,
string_block->strings,
string_block->used);
output_symtab_info.output_merged_strsize += string_block->used;
}
#ifndef RLD
output_flush(flush_string_offset, output_symtab_info.
output_merged_strsize -
start_string_size);
#endif
hint = (struct twolevel_hint *)(output_addr +
output_hints_info.twolevel_hints_command.offset);
if(output_for_dyld && twolevel_namespace == TRUE &&
twolevel_namespace_hints == TRUE){
for(i = 0; i < output_dysymtab_info.dysymtab_command.nundefsym;i++){
merged_symbol = undefsyms_order[i];
hint->isub_image = merged_symbol->definition_object->isub_image;
hint->itoc = merged_symbol->itoc;
hint++;
}
if(host_byte_sex != target_byte_sex){
hint = (struct twolevel_hint *)(output_addr +
output_hints_info.twolevel_hints_command.offset);
swap_twolevel_hint(hint,
output_dysymtab_info.dysymtab_command.nundefsym,
target_byte_sex);
}
#ifndef RLD
output_flush(output_hints_info.twolevel_hints_command.offset,
output_dysymtab_info.dysymtab_command.nundefsym *
sizeof(struct twolevel_hint));
#endif
}
if(undefsyms_order != NULL){
free(undefsyms_order);
undefsyms_order = NULL;
}
}
#if defined(RLD) && !defined(SA_RLD)
__private_extern__
void
output_rld_symfile_merged_symbols(
void)
{
struct nlist *nlist;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
unsigned long string_offset;
struct string_block **q, *string_block;
unsigned long i;
nlist = (struct nlist *)(output_addr +
output_symtab_info.symtab_command.symoff);
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->definition_object->set_num != cur_set)
continue;
*nlist = merged_symbol->nlist;
nlist->n_un.n_strx = output_symtab_info.output_merged_strsize +
merged_symbol_string_index(
merged_symbol->nlist.n_un.n_name);
nlist->n_sect = NO_SECT;
nlist->n_type = N_ABS | N_EXT;
nlist++;
}
}
string_offset = output_symtab_info.symtab_command.stroff +
output_symtab_info.output_merged_strsize;
for(q = &(merged_string_blocks); *q; q = &(string_block->next)){
string_block = *q;
if(string_block->set_num != cur_set)
continue;
memcpy(output_addr + output_symtab_info.symtab_command.stroff +
output_symtab_info.output_merged_strsize,
string_block->strings,
string_block->used);
output_symtab_info.output_merged_strsize += string_block->used;
}
}
#endif
static
unsigned long
merged_symbol_string_index(
char *symbol_name)
{
#ifndef RLD
static struct string_block *string_block = NULL;
if(string_block == NULL)
string_block = merged_string_blocks;
if(symbol_name < string_block->strings ||
symbol_name >= string_block->strings + string_block->used)
string_block = get_string_block(symbol_name);
#else
struct string_block *string_block;
string_block = get_string_block(symbol_name);
#endif
return(string_block->index + (symbol_name - string_block->strings));
}
static
struct string_block *
get_string_block(
char *symbol_name)
{
struct string_block **p, *string_block;
for(p = &(merged_string_blocks); *p; p = &(string_block->next)){
string_block = *p;
if(symbol_name >= string_block->strings &&
symbol_name < string_block->strings + string_block->used)
return(string_block);
}
fatal("internal error: get_string_block() called with symbol_name (%s) "
"not in the string blocks", symbol_name);
return(NULL);
}
__private_extern__
void
process_undefineds(
void)
{
unsigned long i, j, Ycount, errors_save;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
enum bool printed_undef, allowed_undef, prebound_undef;
struct object_list *object_list, **q;
#ifndef RLD
unsigned long k;
struct nlist *object_symbols;
struct object_file *obj;
struct undefined_list *undefined, *prevs;
char *short_name;
struct dynamic_library *dep, *lib, *prev_lib;
unsigned long library_ordinal;
enum bool reported, weak_ref_warning;
#endif
errors_save = 0;
printed_undef = FALSE;
prebound_undef = FALSE;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
merged_symbol->nlist.n_value == 0){
if(dead_strip == TRUE &&
merged_symbol->live == FALSE)
continue;
if(prebinding == TRUE){
if(ld_trace_prebinding_disabled == TRUE)
print("[Logging for XBS] prebinding"
" disabled for %s because of undefined "
"symbols\n", final_output != NULL ?
final_output : outputfile);
warning("prebinding disabled because of undefined "
"symbols");
prebinding = FALSE;
prebound_undef = TRUE;
}
allowed_undef = FALSE;
if(nundef_syms != 0){
for(j = 0; j < nundef_syms; j++){
if(strcmp(undef_syms[j],
merged_symbol->nlist.n_un.n_name) == 0){
allowed_undef = TRUE;
break;
}
}
}
if(allowed_undef == FALSE)
noundefs = FALSE;
if(save_reloc == FALSE &&
(undefined_flag == UNDEFINED_ERROR ||
undefined_flag == UNDEFINED_WARNING)){
if(allowed_undef == FALSE || prebound_undef == TRUE){
if(printed_undef == FALSE){
if(undefined_flag == UNDEFINED_WARNING)
warning("undefined symbols:");
else{
if(allowed_undef == TRUE &&
prebound_undef == TRUE)
errors_save = errors;
error("Undefined symbols:");
if(allowed_undef == TRUE &&
prebound_undef == TRUE)
errors = errors_save;
}
printed_undef = TRUE;
}
else if(errors == 0 &&
undefined_flag == UNDEFINED_ERROR &&
allowed_undef == FALSE){
errors = 1;
}
print("%s\n", merged_symbol->nlist.n_un.n_name);
}
}
else if(save_reloc == FALSE &&
undefined_flag == UNDEFINED_DYNAMIC_LOOKUP &&
twolevel_namespace == TRUE){
SET_LIBRARY_ORDINAL(merged_symbol->nlist.n_desc,
DYNAMIC_LOOKUP_ORDINAL);
}
}
#ifndef RLD
else {
if(save_reloc == FALSE &&
twolevel_namespace == TRUE &&
merged_symbol->defined_in_dylib == TRUE &&
merged_symbol->referenced_in_non_dylib == TRUE &&
merged_symbol->definition_library->
definition_obj->library_ordinal == 0 &&
merged_symbol->definition_library->
indirect_twolevel_ref_flagged == FALSE){
obj = cur_obj;
cur_obj = merged_symbol->non_dylib_referenced_obj;
error_with_cur_obj("illegal reference to symbol: %s "
"defined in indirectly referenced dynamic library "
"%s", merged_symbol->nlist.n_un.n_name,
merged_symbol->definition_library->dylib_file
!= NULL ?
merged_symbol->definition_library->file_name :
merged_symbol->definition_library->dylib_name);
cur_obj = obj;
merged_symbol->definition_library->
indirect_twolevel_ref_flagged = TRUE;
}
}
#endif
}
}
#ifndef RLD
if(macosx_deployment_target.major <= 1){
weak_ref_warning = FALSE;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(((merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
merged_symbol->nlist.n_value == 0) ||
(merged_symbol->nlist.n_type & N_TYPE) == N_PBUD) &&
(merged_symbol->nlist.n_desc & N_WEAK_REF) ==
N_WEAK_REF){
if(weak_ref_warning == FALSE){
warning("weak symbol references not set in output "
"with MACOSX_DEPLOYMENT_TARGET environment "
"variable set to: %s",
macosx_deployment_target.name);
warning("weak referenced symbols:");
weak_ref_warning = TRUE;
}
merged_symbol->nlist.n_desc &= ~(N_WEAK_REF);
print("%s\n", merged_symbol->nlist.n_un.n_name);
}
}
}
}
else{
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->weak_reference_mismatch == TRUE &&
((merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
merged_symbol->nlist.n_value == 0) ||
(merged_symbol->nlist.n_type & N_TYPE) == N_PBUD) &&
(merged_symbol->defined_in_dylib == FALSE ||
merged_symbol->definition_library->
force_weak_dylib == FALSE)){
error("mismatching weak references for symbol: %s",
merged_symbol->nlist.n_un.n_name);
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(j = 0; j < object_list->used; j++){
cur_obj = &(object_list->object_files[j]);
if(cur_obj->dylib && cur_obj->dylib_module ==
NULL)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
for(k = 0; k < cur_obj->nundefineds; k++){
if(merged_symbol == cur_obj->
undefined_maps[k].merged_symbol){
print_obj_name(cur_obj);
object_symbols = (struct nlist *)
(cur_obj->obj_addr +
cur_obj->symtab->symoff);
if((object_symbols[
cur_obj->undefined_maps[
k].index].n_desc & N_WEAK_REF) ==
N_WEAK_REF)
print("reference to weak %s\n",
merged_symbol->nlist.n_un.n_name);
else
print("reference to non-weak %s\n",
merged_symbol->nlist.n_un.n_name);
}
}
}
}
}
}
}
}
#endif
#ifndef RLD
lib = NULL;
prev_lib = NULL;
for(undefined = undefined_list.next;
undefined != &undefined_list;
undefined = undefined->next){
if(undefined->merged_symbol->twolevel_reference == TRUE){
library_ordinal = GET_LIBRARY_ORDINAL(
undefined->merged_symbol->nlist.n_desc);
if(library_ordinal == SELF_LIBRARY_ORDINAL)
lib = undefined->merged_symbol->referencing_library;
else if(library_ordinal == DYNAMIC_LOOKUP_ORDINAL)
fatal("internal error: process_undefineds() 1 with a "
"merged_symbol (%s) on the undefined list with "
"twolevel_reference == TRUE and library_ordinal == "
"DYNAMIC_LOOKUP_ORDINAL", undefined->merged_symbol->
nlist.n_un.n_name);
else
lib = undefined->merged_symbol->referencing_library->
dependent_images[library_ordinal - 1];
reported = FALSE;
for(prevs = undefined_list.next;
prevs != undefined;
prevs = prevs->next){
if(prevs->merged_symbol->twolevel_reference == FALSE)
continue;
library_ordinal = GET_LIBRARY_ORDINAL(
prevs->merged_symbol->nlist.n_desc);
if(library_ordinal == SELF_LIBRARY_ORDINAL)
prev_lib = prevs->merged_symbol->referencing_library;
else if(library_ordinal == DYNAMIC_LOOKUP_ORDINAL)
fatal("internal error: process_undefineds() 2 with a "
"merged_symbol (%s) on the undefined list with "
"twolevel_reference == TRUE and library_ordinal "
"== DYNAMIC_LOOKUP_ORDINAL",
prevs->merged_symbol->nlist.n_un.n_name);
else
prev_lib = prevs->merged_symbol->referencing_library->
dependent_images[library_ordinal - 1];
if(lib == prev_lib &&
strcmp(undefined->merged_symbol->nlist.n_un.n_name,
prevs->merged_symbol->nlist.n_un.n_name) == 0){
reported = TRUE;
break;
}
}
if(reported == FALSE){
if(printed_undef == FALSE){
error("Undefined symbols:");
printed_undef = TRUE;
}
print("%s ", undefined->merged_symbol->nlist.n_un.n_name);
dep = undefined->merged_symbol->referencing_library;
if(dep->umbrella_name != NULL)
short_name = dep->umbrella_name;
else if(dep->library_name != NULL)
short_name = dep->library_name;
else
short_name = dep->dylib_name;
print("referenced from %s ", short_name);
if(lib->umbrella_name != NULL)
short_name = lib->umbrella_name;
else if(lib->library_name != NULL)
short_name = lib->library_name;
else
short_name = lib->dylib_name;
print("expected to be defined in %s\n", short_name);
}
}
}
#endif
if(printed_undef == TRUE && Yflag != 0){
Ycount = 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->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
for(j = 0; j < cur_obj->nundefineds; j++){
merged_symbol =
cur_obj->undefined_maps[j].merged_symbol;
if(merged_symbol == NULL ||
merged_symbol->twolevel_reference == TRUE)
continue;
if(merged_symbol->nlist.n_type == (N_EXT|N_UNDF) &&
merged_symbol->nlist.n_value == 0){
if(Ycount >= Yflag){
print("more references to undefined "
"symbols ...\n");
goto done;
}
print_obj_name(cur_obj);
print("%sreference to undefined %s",
merged_symbol->nlist.n_desc & N_WEAK_REF ?
"weak " : "",
merged_symbol->nlist.n_un.n_name);
#ifndef RLD
library_ordinal = GET_LIBRARY_ORDINAL(
merged_symbol->nlist.n_desc);
if(merged_symbol->twolevel_reference == TRUE &&
library_ordinal != DYNAMIC_LOOKUP_ORDINAL){
if(library_ordinal == SELF_LIBRARY_ORDINAL)
lib = merged_symbol->referencing_library;
else
lib = merged_symbol->referencing_library->
dependent_images[library_ordinal - 1];
if(lib->umbrella_name != NULL)
short_name = lib->umbrella_name;
else if(lib->library_name != NULL)
short_name = lib->library_name;
else
short_name = lib->dylib_name;
print(" expected to be defined in %s\n",
short_name);
}
else
#endif
print("\n");
Ycount++;
}
}
}
}
}
done:
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->referenced_in_non_dylib == FALSE)
nmerged_symbols_referenced_only_from_dylibs++;
}
}
}
#ifndef RLD
__private_extern__
void
reset_prebound_undefines(
void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol, *indr_symbol;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if((merged_symbol->nlist.n_type & N_TYPE) == N_PBUD){
if(prebinding == FALSE){
merged_symbol->nlist.n_type = N_UNDF | N_EXT;
merged_symbol->nlist.n_value = 0;
merged_symbol->nlist.n_desc &= ~REFERENCED_DYNAMICALLY;
}
}
else if(merged_symbol->nlist.n_type == (N_EXT | N_INDR) &&
merged_symbol->defined_in_dylib == TRUE){
if(prebinding == FALSE){
merged_symbol->nlist.n_type = N_UNDF | N_EXT;
merged_symbol->nlist.n_value = 0;
merged_symbol->nlist.n_desc &= ~REFERENCED_DYNAMICALLY;
}
else{
indr_symbol = (struct merged_symbol *)
(merged_symbol->nlist.n_value);
if(indr_symbol->nlist.n_type != (N_EXT | N_UNDF)){
merged_symbol->nlist.n_type = N_PBUD | N_EXT;
merged_symbol->nlist.n_sect = NO_SECT;
merged_symbol->nlist.n_value =
indr_symbol->nlist.n_value;
}
else{
merged_symbol->nlist.n_type = N_UNDF | N_EXT;
merged_symbol->nlist.n_value = 0;
merged_symbol->nlist.n_desc &=
~REFERENCED_DYNAMICALLY;
}
}
}
}
}
}
#endif
__private_extern__
void
assign_output_symbol_indexes(
void)
{
unsigned long index, i, nextdefsym, nundefsym, n_pext;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol, *indr_symbol;
struct object_list *object_list, **q;
struct object_file *last_object;
enum bool rebuild_merged_string_table;
rebuild_merged_string_table = FALSE;
if(strip_level == STRIP_ALL){
if(has_dynamic_linker_command){
strip_level = STRIP_DYNAMIC_EXECUTABLE;
merged_string_blocks = NULL;
merged_string_size = 0;
rebuild_merged_string_table = TRUE;
nstripped_merged_symbols = nstripped_merged_private_symbols;
}
else{
seglinkedit = FALSE;
return;
}
}
else if(strip_level == STRIP_NONGLOBALS &&
keep_private_externs == FALSE &&
nmerged_private_symbols != 0 &&
(filetype != MH_DYLIB || multi_module_dylib == FALSE)){
merged_string_blocks = NULL;
merged_string_size = 0;
rebuild_merged_string_table = TRUE;
}
last_object = add_last_object_file(&link_edit_common_object);
index = 0;
output_dysymtab_info.dysymtab_command.ilocalsym = index;
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->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
#ifdef RLD
if(cur_obj->set_num != cur_set)
continue;
#endif
cur_obj->ilocalsym = index;
index += cur_obj->nlocalsym;
if(keep_private_externs == FALSE){
cur_obj->iprivatesym = index;
cur_obj->cprivatesym = index;
if(strip_level != STRIP_DYNAMIC_EXECUTABLE &&
(strip_level != STRIP_NONGLOBALS ||
(filetype == MH_DYLIB && multi_module_dylib == TRUE))){
index += cur_obj->nprivatesym;
}
else{
nstripped_merged_symbols +=
cur_obj->nprivatesym;
nstripped_merged_private_symbols +=
cur_obj->nprivatesym;
}
}
}
}
if((keep_private_externs == TRUE && index != nlocal_symbols) ||
(keep_private_externs == FALSE && index != nlocal_symbols +
nmerged_private_symbols - nstripped_merged_private_symbols))
fatal("internal error: assign_output_symbol_indexes() "
"inconsistent local symbol counts");
output_dysymtab_info.dysymtab_command.nlocalsym = index;
link_edit_common_object = *last_object;
remove_last_object_file(last_object);
nundefsym = 0;
nextdefsym = 0;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
if(strip_base_symbols == TRUE &&
merged_symbol->definition_object == base_obj)
continue;
#ifdef RLD
if(merged_symbol->definition_object->set_num != cur_set)
continue;
#endif
if(strip_level != STRIP_DYNAMIC_EXECUTABLE &&
dead_strip == TRUE && merged_symbol->live == FALSE)
continue;
if((merged_symbol->nlist.n_type & N_EXT) == N_EXT &&
((merged_symbol->nlist.n_type & N_TYPE) == N_UNDF ||
(merged_symbol->nlist.n_type & N_TYPE) == N_PBUD) |
(merged_symbol->nlist.n_type == (N_EXT | N_INDR) &&
merged_symbol->defined_in_dylib == TRUE)){
if(dead_strip == FALSE || merged_symbol->live == TRUE){
nundefsym++;
if(rebuild_merged_string_table == TRUE)
merged_symbol->nlist.n_un.n_name =
enter_string(merged_symbol->nlist.n_un.n_name,
NULL);
}
else{
nstripped_merged_symbols++;
}
}
else{
if(merged_symbol->nlist.n_type == (N_EXT | N_INDR)){
indr_symbol = (struct merged_symbol *)
(merged_symbol->nlist.n_value);
n_pext = indr_symbol->nlist.n_type & N_PEXT;
}
else{
n_pext = merged_symbol->nlist.n_type & N_PEXT;
}
if(keep_private_externs == TRUE || n_pext == 0){
if(strip_level != STRIP_DYNAMIC_EXECUTABLE ||
(merged_symbol->nlist.n_desc &
REFERENCED_DYNAMICALLY) == REFERENCED_DYNAMICALLY){
nextdefsym++;
if(rebuild_merged_string_table == TRUE)
merged_symbol->nlist.n_un.n_name =
enter_string(merged_symbol->
nlist.n_un.n_name, NULL);
}
else{
nstripped_merged_symbols++;
}
}
}
}
}
undefsyms_order = allocate(nundefsym *
sizeof(struct merged_symbol *));
extdefsyms_order = allocate(nextdefsym *
sizeof(struct merged_symbol *));
nundefsym = 0;
nextdefsym = 0;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
if(strip_base_symbols == TRUE &&
merged_symbol->definition_object == base_obj)
continue;
#ifdef RLD
if(merged_symbol->definition_object->set_num != cur_set)
continue;
#endif
if(dead_strip == TRUE && merged_symbol->live == FALSE)
continue;
if(((merged_symbol->nlist.n_type & N_EXT) == N_EXT &&
((merged_symbol->nlist.n_type & N_TYPE) == N_UNDF ||
(merged_symbol->nlist.n_type & N_TYPE) == N_PBUD)) ||
(merged_symbol->nlist.n_type == (N_EXT | N_INDR) &&
merged_symbol->defined_in_dylib == TRUE))
undefsyms_order[nundefsym++] = merged_symbol;
else{
if(merged_symbol->nlist.n_type == (N_EXT | N_INDR)){
indr_symbol = (struct merged_symbol *)
(merged_symbol->nlist.n_value);
n_pext = indr_symbol->nlist.n_type & N_PEXT;
}
else{
n_pext = merged_symbol->nlist.n_type & N_PEXT;
}
if(keep_private_externs == TRUE || n_pext == 0){
if(strip_level != STRIP_DYNAMIC_EXECUTABLE ||
(merged_symbol->nlist.n_desc &
REFERENCED_DYNAMICALLY) == REFERENCED_DYNAMICALLY){
extdefsyms_order[nextdefsym++] = merged_symbol;
}
else{
if((merged_symbol->nlist.n_type & N_TYPE) == N_ABS)
merged_symbol->output_index =
INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL;
else
merged_symbol->output_index =
INDIRECT_SYMBOL_LOCAL;
}
}
}
}
}
#ifndef SA_RLD
if(filetype == MH_DYLIB)
qsort(extdefsyms_order, nextdefsym, sizeof(struct merged_symbol *),
(int (*)(const void *, const void *))qsort_by_module);
else
qsort(extdefsyms_order, nextdefsym, sizeof(struct merged_symbol *),
(int (*)(const void *, const void *))qsort_by_name);
if(bind_at_load == TRUE)
qsort(undefsyms_order, nundefsym, sizeof(struct merged_symbol **),
(int (*)(const void *, const void *))qsort_by_undef_order);
else
qsort(undefsyms_order, nundefsym, sizeof(struct merged_symbol **),
(int (*)(const void *, const void *))qsort_by_name);
#endif
output_dysymtab_info.dysymtab_command.iextdefsym = index;
output_dysymtab_info.dysymtab_command.nextdefsym = nextdefsym;
cur_obj = NULL;
for(i = 0; i < nextdefsym; i++){
if(filetype == MH_DYLIB){
if(cur_obj != extdefsyms_order[i]->definition_object){
cur_obj = extdefsyms_order[i]->definition_object;
cur_obj->iextdefsym = index;
}
}
extdefsyms_order[i]->output_index = index++;
}
output_dysymtab_info.dysymtab_command.iundefsym = index;
output_dysymtab_info.dysymtab_command.nundefsym = nundefsym;
for(i = 0; i < nundefsym; i++){
undefsyms_order[i]->output_index = index++;
}
if(twolevel_namespace == TRUE)
output_hints_info.twolevel_hints_command.nhints = nundefsym;
if(nmerged_private_symbols != 0 && keep_private_externs == FALSE){
cur_obj = NULL;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
if(strip_base_symbols == TRUE &&
merged_symbol->definition_object == base_obj)
continue;
#ifdef RLD
if(merged_symbol->definition_object->set_num != cur_set)
continue;
#endif
if(dead_strip == TRUE && merged_symbol->live == FALSE)
continue;
if(merged_symbol->nlist.n_type & N_PEXT){
merged_symbol->output_index =
merged_symbol->definition_object->cprivatesym++;
}
}
}
}
}
#ifndef SA_RLD
static
int
qsort_by_module(
const struct merged_symbol **ms1,
const struct merged_symbol **ms2)
{
return((int)((*ms1)->definition_object) -
(int)((*ms2)->definition_object));
}
static
int
qsort_by_name(
const struct merged_symbol **ms1,
const struct merged_symbol **ms2)
{
return(strcmp((*ms1)->nlist.n_un.n_name, (*ms2)->nlist.n_un.n_name));
}
static
int
qsort_by_undef_order(
const struct merged_symbol **ms1,
const struct merged_symbol **ms2)
{
return(((*ms1)->undef_order - (*ms2)->undef_order));
}
__private_extern__
unsigned long
merged_symbol_output_index(
struct merged_symbol *merged_symbol)
{
return(merged_symbol->output_index);
}
#endif
#ifndef RLD
char *dylib_single_module_name;
__private_extern__
void
layout_dylib_tables(
void)
{
unsigned long i, j, flags;
struct merged_symbol *merged_symbol;
struct object_list *object_list, **q;
char *p;
if(multi_module_dylib == TRUE){
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->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
for(j = 0; j < cur_obj->nrefsym; j++){
merged_symbol =
cur_obj->reference_maps[j].merged_symbol;
if(merged_symbol->nlist.n_type & N_PEXT){
flags = cur_obj->reference_maps[j].flags;
if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
cur_obj->reference_maps[j].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
else if(flags == REFERENCE_FLAG_UNDEFINED_LAZY)
cur_obj->reference_maps[j].flags =
REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
}
else{
flags = cur_obj->reference_maps[j].flags;
if(flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)
cur_obj->reference_maps[j].flags =
REFERENCE_FLAG_UNDEFINED_NON_LAZY;
else if(flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)
cur_obj->reference_maps[j].flags =
REFERENCE_FLAG_UNDEFINED_LAZY;
}
}
}
}
}
else{
output_dysymtab_info.dysymtab_command.nextrefsyms =
output_dysymtab_info.dysymtab_command.nextdefsym +
output_dysymtab_info.dysymtab_command.nundefsym;
}
if(multi_module_dylib == TRUE){
output_dysymtab_info.dysymtab_command.nmodtab = 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->dylib == TRUE)
continue;
if(cur_obj->bundle_loader == TRUE)
continue;
cur_obj->imodtab =
output_dysymtab_info.dysymtab_command.nmodtab;
output_dysymtab_info.dysymtab_command.nmodtab++;
if(cur_obj->ar_hdr){
p = allocate(cur_obj->ar_name_size + 1);
memcpy(p, cur_obj->ar_name, cur_obj->ar_name_size);
p[cur_obj->ar_name_size] = '\0';
cur_obj->module_name = enter_string(p, NULL);
free(p);
}
else{
p = strrchr(cur_obj->file_name, '/');
if(p != NULL)
p++;
else
p = cur_obj->file_name;
cur_obj->module_name = enter_string(p, NULL);
}
}
}
}
else{
output_dysymtab_info.dysymtab_command.nmodtab = 1;
dylib_single_module_name = enter_string("single module", NULL);
}
output_dysymtab_info.dysymtab_command.ntoc =
output_dysymtab_info.dysymtab_command.nextdefsym;
}
__private_extern__
void
output_dylib_tables(
void)
{
unsigned long i, j, flush_offset, ntoc;
struct object_list *object_list, **q;
struct dylib_reference *ref, *refs;
struct dylib_module *mod, *mods;
struct merged_symbol **toc_order;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
struct dylib_table_of_contents *tocs, *toc;
struct merged_section *ms;
flush_offset = output_dysymtab_info.dysymtab_command.extrefsymoff;
refs = (struct dylib_reference *)(output_addr + flush_offset);
ref = refs;
if(multi_module_dylib == TRUE){
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->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
for(j = 0; j < cur_obj->nrefsym; j++){
ref->isym = merged_symbol_output_index(
cur_obj->reference_maps[j].merged_symbol);
ref->flags = cur_obj->reference_maps[j].flags;
ref++;
}
}
}
}
else{
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
if(dead_strip == TRUE && merged_symbol->live == FALSE)
continue;
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)){
ref->isym = merged_symbol_output_index(merged_symbol);
ref->flags = merged_symbol->nlist.n_desc &
REFERENCE_TYPE;
ref++;
}
else if((merged_symbol->nlist.n_type & N_PEXT) == 0){
ref->isym = merged_symbol_output_index(merged_symbol);
ref->flags = REFERENCE_FLAG_DEFINED;
ref++;
}
}
}
}
if(host_byte_sex != target_byte_sex){
swap_dylib_reference(refs,
output_dysymtab_info.dysymtab_command.nextrefsyms,
target_byte_sex);
}
output_flush(flush_offset,
output_dysymtab_info.dysymtab_command.nextrefsyms *
sizeof(struct dylib_reference));
flush_offset = output_dysymtab_info.dysymtab_command.modtaboff;
mods = (struct dylib_module *)(output_addr + flush_offset);
mod = mods;
if(multi_module_dylib == TRUE){
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->dylib == TRUE)
continue;
if(cur_obj->bundle_loader == TRUE)
continue;
mod->module_name = STRING_SIZE_OFFSET +
merged_symbol_string_index(cur_obj->module_name);
mod->iextdefsym = cur_obj->iextdefsym;
mod->nextdefsym = cur_obj->nextdefsym;
mod->nrefsym = cur_obj->nrefsym;
if(mod->nrefsym == 0)
mod->irefsym = 0;
else
mod->irefsym = cur_obj->irefsym;
mod->nlocalsym = cur_obj->nlocalsym + cur_obj->nprivatesym;
if(mod->nlocalsym == 0)
mod->ilocalsym = 0;
else
mod->ilocalsym = cur_obj->ilocalsym;
mod->nextrel = cur_obj->nextrel;
if(mod->nextrel == 0)
mod->iextrel = 0;
else
mod->iextrel = cur_obj->iextrel;
mod->ninit_nterm = (cur_obj->nterm << 16) | cur_obj->ninit;
if(cur_obj->ninit == 0)
cur_obj->iinit = 0;
if(cur_obj->nterm == 0)
cur_obj->iterm = 0;
mod->iinit_iterm = (cur_obj->iterm << 16) | cur_obj->iinit;
if(cur_obj->objc_module_info != NULL){
mod->objc_module_info_addr =
cur_obj->objc_module_info->output_section->s.addr +
cur_obj->objc_module_info->offset;
mod->objc_module_info_size =
cur_obj->objc_module_info->s->size;
}
else{
mod->objc_module_info_addr = 0;
mod->objc_module_info_size = 0;
}
mod++;
}
}
}
else{
mod->module_name = STRING_SIZE_OFFSET +
merged_symbol_string_index(dylib_single_module_name);
mod->iextdefsym =
output_dysymtab_info.dysymtab_command.iextdefsym;
mod->nextdefsym =
output_dysymtab_info.dysymtab_command.nextdefsym;
mod->irefsym = 0;
mod->nrefsym =
output_dysymtab_info.dysymtab_command.nextrefsyms;
mod->ilocalsym =
output_dysymtab_info.dysymtab_command.ilocalsym;
mod->nlocalsym =
output_dysymtab_info.dysymtab_command.nlocalsym;
mod->iextrel = 0;
mod->nextrel =
output_dysymtab_info.dysymtab_command.nextrel;
mod->iinit_iterm = 0;
mod->ninit_nterm = (nterm << 16) | ninit;
ms = lookup_merged_section(SEG_OBJC, SECT_OBJC_MODULES);
if(ms != NULL){
mod->objc_module_info_addr = ms->s.addr;
mod->objc_module_info_size = ms->s.size;
}
else{
mod->objc_module_info_addr = 0;
mod->objc_module_info_size = 0;
}
}
if(host_byte_sex != target_byte_sex){
swap_dylib_module(mods,
output_dysymtab_info.dysymtab_command.nmodtab,
target_byte_sex);
}
output_flush(flush_offset,
output_dysymtab_info.dysymtab_command.nmodtab *
sizeof(struct dylib_module));
toc_order = allocate(output_dysymtab_info.dysymtab_command.ntoc *
sizeof(struct merged_symbol *));
ntoc = 0;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->referenced_in_non_dylib == FALSE)
continue;
if((merged_symbol->nlist.n_type & N_TYPE) != N_UNDF &&
(merged_symbol->nlist.n_type & N_TYPE) != N_PBUD &&
(merged_symbol->nlist.n_type & N_PEXT) == 0)
toc_order[ntoc++] = merged_symbol;
}
}
if(ntoc != output_dysymtab_info.dysymtab_command.ntoc)
fatal("internal error: output_dylib_tables() inconsistent toc "
"counts");
qsort(toc_order, ntoc, sizeof(struct merged_symbol *),
(int (*)(const void *, const void *))qsort_by_name);
flush_offset = output_dysymtab_info.dysymtab_command.tocoff;
tocs = (struct dylib_table_of_contents *)(output_addr +
flush_offset);
toc = tocs;
for(i = 0; i < ntoc; i++){
toc->symbol_index = merged_symbol_output_index(toc_order[i]);
toc->module_index = object_index(toc_order[i]->definition_object);
toc++;
}
if(host_byte_sex != target_byte_sex){
swap_dylib_table_of_contents(tocs, ntoc, target_byte_sex);
}
output_flush(flush_offset, ntoc *
sizeof(struct dylib_table_of_contents));
free(toc_order);
}
static enum bool some_read_only_reloc_flags_set = FALSE;
__private_extern__
void
clear_read_only_reloc_flags(
void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
if(some_read_only_reloc_flags_set == FALSE)
return;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
merged_symbol->flagged_read_only_reloc = FALSE;
}
}
some_read_only_reloc_flags_set = FALSE;
}
__private_extern__
void
flag_read_only_reloc(
struct section *s,
unsigned long output_index,
enum bool *first_time)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
if(*first_time == TRUE){
if(read_only_reloc_flag == READ_ONLY_RELOC_ERROR)
error_with_cur_obj("has external relocation entries in "
"non-writable section (%.16s,%.16s) for symbols:",
s->segname, s->sectname);
else
warning_with_cur_obj("has external relocation entries in "
"non-writable section (%.16s,%.16s) for symbols:",
s->segname, s->sectname);
*first_time = FALSE;
}
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->output_index == output_index){
if(merged_symbol->flagged_read_only_reloc == FALSE){
print("%s\n", merged_symbol->nlist.n_un.n_name);
merged_symbol->flagged_read_only_reloc = TRUE;
some_read_only_reloc_flags_set = TRUE;
}
return;
}
}
}
}
#endif
#ifdef RLD
__private_extern__
void
free_multiple_defs(void)
{
if(nmultiple_defs != 0){
free(multiple_defs);
multiple_defs = NULL;
nmultiple_defs = 0;
}
}
__private_extern__
void
remove_merged_symbols(void)
{
long i;
unsigned long j;
struct merged_symbol_list *m, *merged_symbol_list, *prev_merged_symbol_list,
*next_merged_symbol_list;
enum bool have_some_symbols;
struct merged_symbol_chunk *p, *first_chunk, *prev_chunk, *next_chunk;
struct string_block *string_block, *prev_string_block, *next_string_block;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = merged_symbol_list->used - 1; i >= 0; i--){
if(merged_symbol_list->symbols[i] != NULL &&
merged_symbol_list->symbols[i]->name_len != 0 &&
merged_symbol_list->symbols[i]->definition_object != NULL &&
merged_symbol_list->symbols[i]->definition_object->set_num ==
cur_set){
merged_symbol_list->symbols[i] = NULL;
merged_symbol_list->used--;
}
}
}
prev_merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
if(merged_symbol_list->used == 0)
break;
prev_merged_symbol_list = merged_symbol_list;
}
if(merged_symbol_list != NULL && merged_symbol_list->used == 0){
if(merged_symbol_list == merged_symbol_root->list)
merged_symbol_root->list = NULL;
else
prev_merged_symbol_list->next = NULL;
for(m = merged_symbol_list; m != NULL; m = next_merged_symbol_list){
next_merged_symbol_list = m->next;
free(m);
}
}
have_some_symbols = FALSE;
for(i = 0; i < SYMBOL_LIST_HASH_SIZE; i++){
if(merged_symbol_root == NULL)
break;
first_chunk = NULL;
prev_chunk = NULL;
for(p = &merged_symbol_root->chunks[i]; p != NULL; p = p->next){
for(j = 0; j < SYMBOL_CHUNK_SIZE; j++){
if(p->symbols[j].name_len != 0 &&
p->symbols[j].definition_object->set_num == cur_set){
memset(p->symbols + j, '\0',
sizeof(struct merged_symbol));
if(first_chunk == NULL &&
p != &merged_symbol_root->chunks[i] &&
j == 0)
first_chunk = p;
}
else{
if(p->symbols[j].name_len != 0)
have_some_symbols = TRUE;
}
}
if(first_chunk == NULL)
prev_chunk = p;
}
if(first_chunk != NULL){
for(p = first_chunk; p != NULL; p = next_chunk){
next_chunk = p->next;
free(p);
}
prev_chunk->next = NULL;
}
}
if(have_some_symbols == FALSE){
free(merged_symbol_root);
merged_symbol_root = NULL;
}
prev_string_block = NULL;
for(string_block = merged_string_blocks;
string_block != NULL;
string_block = string_block->next){
if(string_block->set_num == cur_set)
break;
prev_string_block = string_block;
}
if(string_block != NULL && string_block->set_num == cur_set){
if(string_block == merged_string_blocks)
merged_string_blocks = NULL;
else
prev_string_block->next = NULL;
do {
free(string_block->strings);
next_string_block = string_block->next;
free(string_block);
string_block = next_string_block;
}while(string_block != NULL);
}
}
#endif
#ifdef DEBUG
__private_extern__
void
print_symbol_list(
char *string,
enum bool input_based)
{
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol_chunk *p;
unsigned long i, j;
struct nlist *nlist;
struct section *s;
struct section_map *maps;
print("Merged symbol list (%s)\n", string);
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
print("merged_symbols\n");
for(i = 0; i < merged_symbol_list->used; i++){
print("%-4lu[0x%x]\n", i,
(unsigned int)(merged_symbol_list->symbols + i));
nlist = &(merged_symbol_list->symbols[i]->nlist);
print(" n_name %s\n", nlist->n_un.n_name);
print(" n_type ");
switch(nlist->n_type & N_TYPE){
case N_UNDF:
if(nlist->n_value == 0)
print("N_UNDF\n");
else
print("common (size %u)\n", nlist->n_value);
break;
case N_PBUD:
print("N_PBUD\n");
break;
case N_ABS:
print("N_ABS\n");
break;
case N_SECT:
print("N_SECT\n");
break;
case N_INDR:
print("N_INDR for %s\n", ((struct merged_symbol *)
(nlist->n_value))->nlist.n_un.n_name);
break;
default:
print("unknown 0x%x\n", (unsigned int)(nlist->n_type));
break;
}
print(" n_sect %d ", nlist->n_sect);
maps = merged_symbol_list->symbols[i]->
definition_object->section_maps;
if(nlist->n_sect == NO_SECT)
print("NO_SECT\n");
else{
if(input_based == TRUE)
print("(%.16s,%.16s)\n",
maps[nlist->n_sect - 1].s->segname,
maps[nlist->n_sect - 1].s->sectname);
else{
s = get_output_section(nlist->n_sect);
if(s != NULL)
print("(%.16s,%.16s)\n",s->segname, s->sectname);
else
print("(bad section #%d)\n", nlist->n_sect);
}
}
print(" n_desc 0x%04x\n", (unsigned int)(nlist->n_desc));
print(" n_value 0x%08x\n", (unsigned int)(nlist->n_value));
#ifdef RLD
print(" definition_object ");
print_obj_name(
merged_symbol_list->merged_symbols[i].definition_object);
print("\n");
print(" set_num %d\n", merged_symbol_list->merged_symbols[i].
definition_object->set_num);
#endif
}
}
print("Hash table (merged_symbol_root 0x%x)\n",
(unsigned int)(merged_symbol_root));
for(i = 0; i < SYMBOL_LIST_HASH_SIZE; i++){
for(p = &merged_symbol_root->chunks[i]; p != NULL; p = p->next){
for(j = 0; j < SYMBOL_CHUNK_SIZE; j++){
if(p->symbols[j].name_len != 0){
print(" %-5lu %-2lu [0x%x] %s\n", i, j,
(unsigned int)(p->symbols + j),
p->symbols[j].nlist.n_un.n_name);
}
}
}
}
}
#endif
__private_extern__
struct section *
get_output_section(
unsigned long sect)
{
struct merged_segment **p, *msg;
struct merged_section **content, **zerofill, *ms;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->output_sectnum == sect)
return(&(ms->s));
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
if(ms->output_sectnum == sect)
return(&(ms->s));
zerofill = &(ms->next);
}
p = &(msg->next);
}
return(NULL);
}
#ifdef DEBUG
#ifndef RLD
__private_extern__
void
print_undefined_list(void)
{
struct undefined_list *undefined;
print("Undefined list\n");
for(undefined = undefined_list.next;
undefined != &undefined_list;
undefined = undefined->next){
print(" %s", undefined->merged_symbol->nlist.n_un.n_name);
if(undefined->merged_symbol->nlist.n_type == (N_UNDF | N_EXT) ||
undefined->merged_symbol->nlist.n_value != 0)
print("\n");
else
print(" (no longer undefined)\n");
}
}
#endif
#endif