#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <limits.h>
#import <mach/mach.h>
#import "stuff/openstep_mach.h"
#import <mach-o/loader.h>
#import <mach-o/nlist.h>
#import "inline_strcmp.h"
#import "stuff/bool.h"
#import "images.h"
#import "symbols.h"
#import "allocate.h"
#import "errors.h"
#import "reloc.h"
#import "register_funcs.h"
#import "mod_init_funcs.h"
#import "lock.h"
#import "dyld_init.h"
#import "trace.h"
struct symbol_list undefined_list = {
NULL, NULL, NULL, FALSE, FALSE, FALSE, &undefined_list, &undefined_list
};
static struct symbol_list being_linked_list = {
NULL, NULL, NULL, FALSE, FALSE, FALSE, &being_linked_list,&being_linked_list
};
static struct symbol_list free_list = {
NULL, NULL, NULL, FALSE, FALSE, FALSE, &free_list, &free_list
};
enum nsymbol_lists { NSYMBOL_LISTS = 100 };
struct symbol_block {
enum bool initialized;
struct symbol_list symbols[NSYMBOL_LISTS];
struct symbol_block *next;
};
enum nsymbol_blocks { NSYMBOL_BLOCKS = 45 };
extern struct symbol_block symbol_blocks[NSYMBOL_BLOCKS];
static unsigned long symbol_blocks_used = 0;
object_image_register_proc object_image_register = NULL;
object_image_locator_proc object_image_locator = NULL;
static void initialize_symbol_block(
struct symbol_block *symbol_block);
static struct symbol_list *new_symbol_list(
void);
static void add_to_undefined_list(
char *name,
struct nlist *symbol,
struct image *image,
enum bool bind_fully,
enum bool flat_reference);
static void add_to_being_linked_list(
char *name,
struct nlist *symbol,
struct image *image,
enum bool flat_reference);
static enum bool are_symbols_coalesced(
struct image *image1,
struct nlist *symbol1,
struct image *image2,
struct nlist *symbol2);
static enum bool is_symbol_coalesced_and_weak(
struct image *image,
struct nlist *symbol);
static enum bool is_section_coalesced(
struct image *image,
unsigned int nsect);
static void add_reference(
char *symbol_name,
struct nlist *symbol,
struct image *image,
enum bool bind_now,
enum bool bind_fully);
static struct image *get_indr_image(
char *symbol_name,
struct image *image);
static enum bool lookup_symbol_in_library_image(
char *symbol_name,
unsigned long itoc,
struct image *image,
module_state *library_modules,
struct library_image *library_image,
struct nlist **defined_symbol,
module_state **defined_module,
struct image **defined_image,
struct library_image **defined_library_image,
struct indr_loop_list *indr_loop);
static char *nlist_bsearch_strings;
static struct nlist *toc_bsearch_symbols;
static char *toc_bsearch_strings;
#include "inline_bsearch.h"
static struct nlist *nlist_linear_search(
char *symbol_name,
struct nlist *symbols,
unsigned long nsymbols,
char *strings);
static char * look_for_flat_reference(
char *symbol_name,
struct nlist **referenced_symbol,
module_state **referenced_module,
struct image **referenced_image,
struct library_image **referenced_library_image,
enum bool ignore_lazy_references);
static void relocate_symbol_pointers(
unsigned long symbol_index,
unsigned long *indirect_symtab,
struct image *image,
unsigned long value,
enum bool only_lazy_pointers);
static void resolve_non_lazy_symbol_pointers_in_image(
struct image *image);
static enum bool check_libraries_for_definition_and_refernce(
char *symbol_name,
struct library_image *library_image);
struct image *
get_primary_image(
struct image *image,
struct nlist *symbol)
{
struct image *primary_image;
if(image != NULL && symbol != NULL && force_flat_namespace == FALSE &&
(image->mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL){
if(GET_LIBRARY_ORDINAL(symbol->n_desc) == EXECUTABLE_ORDINAL)
primary_image = &object_images.images[0].image;
else if(GET_LIBRARY_ORDINAL(symbol->n_desc) ==
DYNAMIC_LOOKUP_ORDINAL &&
image->ndependent_images != DYNAMIC_LOOKUP_ORDINAL)
primary_image = NULL;
else if(GET_LIBRARY_ORDINAL(symbol->n_desc) ==
SELF_LIBRARY_ORDINAL){
primary_image = image;
}
else{
primary_image = image->dependent_images[
GET_LIBRARY_ORDINAL(symbol->n_desc) - 1];
}
}
else{
primary_image = NULL;
}
return(primary_image);
}
struct twolevel_hint *
get_hint(
struct image *image,
struct nlist *symbol)
{
struct nlist *symbols;
struct twolevel_hint *hints, *hint;
unsigned long symbol_index;
if(image != NULL &&
symbol != NULL &&
image->image_can_use_hints == TRUE &&
((symbol->n_type & N_TYPE) == N_UNDF ||
(symbol->n_type & N_TYPE) == N_PBUD) ){
symbols = (struct nlist *)
(image->vmaddr_slide +
image->linkedit_segment->vmaddr +
image->st->symoff -
image->linkedit_segment->fileoff);
hints = (struct twolevel_hint *)
(image->vmaddr_slide +
image->linkedit_segment->vmaddr +
image->hints_cmd->offset -
image->linkedit_segment->fileoff);
symbol_index = symbol - symbols;
hint = hints + (symbol_index - image->dyst->iundefsym);
}
else{
hint = NULL;
}
return(hint);
}
enum bool
get_weak(
struct nlist *symbol)
{
if(symbol != NULL && (symbol->n_desc & N_WEAK_REF) == N_WEAK_REF)
return(TRUE);
return(FALSE);
}
void
setup_initial_undefined_list(
enum bool all_symbols)
{
unsigned long i;
char *symbol_name;
struct nlist *symbols;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct image *image;
enum bool bind_fully;
enum bool flat_reference;
linkedit_segment = object_images.images[0].image.linkedit_segment;
st = object_images.images[0].image.st;
dyst = object_images.images[0].image.dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
return;
symbols = (struct nlist *)
(linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
image = &object_images.images[0].image;
if(force_flat_namespace == FALSE)
flat_reference = (object_images.images[0].image.mh->flags &
MH_TWOLEVEL) != MH_TWOLEVEL;
else
flat_reference = TRUE;
bind_fully = FALSE;
#ifdef FULLY_BIND_MOD_INIT_ROUTINES
if(object_images.images[0].image.init != NULL ||
object_images.images[0].image.term != NULL)
bind_fully = TRUE;
#endif
for(i = dyst->iundefsym; i < dyst->iundefsym + dyst->nundefsym; i++){
if(executable_bind_at_load == TRUE ||
all_symbols == TRUE ||
(symbols[i].n_desc & REFERENCE_TYPE) ==
REFERENCE_FLAG_UNDEFINED_NON_LAZY){
symbol_name = (char *)
(image->linkedit_segment->vmaddr +
image->st->stroff -
image->linkedit_segment->fileoff) +
symbols[i].n_un.n_strx;
add_to_undefined_list(symbol_name, symbols + i, image,
bind_fully, flat_reference);
}
}
}
void
setup_prebound_coalesed_symbols(
void)
{
unsigned long i, j, k, isym;
char *symbol_name;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
char *strings;
struct image *image;
struct library_images *q;
struct dylib_module *dylib_modules, *dylib_module;
struct dylib_reference *dylib_references;
struct symbol_list *being_linked;
enum link_state link_state;
enum bool found;
struct relocation_info *relocs;
struct dylib_table_of_contents *tocs, *toc;
enum bool flat_reference;
int number_of_global_coalesced_symbols;
int total_number_of_global_coalesced_symbols;
total_number_of_global_coalesced_symbols = 0;
image = &object_images.images[0].image;
if(image->has_coalesced_sections == TRUE){
number_of_global_coalesced_symbols = 0;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
if(force_flat_namespace == FALSE)
flat_reference = (object_images.images[0].image.mh->flags &
MH_TWOLEVEL) != MH_TWOLEVEL;
else
flat_reference = TRUE;
if(linkedit_segment != NULL && st != NULL && dyst != NULL &&
flat_reference == TRUE){
symbols = (struct nlist *)
(linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
for(i = dyst->iextdefsym;
i < dyst->iextdefsym + dyst->nextdefsym;
i++){
symbol = symbols + i;
if((symbol->n_type & N_TYPE) == N_SECT &&
is_section_coalesced(image, symbol->n_sect - 1) == TRUE){
symbol_name = strings + symbol->n_un.n_strx;
number_of_global_coalesced_symbols += 1;
add_to_being_linked_list(symbol_name, symbol, image,
flat_reference);
}
}
}
total_number_of_global_coalesced_symbols +=
number_of_global_coalesced_symbols;
}
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
number_of_global_coalesced_symbols = 0;
image = &(q->images[i].image);
if(image->has_coalesced_sections == FALSE)
continue;
if(force_flat_namespace == FALSE)
flat_reference = (image->mh->flags &
MH_TWOLEVEL) != MH_TWOLEVEL;
else
flat_reference = TRUE;
if(flat_reference == FALSE)
continue;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
dylib_modules = (struct dylib_module *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
dylib_references = (struct dylib_reference *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->extrefsymoff -
linkedit_segment->fileoff);
for(j = 0; j < image->dyst->nmodtab; j++){
link_state = GET_LINK_STATE(q->images[i].modules[j]);
if(link_state != FULLY_LINKED)
continue;
dylib_module = dylib_modules + j;
for(k = dylib_module->irefsym;
k < dylib_module->irefsym + dylib_module->nrefsym;
k++){
symbol = symbols + dylib_references[k].isym;
if(dylib_references[k].flags ==
REFERENCE_FLAG_DEFINED &&
(symbol->n_type & N_TYPE) ==
N_SECT &&
is_section_coalesced(image, symbol->n_sect - 1) ==
TRUE){
symbol_name = strings + symbol->n_un.n_strx;
number_of_global_coalesced_symbols += 1;
found = FALSE;
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
if(being_linked->image != image &&
strcmp(being_linked->name, symbol_name) ==0){
found = TRUE;
break;
}
}
if(found == FALSE){
add_to_being_linked_list(symbol_name, symbol,
image, flat_reference);
}
}
}
}
total_number_of_global_coalesced_symbols +=
number_of_global_coalesced_symbols;
}
q = q->next_images;
}while(q != NULL);
if(total_number_of_global_coalesced_symbols == 0)
return;
image = &object_images.images[0].image;
relocate_symbol_pointers_in_object_image(image);
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
image = &(q->images[i].image);
relocate_symbol_pointers_in_library_image(image);
}
q = q->next_images;
}while(q != NULL);
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
image = &object_images.images[0].image;
if(being_linked->image != image &&
(force_flat_namespace == TRUE ||
(image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL)){
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
if(linkedit_segment != NULL && st != NULL && dyst != NULL){
symbols = (struct nlist *)
(linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
nlist_bsearch_strings = (char *)
(linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
symbol = inline_bsearch_nlist(being_linked->name,
symbols + dyst->iextdefsym,
dyst->nextdefsym);
if(symbol != NULL){
if(image->mh->flags & MH_BINDATLOAD)
symbol = nlist_linear_search(being_linked->name,
symbols + dyst->iundefsym, dyst->nundefsym,
nlist_bsearch_strings);
else
symbol = inline_bsearch_nlist(being_linked->name,
symbols + dyst->iundefsym, dyst->nundefsym);
}
if(symbol != NULL){
isym = symbol - symbols;
relocs = (struct relocation_info *)
(linkedit_segment->vmaddr +
dyst->extreloff -
linkedit_segment->fileoff);
if(image->change_protect_on_reloc)
make_image_writable(image, "object");
for(i = 0; i < dyst->nextrel; i++){
if(isym == relocs[i].r_symbolnum){
undo_external_relocation(
TRUE,
image,
relocs + i,
1,
symbols,
nlist_bsearch_strings,
NULL,
image->name);
(void)external_relocation(
image,
relocs + i,
1,
symbols,
nlist_bsearch_strings,
NULL,
image->name);
}
}
if(image->change_protect_on_reloc)
restore_image_vm_protections(image, "object");
}
}
}
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
image = &(q->images[i].image);
if(being_linked->image != image &&
(force_flat_namespace == TRUE ||
(image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL)){
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
tocs = (struct dylib_table_of_contents *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
toc_bsearch_strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
toc = inline_bsearch_toc(being_linked->name, tocs,
dyst->ntoc);
if(toc != NULL){
symbol = toc_bsearch_symbols + toc->symbol_index;
isym = toc->symbol_index;
}
else{
nlist_bsearch_strings = toc_bsearch_strings;
symbol = inline_bsearch_nlist(being_linked->name,
toc_bsearch_symbols + dyst->iundefsym,
dyst->nundefsym);
if(symbol == NULL)
continue;
isym = symbol - toc_bsearch_symbols;
}
strings = toc_bsearch_strings;
symbols = toc_bsearch_symbols;
dylib_modules = (struct dylib_module *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
relocs = (struct relocation_info *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->extreloff -
linkedit_segment->fileoff);
if(image->change_protect_on_reloc)
make_image_writable(image, "object");
for(j = 0; j < image->dyst->nmodtab; j++){
link_state =
GET_LINK_STATE(q->images[i].modules[j]);
if(link_state != FULLY_LINKED)
continue;
dylib_module = dylib_modules + j;
for(k = dylib_modules[j].iextrel;
k < dylib_modules[j].nextrel;
k++){
if(isym == relocs[k].r_symbolnum){
undo_external_relocation(
TRUE,
image,
relocs + k,
1,
symbols,
strings,
image->name,
strings + dylib_modules[j].module_name);
(void)external_relocation(
image,
relocs + k,
1,
symbols,
strings,
image->name,
strings + dylib_modules[j].module_name);
}
}
}
if(image->change_protect_on_reloc)
restore_image_vm_protections(image, "object");
}
}
q = q->next_images;
}while(q != NULL);
}
clear_being_linked_list(FALSE);
}
static
void
initialize_symbol_block(
struct symbol_block *symbol_block)
{
unsigned long i;
struct symbol_list *undefineds;
undefineds = symbol_block->symbols;
free_list.next = &undefineds[0];
undefineds[0].prev = &free_list;
undefineds[0].next = &undefineds[1];
undefineds[0].symbol = NULL;
undefineds[0].image = NULL;
for(i = 1 ; i < NSYMBOL_LISTS - 1 ; i++){
undefineds[i].prev = &undefineds[i-1];
undefineds[i].next = &undefineds[i+1];
undefineds[i].symbol = NULL;
undefineds[i].image = NULL;
}
free_list.prev = &undefineds[i];
undefineds[i].prev = &undefineds[i-1];
undefineds[i].next = &free_list;
undefineds[i].symbol = NULL;
undefineds[i].image = NULL;
symbol_block->initialized = TRUE;
}
static
struct symbol_list *
new_symbol_list(
void)
{
struct symbol_block *p, *q;
struct symbol_list *new;
if(free_list.next == &free_list){
if(symbol_blocks[0].initialized == FALSE){
symbol_blocks_used++;
q = symbol_blocks;
}
else{
for(p = symbol_blocks; p->next != NULL; p = p->next)
;
if(symbol_blocks_used < NSYMBOL_BLOCKS){
q = symbol_blocks + symbol_blocks_used;
symbol_blocks_used++;
}
else{
q = allocate(sizeof(struct symbol_block));
}
p->next = q;
q->next = NULL;
}
initialize_symbol_block(q);
}
new = free_list.next;
new->next->prev = &free_list;
free_list.next = new->next;
return(new);
}
static
void
add_to_undefined_list(
char *name,
struct nlist *symbol,
struct image *image,
enum bool bind_fully,
enum bool flat_reference)
{
struct symbol_list *undefined;
struct symbol_list *new;
if(flat_reference == TRUE){
for(undefined = undefined_list.next;
undefined != &undefined_list;
undefined = undefined->next){
if(undefined->name == name){
if(bind_fully == TRUE)
undefined->bind_fully = bind_fully;
if(flat_reference == TRUE)
undefined->flat_reference = flat_reference;
return;
}
}
}
new = new_symbol_list();
new->name = name;
new->symbol = symbol;
new->image = image;
new->remove_on_error = return_on_error;
new->bind_fully = bind_fully;
new->flat_reference = flat_reference;
new->prev = undefined_list.prev;
new->next = &undefined_list;
undefined_list.prev->next = new;
undefined_list.prev = new;
}
static
void
add_to_being_linked_list(
char *name,
struct nlist *symbol,
struct image *image,
enum bool flat_reference)
{
struct symbol_list *new;
new = new_symbol_list();
new->name = name;
new->symbol = symbol;
new->image = image;
new->remove_on_error = return_on_error;
new->bind_fully = FALSE;
new->flat_reference = flat_reference;
new->prev = being_linked_list.prev;
new->next = &being_linked_list;
being_linked_list.prev->next = new;
being_linked_list.prev = new;
}
void
clear_being_linked_list(
enum bool only_remove_on_error)
{
struct symbol_list *old, *old_next;
for(old = being_linked_list.next;
old != &being_linked_list;
){
if(only_remove_on_error == FALSE ||
old->remove_on_error == TRUE){
old->next->prev = &being_linked_list;
old_next = old->next;
old->prev = free_list.prev;
old->next = &free_list;
free_list.prev->next = old;
free_list.prev = old;
old->name = NULL;
old->symbol = NULL;
old->image = NULL;
old->remove_on_error = FALSE;
old->bind_fully = FALSE;
old->flat_reference = FALSE;
old = old_next;
}
else if(only_remove_on_error == TRUE &&
old->remove_on_error == FALSE){
old->next->prev = &being_linked_list;
old_next = old->next;
old->prev = undefined_list.prev;
old->next = &undefined_list;
undefined_list.prev->next = old;
undefined_list.prev = old;
}
}
if(only_remove_on_error == TRUE &&
being_linked_list.prev != &being_linked_list)
return;
being_linked_list.name = NULL;
being_linked_list.symbol = NULL;
being_linked_list.image = NULL;
being_linked_list.prev = &being_linked_list;
being_linked_list.next = &being_linked_list;
}
void
clear_undefined_list(
enum bool only_remove_on_error)
{
struct symbol_list *old, *old_next;
for(old = undefined_list.next;
old != &undefined_list;
){
if(only_remove_on_error == FALSE ||
old->remove_on_error == TRUE){
old->next->prev = &undefined_list;
old_next = old->next;
old->prev = free_list.prev;
old->next = &free_list;
free_list.prev->next = old;
free_list.prev = old;
old->name = NULL;
old->symbol = NULL;
old->image = NULL;
old->remove_on_error = FALSE;
old->bind_fully = FALSE;
old->flat_reference = FALSE;
old = old_next;
}
}
if(only_remove_on_error == TRUE &&
undefined_list.prev != &undefined_list)
return;
undefined_list.name = NULL;
undefined_list.symbol = NULL;
undefined_list.image = NULL;
undefined_list.prev = &undefined_list;
undefined_list.next = &undefined_list;
}
enum bool
resolve_undefineds(
enum bool bind_now,
enum bool launching_with_prebound_libraries)
{
struct symbol_list *undefined, *next_undefined, *defined;
struct nlist *symbol;
module_state *module;
struct image *image;
enum link_state link_state;
struct library_image *library_image;
unsigned long module_index;
enum bool r, bind_fully;
struct object_image *object_image;
for(undefined = undefined_list.next;
undefined != &undefined_list;
){
bind_fully = undefined->bind_fully;
lookup_symbol(undefined->name,
get_primary_image(undefined->image, undefined->symbol),
get_hint(undefined->image, undefined->symbol),
get_weak(undefined->symbol),
&symbol, &module, &image, &library_image, NO_INDR_LOOP);
if(symbol != NULL){
next_undefined = undefined->next;
undefined->prev->next = undefined->next;
undefined->next->prev = undefined->prev;
defined = undefined;
undefined = next_undefined;
if(symbol != &some_weak_symbol){
defined->name = (char *)
(image->vmaddr_slide +
image->linkedit_segment->vmaddr +
image->st->stroff -
image->linkedit_segment->fileoff) +
symbol->n_un.n_strx;
}
defined->symbol = symbol;
defined->image = image;
defined->prev = being_linked_list.prev;
defined->next = &being_linked_list;
being_linked_list.prev->next = defined;
being_linked_list.prev = defined;
if(return_on_error == TRUE){
if(library_image != NULL){
if(library_image->remove_on_error == FALSE &&
library_image->module_states_saved == FALSE){
if(library_image->saved_module_states == NULL){
library_image->saved_module_states =
allocate(library_image->nmodules *
sizeof(module_state));
}
memcpy(library_image->saved_module_states,
library_image->modules,
library_image->nmodules *
sizeof(module_state));
library_image->module_states_saved = TRUE;
}
}
else{
object_image = find_object_image(image);
if(object_image->module_state_saved == FALSE){
object_image->saved_module_state =
object_image->module;
object_image->module_state_saved = TRUE;
}
}
}
link_state = GET_LINK_STATE(*module);
if(link_state == PREBOUND_UNLINKED){
undo_prebinding_for_library_module(
module,
image,
library_image);
module_index = module - library_image->modules;
SET_LINK_STATE(*module, UNLINKED);
if(return_on_error == TRUE &&
library_image->saved_module_states != NULL)
SET_LINK_STATE(library_image->saved_module_states
[module_index], UNLINKED);
r = link_library_module(library_image, image, module,
bind_now, bind_fully,
launching_with_prebound_libraries);
if(return_on_error == TRUE && r == FALSE)
goto back_out_changes;
}
else if(link_state == UNLINKED){
r = link_library_module(library_image, image, module,
bind_now, bind_fully,
launching_with_prebound_libraries);
if(launching_with_prebound_libraries == TRUE && r == FALSE)
return(FALSE);
if(return_on_error == TRUE && r == FALSE)
goto back_out_changes;
}
else if(bind_now == TRUE &&
library_image != NULL &&
link_state == LINKED){
r = link_library_module(library_image, image, module,
bind_now, bind_fully,
launching_with_prebound_libraries);
if(return_on_error == TRUE && r == FALSE)
goto back_out_changes;
}
else if(bind_fully == TRUE &&
GET_FULLYBOUND_STATE(*module) == 0){
if(library_image != NULL){
r = link_library_module(library_image, image, module,
TRUE, bind_fully,
launching_with_prebound_libraries);
if(return_on_error == TRUE && r == FALSE)
goto back_out_changes;
}
else{
object_image = find_object_image(image);
r = link_object_module(object_image, TRUE, TRUE);
if(return_on_error == TRUE && r == FALSE)
goto back_out_changes;
}
}
if(undefined == &undefined_list &&
undefined->next != &undefined_list)
undefined = undefined->next;
}
else{
undefined = undefined->next;
}
}
return(TRUE);
back_out_changes:
clear_state_changes_to_the_modules();
clear_being_linked_list(TRUE);
clear_undefined_list(TRUE);
return(FALSE);
}
void
clear_module_states_saved(
void)
{
unsigned long i;
struct object_images *p;
struct library_images *q;
for(p = &object_images ; p != NULL; p = p->next_images){
for(i = 0; i < p->nimages; i++){
p->images[i].module_state_saved = FALSE;
}
}
for(q = &library_images; q != NULL; q = q->next_images){
for(i = 0; i < q->nimages; i++){
q->images[i].module_states_saved = FALSE;
}
}
}
void
clear_state_changes_to_the_modules(
void)
{
unsigned long i, j;
struct object_images *q;
struct library_images *p;
for(q = &object_images; q != NULL; q = q->next_images){
for(i = 0; i < q->nimages; i++){
if(q->images[i].module_state_saved == TRUE){
SET_LINK_STATE(q->images[i].module,
q->images[i].saved_module_state);
if(GET_FULLYBOUND_STATE(
q->images[i].saved_module_state) == 0)
CLEAR_FULLYBOUND_STATE(q->images[i].module);
q->images[i].module_state_saved = FALSE;
}
}
}
for(p = &library_images; p != NULL; p = p->next_images){
for(i = 0; i < p->nimages; i++){
if(p->images[i].remove_on_error == FALSE &&
p->images[i].module_states_saved == TRUE){
for(j = 0; j < p->images[i].nmodules ; j++){
SET_LINK_STATE(p->images[i].modules[j],
p->images[i].saved_module_states[j]);
if(GET_FULLYBOUND_STATE(
p->images[i].saved_module_states[j]) == 0)
CLEAR_FULLYBOUND_STATE(p->images[i].modules[j]);
}
p->images[i].module_states_saved = FALSE;
}
}
}
}
static
enum bool
are_symbols_coalesced(
struct image *image1,
struct nlist *symbol1,
struct image *image2,
struct nlist *symbol2)
{
if((symbol1->n_type & N_TYPE) != N_SECT ||
(symbol2->n_type & N_TYPE) != N_SECT)
return(FALSE);
if(is_section_coalesced(image1, symbol1->n_sect - 1) == FALSE)
return(FALSE);
if(is_section_coalesced(image2, symbol2->n_sect - 1) == FALSE)
return(FALSE);
return(TRUE);
}
enum bool
is_symbol_coalesced(
struct image *image,
struct nlist *symbol)
{
if((symbol->n_type & N_TYPE) != N_SECT)
return(FALSE);
return(is_section_coalesced(image, symbol->n_sect - 1));
}
static
enum bool
is_symbol_coalesced_and_weak(
struct image *image,
struct nlist *symbol)
{
if((symbol->n_type & N_TYPE) != N_SECT)
return(FALSE);
if(is_section_coalesced(image, symbol->n_sect - 1) == FALSE)
return(FALSE);
if((symbol->n_desc & N_WEAK_DEF) != N_WEAK_DEF)
return(FALSE);
return(TRUE);
}
static
enum bool
is_section_coalesced(
struct image *image,
unsigned int nsect)
{
unsigned long i, j;
struct load_command *lc, *load_commands;
struct segment_command *sg;
struct section *s;
load_commands = (struct load_command *)
((char *)image->mh + sizeof(struct mach_header));
lc = load_commands;
j = 0;
for(i = 0; i < image->mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
if(nsect - j < sg->nsects){
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
if((s[nsect - j].flags & SECTION_TYPE) == S_COALESCED)
return(TRUE);
else
return(FALSE);
}
j += sg->nsects;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
return(FALSE);
}
enum bool
link_library_module(
struct library_image *library_image,
struct image *image,
module_state *module,
enum bool bind_now,
enum bool bind_fully,
enum bool launching_with_prebound_libraries)
{
unsigned long i, j;
char *symbol_name;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols;
char *strings;
struct dylib_module *dylib_modules, *dylib_module;
unsigned long module_index;
enum link_state link_state;
struct nlist *prev_symbol;
module_state *prev_module;
struct image *prev_image;
struct library_image *prev_library_image;
enum link_state prev_link_state;
struct segment_command *prev_linkedit_segment;
struct symtab_command *prev_st;
struct dysymtab_command *prev_dyst;
struct nlist *prev_symbols;
char *prev_strings, *prev_library_name, *prev_module_name;
struct dylib_module *prev_dylib_modules, *prev_dylib_module;
unsigned long prev_module_index;
struct dylib_reference *dylib_references;
enum link_state ref_link_state;
enum bool found;
struct symbol_list *being_linked;
enum bool private_refs;
enum bool flat_reference;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
dylib_modules = (struct dylib_module *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
module_index = module - library_image->modules;
dylib_module = dylib_modules + module_index;
#ifdef FULLY_BIND_MOD_INIT_ROUTINES
if(bind_fully == FALSE && dylib_module->ninit_nterm != 0){
bind_fully = TRUE;
bind_now = TRUE;
}
#endif
if(force_flat_namespace == FALSE)
flat_reference = (image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL;
else
flat_reference = TRUE;
link_state = GET_LINK_STATE(*module);
if(link_state == LINKED || link_state == BEING_LINKED)
goto add_undefineds;
if(force_flat_namespace == FALSE &&
(image->mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL){
goto add_undefineds;
}
for(i = dylib_module->iextdefsym;
i < dylib_module->iextdefsym + dylib_module->nextdefsym;
i++){
symbol_name = strings + symbols[i].n_un.n_strx;
lookup_symbol(symbol_name, NULL, NULL, FALSE, &prev_symbol,
&prev_module, &prev_image, &prev_library_image,
NO_INDR_LOOP);
if(prev_symbol != NULL && module != prev_module &&
prev_image != NULL &&
(force_flat_namespace == TRUE ||
(prev_image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL)){
prev_link_state = GET_LINK_STATE(*prev_module);
if(prev_link_state == BEING_LINKED ||
prev_link_state == RELOCATED ||
prev_link_state == REGISTERING ||
prev_link_state == INITIALIZING ||
prev_link_state == LINKED ||
prev_link_state == FULLY_LINKED){
prev_linkedit_segment = prev_image->linkedit_segment;
prev_st = prev_image->st;
prev_dyst = prev_image->dyst;
prev_symbols = (struct nlist *)
(prev_image->vmaddr_slide +
prev_linkedit_segment->vmaddr +
prev_st->symoff -
prev_linkedit_segment->fileoff);
prev_strings = (char *)
(prev_image->vmaddr_slide +
prev_linkedit_segment->vmaddr +
prev_st->stroff -
prev_linkedit_segment->fileoff);
prev_dylib_modules = (struct dylib_module *)
(prev_image->vmaddr_slide +
prev_linkedit_segment->vmaddr +
prev_dyst->modtaboff -
prev_linkedit_segment->fileoff);
if(prev_library_image != NULL){
prev_module_index = prev_module -
prev_library_image->modules;
prev_dylib_module = prev_dylib_modules +
prev_module_index;
prev_library_name = prev_image->name;
prev_module_name = prev_strings +
prev_dylib_module->module_name;
}
else{
prev_library_name = NULL;
prev_module_name = prev_image->name;
}
if((image->has_coalesced_sections == TRUE &&
(are_symbols_coalesced(image, symbols + i,
prev_image,prev_symbol) == TRUE ||
is_symbol_coalesced_and_weak(image, symbols + i))) ||
(prev_image->has_coalesced_sections == TRUE &&
is_symbol_coalesced_and_weak(prev_image,
prev_symbol) == TRUE) ){
found = FALSE;
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
if(being_linked->symbol == prev_symbol){
found = TRUE;
break;
}
}
if(prev_image->has_coalesced_sections == TRUE &&
is_symbol_coalesced_and_weak(prev_image,
prev_symbol) == TRUE){
if(found == TRUE){
being_linked->prev->next = being_linked->next;
being_linked->next->prev = being_linked->prev;
being_linked->prev = free_list.prev;
being_linked->next = &free_list;
being_linked->name = NULL;
being_linked->symbol = NULL;
being_linked->image = NULL;
being_linked->remove_on_error = FALSE;
being_linked->bind_fully = FALSE;
being_linked->flat_reference = FALSE;
}
found = FALSE;
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
if(being_linked->symbol == symbols + i){
found = TRUE;
break;
}
}
if(found == FALSE)
add_to_being_linked_list(symbol_name,
symbols + i, image, flat_reference);
}
else{
if(found == FALSE)
add_to_being_linked_list(symbol_name,
prev_symbol, prev_image, flat_reference);
}
continue;
}
if(launching_with_prebound_libraries == TRUE){
if(dyld_prebind_debug != 0 && prebinding == TRUE)
print("dyld: %s: trying to use prebound libraries "
"failed due to multiply defined symbols\n",
executables_name);
prebinding = FALSE;
return(FALSE);
}
multiply_defined_error(symbol_name,
image,
symbols + i,
module,
image->name,
strings + dylib_module->module_name,
prev_image,
prev_symbol,
prev_module,
prev_library_name,
prev_module_name);
if(return_on_error == TRUE)
return(FALSE);
}
else{
if(image->has_coalesced_sections == TRUE &&
is_symbol_coalesced(image, symbols + i) == TRUE){
add_to_being_linked_list(symbol_name, symbols+i, image,
flat_reference);
}
}
}
else{
if(image->has_coalesced_sections == TRUE &&
is_symbol_coalesced(image, symbols + i) == TRUE){
add_to_being_linked_list(symbol_name, symbols + i, image,
flat_reference);
}
}
}
add_undefineds:
private_refs = FALSE;
dylib_references = (struct dylib_reference *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->extrefsymoff -
linkedit_segment->fileoff);
for(i = dylib_module->irefsym;
i < dylib_module->irefsym + dylib_module->nrefsym;
i++){
if(dylib_references[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
((executable_bind_at_load || bind_now || bind_fully) &&
dylib_references[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)){
symbol_name = strings +
symbols[dylib_references[i].isym].n_un.n_strx;
add_reference(symbol_name, symbols + dylib_references[i].isym,
image, bind_now, bind_fully);
}
else if(dylib_references[i].flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
((executable_bind_at_load || bind_now || bind_fully) &&
dylib_references[i].flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)){
private_refs = TRUE;
}
}
link_state = GET_LINK_STATE(*module);
if(bind_now == FALSE){
if(link_state != RELOCATED &&
link_state != REGISTERING &&
link_state != INITIALIZING &&
link_state != LINKED &&
link_state != FULLY_LINKED)
SET_LINK_STATE(*module, BEING_LINKED);
}
else{
if(link_state != RELOCATED &&
link_state != REGISTERING &&
link_state != INITIALIZING &&
link_state != LINKED &&
link_state != FULLY_LINKED)
SET_LINK_STATE(*module, BEING_LINKED);
else if(link_state == LINKED)
SET_LINK_STATE(*module, FULLY_LINKED);
}
if(bind_fully == TRUE)
SET_FULLYBOUND_STATE(*module);
if(bind_fully == TRUE || bind_now == TRUE)
image->some_modules_being_bound_fully = TRUE;
if(private_refs == TRUE){
for(i = dylib_module->irefsym;
i < dylib_module->irefsym + dylib_module->nrefsym;
i++){
if(dylib_references[i].flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
((executable_bind_at_load || bind_now || bind_fully) &&
dylib_references[i].flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)){
for(j = 0; j < dyst->nmodtab; j++){
if(dylib_references[i].isym >=
dylib_modules[j].ilocalsym &&
dylib_references[i].isym <
dylib_modules[j].ilocalsym +
dylib_modules[j].nlocalsym)
break;
}
if(j < dyst->nmodtab){
ref_link_state =
GET_LINK_STATE(library_image->modules[j]);
if(ref_link_state == PREBOUND_UNLINKED){
undo_prebinding_for_library_module(
library_image->modules + j,
image,
library_image);
ref_link_state = UNLINKED;
SET_LINK_STATE(library_image->modules[j],
ref_link_state);
if(return_on_error == TRUE &&
library_image->saved_module_states != NULL)
SET_LINK_STATE(library_image->
saved_module_states[j], UNLINKED);
}
if(ref_link_state == UNLINKED ||
(bind_fully == TRUE &&
GET_FULLYBOUND_STATE(
library_image->modules[j]) == 0)){
if(link_library_module(
library_image,
&(library_image->image),
library_image->modules + j,
bind_now,
bind_fully,
launching_with_prebound_libraries) == FALSE){
return(FALSE);
}
}
}
}
}
}
if(library_image->image.rc != NULL){
module = library_image->modules +
library_image->image.rc->init_module;
link_state = GET_LINK_STATE(*module);
if(link_state == PREBOUND_UNLINKED){
undo_prebinding_for_library_module(
module,
image,
library_image);
SET_LINK_STATE(*module, UNLINKED);
if(return_on_error == TRUE &&
library_image->saved_module_states != NULL)
SET_LINK_STATE(library_image->saved_module_states[
library_image->image.rc->init_module], UNLINKED);
}
if(library_image->image.init_bound == FALSE){
library_image->image.init_bound = TRUE;
return(link_library_module(
library_image,
&(library_image->image),
module,
TRUE,
TRUE,
launching_with_prebound_libraries));
}
}
return(TRUE);
}
static
void
add_reference(
char *symbol_name,
struct nlist *symbol,
struct image *image,
enum bool bind_now,
enum bool bind_fully)
{
struct nlist *ref_symbol;
module_state *ref_module;
struct image *ref_image;
struct library_image *ref_library_image;
enum link_state ref_link_state;
enum bool found;
struct symbol_list *being_linked;
enum bool flat_reference;
if(force_flat_namespace == FALSE)
flat_reference = (image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL;
else
flat_reference = TRUE;
if(flat_reference == FALSE){
add_to_undefined_list(symbol_name, symbol, image, bind_fully,
flat_reference);
return;
}
lookup_symbol(symbol_name, get_primary_image(image, symbol),
get_hint(image, symbol), get_weak(symbol), &ref_symbol,
&ref_module, &ref_image, &ref_library_image,NO_INDR_LOOP);
if(ref_symbol != NULL){
ref_link_state = GET_LINK_STATE(*ref_module);
if(ref_link_state == BEING_LINKED ||
ref_link_state == RELOCATED ||
ref_link_state == REGISTERING ||
ref_link_state == INITIALIZING ||
ref_link_state == LINKED ||
ref_link_state == FULLY_LINKED){
found = FALSE;
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
if(being_linked->symbol == ref_symbol){
found = TRUE;
break;
}
}
if(found == FALSE){
if((bind_fully == TRUE &&
GET_FULLYBOUND_STATE(*ref_module) == 0) ||
(bind_now == TRUE &&
ref_library_image != NULL &&
ref_link_state == LINKED) ){
add_to_undefined_list(symbol_name, ref_symbol,
ref_image, bind_fully, flat_reference);
}
else{
add_to_being_linked_list(symbol_name, ref_symbol,
ref_image, flat_reference);
}
}
else{
if((bind_fully == TRUE &&
GET_FULLYBOUND_STATE(*ref_module) == 0) ||
(bind_now == TRUE &&
ref_library_image != NULL &&
ref_link_state == LINKED) ){
being_linked->prev->next = being_linked->next;
being_linked->next->prev = being_linked->prev;
being_linked->prev = free_list.prev;
being_linked->next = &free_list;
being_linked->name = NULL;
being_linked->symbol = NULL;
being_linked->image = NULL;
being_linked->remove_on_error = FALSE;
being_linked->bind_fully = FALSE;
if(being_linked->flat_reference == TRUE)
flat_reference = TRUE;
being_linked->flat_reference = FALSE;
add_to_undefined_list(symbol_name, ref_symbol,
ref_image, bind_fully, flat_reference);
}
else if(flat_reference == TRUE &&
being_linked->flat_reference == FALSE){
being_linked->flat_reference = TRUE;
}
}
}
else{
add_to_undefined_list(symbol_name, ref_symbol, ref_image,
bind_fully, flat_reference);
}
}
else{
add_to_undefined_list(symbol_name, symbol, image, bind_fully,
flat_reference);
}
}
enum bool
link_object_module(
struct object_image *object_image,
enum bool bind_now,
enum bool bind_fully)
{
unsigned long i;
char *symbol_name;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
unsigned long *indirect_symtab;
struct nlist *symbols;
char *strings;
enum link_state link_state, saved_link_state;
struct nlist *prev_symbol;
module_state *prev_module;
struct image *prev_image;
struct library_image *prev_library_image;
enum link_state prev_link_state;
struct segment_command *prev_linkedit_segment;
struct symtab_command *prev_st;
struct dysymtab_command *prev_dyst;
struct nlist *prev_symbols;
char *prev_strings, *prev_library_name, *prev_module_name;
struct dylib_module *prev_dylib_modules, *prev_dylib_module;
unsigned long prev_module_index;
enum bool found;
struct symbol_list *being_linked;
enum bool flat_reference;
linkedit_segment = object_image->image.linkedit_segment;
st = object_image->image.st;
dyst = object_image->image.dyst;
symbols = (struct nlist *)
(object_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(object_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
if(force_flat_namespace == FALSE)
flat_reference = (object_image->image.mh->flags &
MH_TWOLEVEL) != MH_TWOLEVEL;
else
flat_reference = TRUE;
#ifdef FULLY_BIND_MOD_INIT_ROUTINES
if(bind_fully == FALSE &&
(object_image->image.init != NULL ||
object_image->image.init != NULL)){
bind_fully = TRUE;
bind_now = TRUE;
}
#endif
link_state = GET_LINK_STATE(object_image->module);
if(link_state == LINKED || link_state == BEING_LINKED)
goto add_undefineds;
if(object_image->image.private == TRUE ||
(force_flat_namespace == TRUE ||
(object_image->image.mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL)){
if(object_image->image.has_coalesced_sections == FALSE)
goto add_undefineds;
indirect_symtab = (unsigned long *)
(object_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->indirectsymoff -
linkedit_segment->fileoff);
for(i = 0; i < dyst->nindirectsyms; i++){
if(indirect_symtab[i] != INDIRECT_SYMBOL_LOCAL &&
indirect_symtab[i] != INDIRECT_SYMBOL_ABS &&
is_symbol_coalesced(&(object_image->image),
symbols + indirect_symtab[i]) == TRUE){
relocate_symbol_pointers(
indirect_symtab[i],
indirect_symtab,
&(object_image->image),
symbols[indirect_symtab[i]].n_value +
object_image->image.vmaddr_slide,
FALSE);
}
}
goto add_undefineds;
}
if(force_flat_namespace == FALSE &&
(object_image->image.mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL)
goto add_undefineds;
saved_link_state = GET_LINK_STATE(object_image->module);
SET_LINK_STATE(object_image->module, UNUSED);
for(i = dyst->iextdefsym;
i < dyst->iextdefsym + dyst->nextdefsym;
i++){
symbol_name = strings + symbols[i].n_un.n_strx;
lookup_symbol(symbol_name, NULL, NULL, FALSE,
&prev_symbol, &prev_module, &prev_image,
&prev_library_image, NO_INDR_LOOP);
if(prev_symbol != NULL && &object_image->module != prev_module &&
prev_image != NULL &&
(force_flat_namespace == FALSE &&
(prev_image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL)){
prev_link_state = GET_LINK_STATE(*prev_module);
if(prev_link_state == BEING_LINKED ||
prev_link_state == RELOCATED ||
prev_link_state == REGISTERING ||
prev_link_state == INITIALIZING ||
prev_link_state == LINKED ||
prev_link_state == FULLY_LINKED){
prev_linkedit_segment = prev_image->linkedit_segment;
prev_st = prev_image->st;
prev_dyst = prev_image->dyst;
prev_symbols = (struct nlist *)
(prev_image->vmaddr_slide +
prev_linkedit_segment->vmaddr +
prev_st->symoff -
prev_linkedit_segment->fileoff);
prev_strings = (char *)
(prev_image->vmaddr_slide +
prev_linkedit_segment->vmaddr +
prev_st->stroff -
prev_linkedit_segment->fileoff);
prev_dylib_modules = (struct dylib_module *)
(prev_image->vmaddr_slide +
prev_linkedit_segment->vmaddr +
prev_dyst->modtaboff -
prev_linkedit_segment->fileoff);
if(prev_library_image != NULL){
prev_module_index = prev_module -
prev_library_image->modules;
prev_dylib_module = prev_dylib_modules +
prev_module_index;
prev_library_name = prev_image->name;
prev_module_name = prev_strings +
prev_dylib_module->module_name;
}
else{
prev_library_name = NULL;
prev_module_name = prev_image->physical_name;
}
if((object_image->image.has_coalesced_sections == TRUE &&
(are_symbols_coalesced(&(object_image->image),
symbols + i, prev_image, prev_symbol) == TRUE ||
is_symbol_coalesced_and_weak(&(object_image->image),
symbols + i))) ||
(prev_image->has_coalesced_sections == TRUE &&
is_symbol_coalesced_and_weak(prev_image,
prev_symbol) == TRUE) ){
found = FALSE;
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
if(being_linked->symbol == prev_symbol){
found = TRUE;
break;
}
}
if(prev_image->has_coalesced_sections == TRUE &&
is_symbol_coalesced_and_weak(prev_image,
prev_symbol) == TRUE){
if(found == TRUE){
being_linked->prev->next = being_linked->next;
being_linked->next->prev = being_linked->prev;
being_linked->prev = free_list.prev;
being_linked->next = &free_list;
being_linked->name = NULL;
being_linked->symbol = NULL;
being_linked->image = NULL;
being_linked->remove_on_error = FALSE;
being_linked->bind_fully = FALSE;
being_linked->flat_reference = FALSE;
}
found = FALSE;
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
if(being_linked->symbol == symbols + i){
found = TRUE;
break;
}
}
if(found == FALSE)
add_to_being_linked_list(symbol_name,
symbols + i, &(object_image->image),
flat_reference);
}
else{
discard_symbol(&(object_image->image), symbols + i);
if(found == FALSE)
add_to_being_linked_list(symbol_name,
prev_symbol, prev_image, flat_reference);
}
continue;
}
multiply_defined_error(symbol_name,
&(object_image->image),
symbols + i,
&object_image->module,
NULL,
object_image->image.physical_name,
prev_image,
prev_symbol,
prev_module,
prev_library_name,
prev_module_name);
if(return_on_error == TRUE){
SET_LINK_STATE(object_image->module, saved_link_state);
return(FALSE);
}
}
else{
if(object_image->image.has_coalesced_sections == TRUE &&
is_symbol_coalesced(&(object_image->image),
symbols + i) == TRUE){
add_to_being_linked_list(symbol_name, symbols + i,
&(object_image->image),
flat_reference);
}
}
}
else{
if(object_image->image.has_coalesced_sections == TRUE &&
is_symbol_coalesced(&(object_image->image),
symbols + i) == TRUE){
add_to_being_linked_list(symbol_name, symbols + i,
&(object_image->image),
flat_reference);
}
}
}
SET_LINK_STATE(object_image->module, saved_link_state);
add_undefineds:
for(i = dyst->iundefsym; i < dyst->iundefsym + dyst->nundefsym; i++){
if(bind_now == TRUE ||
bind_fully == TRUE ||
executable_bind_at_load == TRUE ||
(symbols[i].n_desc & REFERENCE_TYPE) ==
REFERENCE_FLAG_UNDEFINED_NON_LAZY){
symbol_name = strings + symbols[i].n_un.n_strx;
add_reference(symbol_name, symbols + i, &(object_image->image),
bind_now, bind_fully);
}
}
link_state = GET_LINK_STATE(object_image->module);
if(bind_now == FALSE){
if(link_state != LINKED && link_state != FULLY_LINKED)
SET_LINK_STATE(object_image->module, BEING_LINKED);
}
else{
if(link_state != LINKED && link_state != FULLY_LINKED)
SET_LINK_STATE(object_image->module, BEING_LINKED);
else
SET_LINK_STATE(object_image->module, FULLY_LINKED);
}
if(bind_fully == TRUE)
SET_FULLYBOUND_STATE(object_image->module);
if(bind_fully == TRUE || bind_now == TRUE)
object_image->image.some_modules_being_bound_fully = TRUE;
return(TRUE);
}
void
unlink_object_module(
struct object_image *object_image,
enum bool reset_lazy_references)
{
unsigned long i;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
char *strings, *symbol_name;
char *reference_name;
struct nlist *referenced_symbol;
module_state *referenced_module;
struct image *referenced_image;
struct library_image *referenced_library_image;
linkedit_segment = object_image->image.linkedit_segment;
st = object_image->image.st;
dyst = object_image->image.dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
return;
symbols = (struct nlist *)
(object_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(object_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
for(i = 0; i < dyst->nextdefsym; i++){
symbol = symbols + dyst->iextdefsym + i;
if(symbol->n_un.n_strx == 0)
continue;
symbol_name = strings + symbol->n_un.n_strx;
reference_name = look_for_flat_reference(symbol_name,
&referenced_symbol,
&referenced_module, &referenced_image,
&referenced_library_image,
reset_lazy_references);
if(reference_name != NULL){
add_to_undefined_list(reference_name, referenced_symbol,
referenced_image, FALSE, TRUE);
}
if(reset_lazy_references == TRUE){
change_symbol_pointers_in_flat_images(symbol_name,
(unsigned long)&unlinked_lazy_pointer_handler,
TRUE );
}
}
}
void
lookup_symbol(
char *symbol_name,
struct image *primary_image,
struct twolevel_hint *hint,
enum bool weak_symbol,
struct nlist **defined_symbol,
module_state **defined_module,
struct image **defined_image,
struct library_image **defined_library_image,
struct indr_loop_list *indr_loop)
{
unsigned long i, itoc;
struct object_images *p;
struct library_images *q;
struct library_image *outer_library_image;
struct object_image *outer_object_image;
struct object_image *object_image_found;
DYLD_TRACE_SYMBOLS_NAMED_START(DYLD_TRACE_lookup_symbol, symbol_name);
*defined_symbol = NULL;
*defined_module = NULL;
*defined_image = NULL;
*defined_library_image = NULL;
if(primary_image != NULL){
if(primary_image ==
(struct image *)&(some_weak_library_image.image)){
weak_symbol = TRUE;
goto weak_library_symbol;
}
if(primary_image->mh->filetype != MH_DYLIB){
outer_object_image = (struct object_image *)
primary_image->outer_image;
if(lookup_symbol_in_object_image(symbol_name, primary_image,
&(outer_object_image->module), defined_symbol,
defined_module, defined_image, defined_library_image,
indr_loop) == TRUE){
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
}
else{
itoc = ULONG_MAX;
if(hint != NULL && primary_image->subs_can_use_hints == TRUE){
if(hint->isub_image != 0){
if((unsigned long)(hint->isub_image - 1) <
primary_image->nsub_images){
if(primary_image->sub_images[hint->isub_image - 1]->
mh->filetype == MH_DYLIB){
outer_library_image = (struct library_image *)
primary_image->sub_images[hint->isub_image -
1]->outer_image;
if(lookup_symbol_in_library_image(symbol_name,
hint->itoc,
primary_image->sub_images[
hint->isub_image - 1],
outer_library_image->modules,
outer_library_image, defined_symbol,
defined_module, defined_image,
defined_library_image, indr_loop) ==
TRUE){
if(dyld_hints_debug > 1)
print("hint for symbol: %s into "
"sub-image: %s of image: %s "
"worked\n", symbol_name,
primary_image->sub_images[
hint->isub_image - 1]->name,
primary_image->name);
DYLD_TRACE_SYMBOLS_END(
DYLD_TRACE_lookup_symbol);
return;
}
}
}
if(dyld_hints_debug > 1)
print("hint for symbol: %s into image: %s failed\n",
symbol_name, primary_image->name);
}
else{
itoc = hint->itoc;
}
}
outer_library_image = (struct library_image *)
primary_image->outer_image;
if(lookup_symbol_in_library_image(symbol_name, itoc,
primary_image, outer_library_image->modules,
outer_library_image, defined_symbol, defined_module,
defined_image, defined_library_image,indr_loop) ==TRUE){
if(dyld_hints_debug > 1 && itoc != ULONG_MAX)
print("hint for symbol: %s into image: %s worked\n",
symbol_name, primary_image->name);
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
if(dyld_hints_debug > 1 && itoc != ULONG_MAX)
print("hint for symbol: %s into image: %s failed\n",
symbol_name, primary_image->name);
}
for(i = 0; i < primary_image->nsub_images; i++){
if(primary_image->sub_images[i]->mh->filetype != MH_DYLIB){
outer_object_image = (struct object_image *)
primary_image->sub_images[i]->outer_image;
if(lookup_symbol_in_object_image(symbol_name,
primary_image->sub_images[i],
&(outer_object_image->module), defined_symbol,
defined_module, defined_image,
defined_library_image, indr_loop) == TRUE){
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
}
else{
outer_library_image = (struct library_image *)
primary_image->sub_images[i]->outer_image;
if(lookup_symbol_in_library_image(symbol_name, ULONG_MAX,
primary_image->sub_images[i],
outer_library_image->modules, outer_library_image,
defined_symbol, defined_module, defined_image,
defined_library_image, indr_loop) == TRUE){
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
}
}
weak_library_symbol:
if(defined_symbol != NULL && weak_symbol == TRUE){
*defined_symbol = (struct nlist *)&some_weak_symbol;
*defined_module = (module_state *)&some_weak_module;;
if(primary_image ==
(struct image *)&(some_weak_library_image.image)){
*defined_image =
(struct image *)&(some_weak_library_image.image);
*defined_library_image =
(struct library_image *)&some_weak_library_image;
}
else{
*defined_image = primary_image;
if(primary_image->mh->filetype == MH_DYLIB)
*defined_library_image = (struct library_image *)
primary_image->outer_image;
else
*defined_library_image = NULL;
}
}
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
if(object_image_locator != NULL){
release_lock();
object_image_found = (*object_image_locator)(symbol_name);
set_lock();
if(object_image_found != NULL){
if(object_image_found == (struct object_image *)(-1)){
return;
}
if(lookup_symbol_in_object_image(symbol_name,
&(object_image_found->image),
&(object_image_found->module),
defined_symbol, defined_module, defined_image,
defined_library_image, indr_loop) == TRUE){
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
}
}
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
if(p->images[i].image.private == TRUE)
continue;
if(lookup_symbol_in_object_image(symbol_name,
&(p->images[i].image), &(p->images[i].module),
defined_symbol, defined_module, defined_image,
defined_library_image, indr_loop) == TRUE){
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
}
p = p->next_images;
}while(p != NULL);
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(lookup_symbol_in_library_image(symbol_name, ULONG_MAX,
&(q->images[i].image), q->images[i].modules,
&(q->images[i]), defined_symbol, defined_module,
defined_image, defined_library_image, indr_loop) ==
TRUE){
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
return;
}
}
q = q->next_images;
}while(q != NULL);
if(defined_symbol != NULL && weak_symbol == TRUE){
*defined_symbol = (struct nlist *)&some_weak_symbol;
*defined_module = (module_state *)&some_weak_module;;
*defined_image = (struct image *)&(some_weak_library_image.image);
*defined_library_image =
(struct library_image *)&some_weak_library_image;
}
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_lookup_symbol);
}
static
struct image *
get_indr_image(
char *symbol_name,
struct image *image)
{
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
char *strings;
struct dylib_table_of_contents *tocs, *toc;
unsigned long symbol_index;
struct image *indr_image;
if(force_flat_namespace == TRUE ||
(image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL)
return(NULL);
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
if(image->mh->filetype != MH_DYLIB){
nlist_bsearch_strings = strings;
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym);
if(symbol == NULL)
return(NULL);
indr_image = get_primary_image(image, symbol);
}
else{
tocs = (struct dylib_table_of_contents *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = symbols;
toc_bsearch_strings = strings;
toc = inline_bsearch_toc(symbol_name, tocs, dyst->ntoc);
if(toc != NULL){
symbol_index = toc->symbol_index;
}
else{
nlist_bsearch_strings = strings;
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym);
if(symbol == NULL)
return(NULL);
symbol_index = symbol - symbols;
}
indr_image = get_primary_image(image, symbols + symbol_index);
}
return(indr_image);
}
enum bool
lookup_symbol_in_object_image(
char *symbol_name,
struct image *object_image,
module_state *object_module,
struct nlist **defined_symbol,
module_state **defined_module,
struct image **defined_image,
struct library_image **defined_library_image,
struct indr_loop_list *indr_loop)
{
enum link_state link_state;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
struct indr_loop_list new_indr_loop, *loop, *l;
char *strings, *module_name;
struct dylib_module *dylib_modules, *dylib_module;
unsigned long module_index;
struct image *indr_image;
link_state = GET_LINK_STATE(*object_module);
if(link_state == UNUSED)
return(FALSE);
linkedit_segment = object_image->linkedit_segment;
st = object_image->st;
dyst = object_image->dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
return(FALSE);
symbols = (struct nlist *)
(object_image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
nlist_bsearch_strings = (char *)
(object_image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iextdefsym,
dyst->nextdefsym);
if(symbol != NULL &&
(symbol->n_desc & N_DESC_DISCARDED) == 0){
if((symbol->n_type & N_TYPE) == N_INDR &&
indr_loop != NO_INDR_LOOP){
for(loop = indr_loop; loop != NULL; loop = loop->next){
if(loop->defined_symbol == symbol &&
loop->defined_module == object_module &&
loop->defined_image == object_image &&
loop->defined_library_image == NULL){
error("indirect symbol loop:");
for(l = indr_loop; l != NULL; l = l->next){
linkedit_segment =
l->defined_image->linkedit_segment;
st = l->defined_image->st;
strings = (char *)
(l->defined_image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
if(l->defined_library_image != NULL){
dyst = l->defined_image->dyst;
dylib_modules =
(struct dylib_module *)
(l->defined_image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
module_index = l->defined_module -
l->defined_library_image->modules;
dylib_module = dylib_modules +
module_index;
module_name = strings +
dylib_module->module_name;
add_error_string("%s(%s) definition of "
"%s as indirect for %s\n",
l->defined_image->name, module_name,
strings +
l->defined_symbol->n_un.n_strx,
strings +
l->defined_symbol->n_value);
}
else{
add_error_string("%s definition of "
"%s as indirect for %s\n",
l->defined_image->name,
strings +
l->defined_symbol->n_un.n_strx,
strings +
l->defined_symbol->n_value);
}
if(l == loop)
break;
}
link_edit_error(DYLD_OTHER_ERROR,
DYLD_INDR_LOOP, NULL);
return(FALSE);
}
}
new_indr_loop.defined_symbol = symbol;
new_indr_loop.defined_module = object_module;
new_indr_loop.defined_image = object_image;
new_indr_loop.defined_library_image = NULL;
new_indr_loop.next = indr_loop;
symbol_name = nlist_bsearch_strings + symbol->n_value;
indr_image = get_indr_image(symbol_name,
new_indr_loop.defined_image);
lookup_symbol(symbol_name, indr_image, NULL, FALSE,
defined_symbol, defined_module, defined_image,
defined_library_image, &new_indr_loop);
return(defined_symbol != NULL);
}
else{
if(executable_bind_at_load != TRUE ||
*defined_symbol == NULL){
*defined_symbol = symbol;
*defined_module = object_module;
*defined_image = object_image;
*defined_library_image = NULL;
}
if(executable_bind_at_load == TRUE){
if(link_state == BEING_LINKED ||
link_state == RELOCATED ||
link_state == REGISTERING ||
link_state == INITIALIZING ||
link_state == LINKED ||
link_state == FULLY_LINKED){
*defined_symbol = symbol;
*defined_module = object_module;
*defined_image = object_image;
*defined_library_image = NULL;
return(TRUE);
}
else
return(FALSE);
}
return(TRUE);
}
}
return(FALSE);
}
static
enum bool
lookup_symbol_in_library_image(
char *symbol_name,
unsigned long itoc,
struct image *image,
module_state *library_modules,
struct library_image *library_image,
struct nlist **defined_symbol,
module_state **defined_module,
struct image **defined_image,
struct library_image **defined_library_image,
struct indr_loop_list *indr_loop)
{
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbol;
struct dylib_table_of_contents *tocs, *toc;
struct indr_loop_list new_indr_loop, *loop, *l;
char *strings, *module_name;
struct dylib_module *dylib_modules, *dylib_module;
unsigned long module_index;
enum link_state link_state;
struct image *indr_image;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
tocs = (struct dylib_table_of_contents *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
toc_bsearch_strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
toc = inline_bsearch_toc_with_index(symbol_name, tocs, dyst->ntoc,itoc);
if(toc != NULL &&
(toc_bsearch_symbols[toc->symbol_index].n_desc &
N_DESC_DISCARDED) == 0){
symbol = toc_bsearch_symbols + toc->symbol_index;
if((symbol->n_type & N_TYPE) == N_INDR &&
indr_loop != NO_INDR_LOOP){
for(loop = indr_loop; loop != NULL; loop = loop->next){
if(loop->defined_symbol ==
toc_bsearch_symbols + toc->symbol_index &&
loop->defined_module ==
library_modules + toc->module_index &&
loop->defined_image == image &&
loop->defined_library_image == library_image){
error("indirect symbol loop:");
for(l = indr_loop; l != NULL; l = l->next){
linkedit_segment =
l->defined_image->linkedit_segment;
st = l->defined_image->st;
strings = (char *)
(l->defined_image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
if(l->defined_library_image != NULL){
dyst = l->defined_image->dyst;
dylib_modules =
(struct dylib_module *)
(l->defined_image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
module_index = l->defined_module -
l->defined_library_image->modules;
dylib_module = dylib_modules +
module_index;
module_name = strings +
dylib_module->module_name;
add_error_string("%s(%s) definition of "
"%s as indirect for %s\n",
l->defined_image->name, module_name,
strings +
l->defined_symbol->n_un.n_strx,
strings +
l->defined_symbol->n_value);
}
else{
add_error_string("%s definition of "
"%s as indirect for %s\n",
l->defined_image->name,
strings +
l->defined_symbol->n_un.n_strx,
strings +
l->defined_symbol->n_value);
}
if(l == loop)
break;
}
link_edit_error(DYLD_OTHER_ERROR,
DYLD_INDR_LOOP, NULL);
return(FALSE);
}
}
new_indr_loop.defined_symbol =
toc_bsearch_symbols + toc->symbol_index;
new_indr_loop.defined_module =
library_modules + toc->module_index;
new_indr_loop.defined_image = image;
new_indr_loop.defined_library_image = library_image;
new_indr_loop.next = indr_loop;
symbol_name = toc_bsearch_strings + symbol->n_value;
indr_image = get_indr_image(symbol_name,
new_indr_loop.defined_image);
lookup_symbol(symbol_name, indr_image, NULL, FALSE,
defined_symbol, defined_module, defined_image,
defined_library_image, &new_indr_loop);
return(defined_symbol != NULL);
}
else{
if(executable_bind_at_load != TRUE ||
*defined_symbol == NULL){
*defined_symbol =
toc_bsearch_symbols + toc->symbol_index;
*defined_module =
library_modules + toc->module_index;
*defined_image = image;
*defined_library_image = library_image;
}
if(executable_bind_at_load == TRUE){
link_state = GET_LINK_STATE(*(library_modules +
toc->module_index));
if(link_state == BEING_LINKED ||
link_state == RELOCATED ||
link_state == REGISTERING ||
link_state == INITIALIZING ||
link_state == LINKED ||
link_state == FULLY_LINKED){
*defined_symbol =
toc_bsearch_symbols + toc->symbol_index;
*defined_module =
library_modules + toc->module_index;
*defined_image = image;
*defined_library_image = library_image;
return(TRUE);
}
else
return(FALSE);
}
return(TRUE);
}
}
return(FALSE);
}
void
lookup_symbol_in_hinted_library(
char *symbol_name,
char *hinted_library,
struct nlist **defined_symbol,
module_state **defined_module,
struct image **defined_image,
struct library_image **defined_library_image)
{
unsigned long i;
struct library_images *q;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbol;
struct dylib_table_of_contents *tocs, *toc;
enum link_state link_state;
*defined_symbol = NULL;
*defined_module = NULL;
*defined_image = NULL;
*defined_library_image = NULL;
if(hinted_library == NULL)
return;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(strstr(q->images[i].image.name, hinted_library) == NULL)
continue;
linkedit_segment = q->images[i].image.linkedit_segment;
st = q->images[i].image.st;
dyst = q->images[i].image.dyst;
tocs = (struct dylib_table_of_contents *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = (struct nlist *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
toc_bsearch_strings = (char *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
toc = inline_bsearch_toc(symbol_name, tocs, dyst->ntoc);
if(toc != NULL &&
(toc_bsearch_symbols[toc->symbol_index].n_desc &
N_DESC_DISCARDED) == 0){
symbol = toc_bsearch_symbols + toc->symbol_index;
if((symbol->n_type & N_TYPE) == N_INDR)
return;
link_state = GET_LINK_STATE(*(q->images[i].modules +
toc->module_index));
if(link_state == BEING_LINKED ||
link_state == RELOCATED ||
link_state == REGISTERING ||
link_state == INITIALIZING ||
link_state == LINKED ||
link_state == FULLY_LINKED){
*defined_symbol =
toc_bsearch_symbols + toc->symbol_index;
*defined_module =
q->images[i].modules + toc->module_index;
*defined_image = &(q->images[i].image);
*defined_library_image = &(q->images[i]);
}
}
return;
}
q = q->next_images;
}while(q != NULL);
}
static
char *
look_for_flat_reference(
char *symbol_name,
struct nlist **referenced_symbol,
module_state **referenced_module,
struct image **referenced_image,
struct library_image **referenced_library_image,
enum bool ignore_lazy_references)
{
unsigned long i, j, k, isym;
struct object_images *p;
struct library_images *q;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
struct dylib_table_of_contents *tocs, *toc;
struct dylib_module *dylib_modules;
struct dylib_reference *dylib_references;
char *reference_name;
enum link_state link_state;
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state == UNUSED)
continue;
if(force_flat_namespace == FALSE &&
(p->images[i].image.mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL)
continue;
linkedit_segment = p->images[i].image.linkedit_segment;
st = p->images[i].image.st;
dyst = p->images[i].image.dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
continue;
symbols = (struct nlist *)
(p->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
nlist_bsearch_strings = (char *)
(p->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
if(p->images[i].image.mh->flags & MH_BINDATLOAD)
symbol = nlist_linear_search(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym,
nlist_bsearch_strings);
else
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iundefsym,
dyst->nundefsym);
if(symbol != NULL){
if(ignore_lazy_references == TRUE &&
(symbol->n_desc & REFERENCE_TYPE) ==
REFERENCE_FLAG_UNDEFINED_LAZY)
continue;
*referenced_symbol = symbol;
*referenced_module = &(p->images[i].module);
*referenced_image = &(p->images[i].image);
*referenced_library_image = NULL;
reference_name = nlist_bsearch_strings +
symbol->n_un.n_strx;
return(reference_name);
}
}
p = p->next_images;
}while(p != NULL);
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(force_flat_namespace == FALSE &&
(q->images[i].image.mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL)
continue;
linkedit_segment = q->images[i].image.linkedit_segment;
st = q->images[i].image.st;
dyst = q->images[i].image.dyst;
tocs = (struct dylib_table_of_contents *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = (struct nlist *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
toc_bsearch_strings = (char *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
toc = inline_bsearch_toc(symbol_name, tocs, dyst->ntoc);
if(toc != NULL){
symbol = toc_bsearch_symbols + toc->symbol_index;
isym = toc->symbol_index;
}
else{
nlist_bsearch_strings = toc_bsearch_strings;
symbol = inline_bsearch_nlist(symbol_name,
toc_bsearch_symbols + dyst->iundefsym,
dyst->nundefsym);
if(symbol == NULL)
continue;
isym = symbol - toc_bsearch_symbols;
}
reference_name = nlist_bsearch_strings + symbol->n_un.n_strx;
dylib_modules = (struct dylib_module *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
dylib_references = (struct dylib_reference *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->extrefsymoff -
linkedit_segment->fileoff);
for(j = 0; j < dyst->nmodtab; j++){
link_state = GET_LINK_STATE(q->images[i].modules[j]);
if(link_state == BEING_LINKED ||
link_state == RELOCATED ||
link_state == REGISTERING ||
link_state == INITIALIZING ||
link_state == LINKED ||
link_state == FULLY_LINKED){
for(k = dylib_modules[j].irefsym;
k < dylib_modules[j].irefsym +
dylib_modules[j].nrefsym;
k++){
if(dylib_references[k].isym == isym){
if(dylib_references[k].flags ==
REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
(dylib_references[k].flags ==
REFERENCE_FLAG_UNDEFINED_LAZY &&
ignore_lazy_references == FALSE)){
*referenced_symbol = symbol;
*referenced_module =
q->images[i].modules + j;
*referenced_image =
&(q->images[i].image);
*referenced_library_image =
&(q->images[i]);
return(reference_name);
}
}
}
}
}
}
q = q->next_images;
}while(q != NULL);
*referenced_symbol = NULL;
*referenced_module = NULL;
*referenced_image = NULL;
*referenced_library_image = NULL;
return(NULL);
}
static
struct nlist *
nlist_linear_search(
char *symbol_name,
struct nlist *symbols,
unsigned long nsymbols,
char *strings)
{
unsigned long i;
for(i = 0; i < nsymbols; i++){
if(strcmp(symbol_name, strings + symbols[i].n_un.n_strx) == 0)
return(symbols + i);
}
return(NULL);
}
enum bool
validate_NSSymbol(
struct nlist *symbol,
module_state **defined_module,
struct image **defined_image,
struct library_image **defined_library_image)
{
unsigned long i, j, isym;
struct object_images *p;
struct library_images *q;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols;
struct dylib_module *dylib_modules;
enum link_state link_state;
*defined_module = NULL;
*defined_image = NULL;
*defined_library_image = NULL;
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state == UNUSED)
continue;
linkedit_segment = p->images[i].image.linkedit_segment;
st = p->images[i].image.st;
dyst = p->images[i].image.dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
continue;
symbols = (struct nlist *)
(p->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
if(symbol >= symbols + dyst->iextdefsym &&
symbol < symbols + (dyst->iextdefsym + dyst->nextdefsym)){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state != INITIALIZING &&
link_state != LINKED &&
link_state != FULLY_LINKED)
return(FALSE);
if((symbol->n_desc & N_DESC_DISCARDED) == N_DESC_DISCARDED)
return(FALSE);
*defined_module = &(p->images[i].module);
*defined_image = &(p->images[i].image);
*defined_library_image = NULL;
return(TRUE);
}
}
p = p->next_images;
}while(p != NULL);
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
linkedit_segment = q->images[i].image.linkedit_segment;
st = q->images[i].image.st;
dyst = q->images[i].image.dyst;
symbols = (struct nlist *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
if(symbol >= symbols + dyst->iextdefsym &&
symbol < symbols + (dyst->iextdefsym + dyst->nextdefsym)){
if((symbol->n_desc & N_DESC_DISCARDED) == N_DESC_DISCARDED)
return(FALSE);
isym = symbol - symbols;
dylib_modules = (struct dylib_module *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->modtaboff -
linkedit_segment->fileoff);
for(j = 0; j < dyst->nmodtab; j++){
if(isym >= dylib_modules[j].iextdefsym &&
isym < dylib_modules[j].iextdefsym +
dylib_modules[j].nextdefsym)
break;
}
if(j >= dyst->nmodtab)
return(FALSE);
link_state = GET_LINK_STATE(q->images[i].modules[j]);
if(link_state != INITIALIZING &&
link_state != LINKED &&
link_state != FULLY_LINKED)
return(FALSE);
*defined_module = q->images[i].modules + j;
*defined_image = &(q->images[i].image);
*defined_library_image = q->images + i;
return(TRUE);
}
}
q = q->next_images;
}while(q != NULL);
return(FALSE);
}
enum bool
validate_NSModule(
module_state *module,
struct image **defined_image,
struct library_image **defined_library_image)
{
unsigned long i;
struct object_images *p;
struct library_images *q;
enum link_state link_state;
*defined_image = NULL;
*defined_library_image = NULL;
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state == UNUSED)
continue;
if(&(p->images[i].module) == module){
*defined_image = &(p->images[i].image);
*defined_library_image = NULL;
return(TRUE);
}
}
p = p->next_images;
}while(p != NULL);
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(module >= q->images[i].modules &&
module < q->images[i].modules + q->images[i].nmodules){
*defined_image = &(q->images[i].image);
*defined_library_image = q->images + i;
return(TRUE);
}
}
q = q->next_images;
}while(q != NULL);
return(FALSE);
}
void
relocate_symbol_pointers_in_object_image(
struct image *image)
{
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
unsigned long *indirect_symtab;
struct symbol_list *symbol_list;
char *symbol_name, *strings;
unsigned long value, symbol_index;
struct nlist *defined_symbol;
module_state *defined_module;
struct image *defined_image;
struct library_image *defined_library_image;
struct image *primary_image;
unsigned long i;
enum bool match;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
return;
if(force_flat_namespace == FALSE &&
(image->mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL &&
image->mh->filetype != MH_BUNDLE &&
image->some_modules_being_bound_fully == FALSE){
if(image->non_lazy_symbol_pointers_resolved == FALSE)
resolve_non_lazy_symbol_pointers_in_image(image);
return;
}
symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
indirect_symtab = (unsigned long *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->indirectsymoff -
linkedit_segment->fileoff);
nlist_bsearch_strings = strings;
for(symbol_list = being_linked_list.next;
symbol_list != &being_linked_list;
symbol_list = symbol_list->next){
symbol_name = symbol_list->name;
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iextdefsym, dyst->nextdefsym);
if(symbol == NULL){
if(image->mh->flags & MH_BINDATLOAD)
symbol = nlist_linear_search(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym,
nlist_bsearch_strings);
else
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym);
}
if(symbol == NULL)
continue;
symbol_index = symbol - symbols;
if(force_flat_namespace == FALSE &&
(image->mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL){
if(GET_LIBRARY_ORDINAL(symbol->n_desc) == EXECUTABLE_ORDINAL)
primary_image = &object_images.images[0].image;
else if(GET_LIBRARY_ORDINAL(symbol->n_desc) ==
DYNAMIC_LOOKUP_ORDINAL &&
image->ndependent_images != DYNAMIC_LOOKUP_ORDINAL)
primary_image = symbol_list->image;
else if(GET_LIBRARY_ORDINAL(symbol->n_desc) ==
SELF_LIBRARY_ORDINAL)
primary_image = image;
else{
primary_image = image->dependent_images[
GET_LIBRARY_ORDINAL(symbol->n_desc) - 1];
}
if(primary_image != symbol_list->image){
match = FALSE;
for(i = 0;
i < symbol_list->image->numbrella_images;
i++){
if(primary_image ==
symbol_list->image->umbrella_images[i]){
match = TRUE;
break;
}
}
if(match != TRUE)
continue;
}
}
else{
if(symbol_list->flat_reference == FALSE)
continue;
}
if(symbol_list->symbol != NULL &&
(symbol_list->symbol->n_type & N_TYPE) == N_INDR){
lookup_symbol(symbol_name,
get_primary_image(symbol_list->image,
symbol_list->symbol),
get_hint(symbol_list->image, symbol_list->symbol),
get_weak(symbol_list->symbol),
&defined_symbol, &defined_module, &defined_image,
&defined_library_image, NULL);
nlist_bsearch_strings = strings;
value = defined_symbol->n_value;
if((defined_symbol->n_type & N_TYPE) != N_ABS)
value += defined_image->vmaddr_slide;
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit +
dyld_image_vmaddr_slide;
#endif
relocate_symbol_pointers(symbol_index, indirect_symtab,
image, value, FALSE);
}
else{
value = symbol_list->symbol->n_value;
if((symbol_list->symbol->n_type & N_TYPE) != N_ABS)
value += symbol_list->image->vmaddr_slide;
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit +
dyld_image_vmaddr_slide;
#endif
relocate_symbol_pointers(symbol_index, indirect_symtab,
image, value, FALSE);
}
}
}
static
void
resolve_non_lazy_symbol_pointers_in_image(
struct image *image)
{
unsigned long i, j, k, section_type, size, vmaddr_slide, reserved1, addr;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
unsigned long *indirect_symtab;
char *symbol_name, *strings;
unsigned long symbol_index, indirect_symtab_count;
unsigned long value, *non_lazy_symbol_pointer_addr;
struct nlist *defined_symbol;
module_state *defined_module;
struct image *defined_image;
struct library_image *defined_library_image;
enum bool skip_symbol_index_zero, found;
enum bool checked_for_symbol_index_zero_being_linked;
struct symbol_list *being_linked;
skip_symbol_index_zero = FALSE;
checked_for_symbol_index_zero_being_linked = FALSE;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
return;
symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
indirect_symtab = (unsigned long *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->indirectsymoff -
linkedit_segment->fileoff);
indirect_symtab_count = dyst->nindirectsyms;
lc = (struct load_command *)((char *)image->mh +
sizeof(struct mach_header));
vmaddr_slide = image->vmaddr_slide;
for(i = 0; i < image->mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
size = s->size;
reserved1 = s->reserved1;
addr = s->addr;
section_type = s->flags & SECTION_TYPE;
if(section_type == S_NON_LAZY_SYMBOL_POINTERS){
for(k = 0; k < size / sizeof(unsigned long); k++){
symbol_index = indirect_symtab[reserved1 + k];
if(symbol_index == INDIRECT_SYMBOL_ABS ||
symbol_index == INDIRECT_SYMBOL_LOCAL)
continue;
if(symbol_index == 0 &&
skip_symbol_index_zero == TRUE)
continue;
symbol = symbols + symbol_index;
symbol_name = strings + symbol->n_un.n_strx;
if(image == &(object_images.images[0].image) &&
symbol_index == 0 &&
checked_for_symbol_index_zero_being_linked ==
FALSE){
checked_for_symbol_index_zero_being_linked =
TRUE;
found = FALSE;
for(being_linked = being_linked_list.next;
being_linked != &being_linked_list;
being_linked = being_linked->next){
if(being_linked->image != image &&
being_linked->name == symbol_name){
found = TRUE;
break;
}
}
if(found == FALSE){
skip_symbol_index_zero = TRUE;
continue;
}
}
lookup_symbol(symbol_name,
get_primary_image(image, symbol),
get_hint(image, symbol),
get_weak(symbol), &defined_symbol,
&defined_module, &defined_image,
&defined_library_image, NULL);
if(defined_symbol == NULL)
continue;
value = defined_symbol->n_value;
if((defined_symbol->n_type & N_TYPE) != N_ABS)
value += defined_image->vmaddr_slide;
non_lazy_symbol_pointer_addr = (unsigned long *)
(vmaddr_slide + addr + (k * sizeof(long)));
if(*non_lazy_symbol_pointer_addr != value)
*non_lazy_symbol_pointer_addr = value;
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
image->non_lazy_symbol_pointers_resolved = TRUE;
}
void
relocate_symbol_pointers_in_library_image(
struct image *image)
{
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct dylib_table_of_contents *tocs, *toc;
unsigned long *indirect_symtab;
struct nlist *symbols, *symbol;
char *strings;
struct symbol_list *symbol_list;
char *symbol_name;
unsigned long value, symbol_index;
struct nlist *defined_symbol;
module_state *defined_module;
struct image *defined_image;
struct library_image *defined_library_image;
struct image *primary_image;
unsigned long i;
enum bool match;
if(force_flat_namespace == FALSE &&
(image->mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL &&
image->some_modules_being_bound_fully == FALSE){
if(image->non_lazy_symbol_pointers_resolved == FALSE)
resolve_non_lazy_symbol_pointers_in_image(image);
return;
}
image->some_modules_being_bound_fully = FALSE;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
tocs = (struct dylib_table_of_contents *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
indirect_symtab = (unsigned long *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->indirectsymoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = symbols;
toc_bsearch_strings = strings;
nlist_bsearch_strings = strings;
for(symbol_list = being_linked_list.next;
symbol_list != &being_linked_list;
symbol_list = symbol_list->next){
symbol_name = symbol_list->name;
toc = inline_bsearch_toc(symbol_name, tocs, dyst->ntoc);
if(toc != NULL){
symbol_index = toc->symbol_index;
symbol = symbols + symbol_index;
}
else{
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym);
if(symbol == NULL)
continue;
symbol_index = symbol - symbols;
}
if(force_flat_namespace == FALSE &&
(image->mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL){
if(GET_LIBRARY_ORDINAL(symbol->n_desc) == EXECUTABLE_ORDINAL)
primary_image = &object_images.images[0].image;
else if(GET_LIBRARY_ORDINAL(symbol->n_desc) ==
DYNAMIC_LOOKUP_ORDINAL &&
image->ndependent_images != DYNAMIC_LOOKUP_ORDINAL)
primary_image = symbol_list->image;
else if(GET_LIBRARY_ORDINAL(symbol->n_desc) ==
SELF_LIBRARY_ORDINAL)
primary_image = image;
else{
primary_image = image->dependent_images[
GET_LIBRARY_ORDINAL(symbol->n_desc) - 1];
}
if(primary_image != symbol_list->image){
match = FALSE;
for(i = 0;
i < symbol_list->image->numbrella_images;
i++){
if(primary_image ==
symbol_list->image->umbrella_images[i]){
match = TRUE;
break;
}
}
if(match != TRUE)
continue;
}
}
else{
if(symbol_list->flat_reference == FALSE)
continue;
}
if(symbol_list->symbol != NULL &&
(symbol_list->symbol->n_type & N_TYPE) == N_INDR){
lookup_symbol(symbol_name,
get_primary_image(symbol_list->image,
symbol_list->symbol),
get_hint(symbol_list->image, symbol_list->symbol),
get_weak(symbol_list->symbol),
&defined_symbol, &defined_module, &defined_image,
&defined_library_image, NULL);
toc_bsearch_symbols = symbols;
toc_bsearch_strings = strings;
nlist_bsearch_strings = strings;
value = defined_symbol->n_value;
if((defined_symbol->n_type & N_TYPE) != N_ABS)
value += defined_image->vmaddr_slide;
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit +
dyld_image_vmaddr_slide;
#endif
relocate_symbol_pointers(symbol_index, indirect_symtab,
image, value, FALSE);
}
else{
value = symbol_list->symbol->n_value;
if((symbol_list->symbol->n_type & N_TYPE) != N_ABS)
value += symbol_list->image->vmaddr_slide;
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit +
dyld_image_vmaddr_slide;
#endif
relocate_symbol_pointers(symbol_index, indirect_symtab,
image, value, FALSE);
}
}
}
void
change_symbol_pointers_in_flat_images(
char *symbol_name,
unsigned long value,
enum bool only_lazy_pointers)
{
unsigned long i;
struct object_images *p;
struct library_images *q;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
unsigned long *indirect_symtab;
unsigned long symbol_index;
struct dylib_table_of_contents *tocs, *toc;
char *strings;
enum link_state link_state;
p = &object_images;
do{
for(i = 0; i < p->nimages; i++){
link_state = GET_LINK_STATE(p->images[i].module);
if(link_state == UNUSED)
continue;
if(force_flat_namespace == FALSE &&
(p->images[i].image.mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL)
continue;
linkedit_segment = p->images[i].image.linkedit_segment;
st = p->images[i].image.st;
dyst = p->images[i].image.dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
continue;
symbols = (struct nlist *)
(p->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
nlist_bsearch_strings = (char *)
(p->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
indirect_symtab = (unsigned long *)
(p->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->indirectsymoff -
linkedit_segment->fileoff);
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iextdefsym, dyst->nextdefsym);
if(symbol == NULL){
if(p->images[i].image.mh->flags & MH_BINDATLOAD)
symbol = nlist_linear_search(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym,
nlist_bsearch_strings);
else
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym);
}
if(symbol == NULL)
continue;
symbol_index = symbol - symbols;
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit +
dyld_image_vmaddr_slide;
#endif
relocate_symbol_pointers(symbol_index, indirect_symtab,
&(p->images[i].image), value,
only_lazy_pointers);
}
p = p->next_images;
}while(p != NULL);
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(force_flat_namespace == FALSE &&
(q->images[i].image.mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL)
continue;
linkedit_segment = q->images[i].image.linkedit_segment;
st = q->images[i].image.st;
dyst = q->images[i].image.dyst;
tocs = (struct dylib_table_of_contents *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
symbols = (struct nlist *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
indirect_symtab = (unsigned long *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->indirectsymoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = symbols;
toc_bsearch_strings = strings;
nlist_bsearch_strings = strings;
toc = inline_bsearch_toc(symbol_name, tocs, dyst->ntoc);
if(toc != NULL){
symbol_index = toc->symbol_index;
}
else{
symbol = inline_bsearch_nlist(symbol_name,
symbols + dyst->iundefsym, dyst->nundefsym);
if(symbol == NULL)
continue;
symbol_index = symbol - symbols;
}
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit +
dyld_image_vmaddr_slide;
#endif
relocate_symbol_pointers(symbol_index, indirect_symtab,
&(q->images[i].image), value,
only_lazy_pointers);
}
q = q->next_images;
}while(q != NULL);
}
static
void
relocate_symbol_pointers(
unsigned long symbol_index,
unsigned long *indirect_symtab,
struct image *image,
unsigned long value,
enum bool only_lazy_pointers)
{
unsigned long i, j, k, section_type, size, vmaddr_slide, reserved1, addr;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
#ifdef __ppc__
if(only_lazy_pointers == TRUE)
value = image->dyld_stub_binding_helper;
#endif
lc = (struct load_command *)((char *)image->mh +
sizeof(struct mach_header));
vmaddr_slide = image->vmaddr_slide;
for(i = 0; i < image->mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
size = s->size;
reserved1 = s->reserved1;
addr = s->addr;
section_type = s->flags & SECTION_TYPE;
if((section_type == S_NON_LAZY_SYMBOL_POINTERS &&
only_lazy_pointers == FALSE) ||
section_type == S_LAZY_SYMBOL_POINTERS){
for(k = 0; k < size / sizeof(unsigned long); k++){
if(indirect_symtab[reserved1 + k] == symbol_index){
*((long *)(vmaddr_slide + addr +
(k * sizeof(long)))) = value;
}
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
void
relocate_symbol_pointers_for_defined_externs(
struct image *image)
{
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
unsigned long *indirect_symtab;
struct nlist *symbols;
unsigned long index;
unsigned long i, j, k, section_type;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
linkedit_segment = image->linkedit_segment;
st = image->st;
dyst = image->dyst;
symbols = (struct nlist *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
indirect_symtab = (unsigned long *)
(image->vmaddr_slide +
linkedit_segment->vmaddr +
dyst->indirectsymoff -
linkedit_segment->fileoff);
lc = (struct load_command *)((char *)image->mh +
sizeof(struct mach_header));
for(i = 0; i < image->mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
section_type = s->flags & SECTION_TYPE;
if(section_type == S_NON_LAZY_SYMBOL_POINTERS){
for(k = 0; k < s->size / sizeof(unsigned long); k++){
index = indirect_symtab[s->reserved1 + k];
if(index == INDIRECT_SYMBOL_ABS)
continue;
if(index == INDIRECT_SYMBOL_LOCAL ||
((symbols[index].n_type & N_TYPE) != N_UNDF &&
(symbols[index].n_type & N_TYPE) != N_ABS)){
*((long *)(image->vmaddr_slide + s->addr +
(k * sizeof(long)))) += image->vmaddr_slide;
}
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
unsigned long
bind_lazy_symbol_reference(
struct mach_header *mh,
unsigned long lazy_symbol_pointer_address)
{
struct object_images *p;
struct library_images *q;
struct image *image;
enum bool flat_reference;
unsigned long i, j, section_type, isym;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
struct nlist *symbols, *symbol;
unsigned long *indirect_symtab;
char *symbol_name;
struct nlist *defined_symbol;
module_state *defined_module;
struct image *defined_image;
struct library_image *defined_library_image;
enum link_state link_state;
unsigned long value;
struct library_image *library_image;
struct dylib_module *dylib_modules;
set_lock();
DYLD_TRACE_SYMBOLS_ADDRESSED_START(
DYLD_TRACE_bind_lazy_symbol_reference, lazy_symbol_pointer_address);
image = NULL;
p = &object_images;
do{
for(i = 0; image == NULL && i < p->nimages; i++){
if(p->images[i].image.mh == mh)
image = &(p->images[i].image);
}
p = p->next_images;
}while(image == NULL && p != NULL);
library_image = NULL;
if(image == NULL){
q = &library_images;
do{
for(i = 0; image == NULL && i < q->nimages; i++){
if(q->images[i].image.mh == mh){
image = &(q->images[i].image);
library_image = q->images + i;
}
}
q = q->next_images;
}while(image == NULL && q != NULL);
}
if(image == NULL){
error("bad mach header passed to stub_binding_helper");
link_edit_error(DYLD_OTHER_ERROR, DYLD_LAZY_BIND, NULL);
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_bind_lazy_symbol_reference);
halt();
exit(DYLD_EXIT_FAILURE_BASE + DYLD_OTHER_ERROR);
}
symbols = (struct nlist *)
(image->vmaddr_slide +
image->linkedit_segment->vmaddr +
image->st->symoff -
image->linkedit_segment->fileoff);
indirect_symtab = (unsigned long *)
(image->vmaddr_slide +
image->linkedit_segment->vmaddr +
image->dyst->indirectsymoff -
image->linkedit_segment->fileoff);
symbol = NULL;
isym = 0;
lc = (struct load_command *)((char *)image->mh +
sizeof(struct mach_header));
for(i = 0; symbol == NULL && i < image->mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0; symbol == NULL && j < sg->nsects; j++){
section_type = s->flags & SECTION_TYPE;
if(section_type == S_LAZY_SYMBOL_POINTERS){
if(lazy_symbol_pointer_address >=
s->addr + image->vmaddr_slide &&
lazy_symbol_pointer_address <
s->addr + image->vmaddr_slide + s->size){
isym = indirect_symtab[s->reserved1 +
(lazy_symbol_pointer_address - (s->addr +
image->vmaddr_slide)) /
sizeof(unsigned long)];
symbol = symbols + isym;
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(symbol == NULL){
error("bad address of lazy symbol pointer passed to "
"stub_binding_helper");
link_edit_error(DYLD_OTHER_ERROR, DYLD_LAZY_BIND, NULL);
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_bind_lazy_symbol_reference);
halt();
exit(DYLD_EXIT_FAILURE_BASE + DYLD_OTHER_ERROR);
}
if((symbol->n_type & N_PEXT) == N_PEXT &&
(symbol->n_type & N_EXT) != N_EXT){
if(library_image != NULL){
dylib_modules = (struct dylib_module *)
(image->vmaddr_slide +
image->linkedit_segment->vmaddr +
image->dyst->modtaboff -
image->linkedit_segment->fileoff);
for(j = 0; j < image->dyst->nmodtab; j++){
if(isym >= dylib_modules[j].ilocalsym &&
isym < dylib_modules[j].ilocalsym +
dylib_modules[j].nlocalsym)
break;
}
if(j < image->dyst->nmodtab){
link_state = GET_LINK_STATE(library_image->modules[j]);
if(link_state == PREBOUND_UNLINKED){
undo_prebinding_for_library_module(
library_image->modules + j,
image,
library_image);
link_state = UNLINKED;
SET_LINK_STATE(library_image->modules[j], link_state);
}
if(link_state == UNLINKED){
link_library_module(library_image, image,
library_image->modules + j,
executable_bind_at_load,
FALSE,
FALSE );
link_in_need_modules(FALSE, FALSE, NULL);
}
value = symbol->n_value;
if((symbol->n_type & N_TYPE) != N_ABS)
value += image->vmaddr_slide;
*((long *)lazy_symbol_pointer_address) = value;
DYLD_TRACE_SYMBOLS_END(
DYLD_TRACE_bind_lazy_symbol_reference);
release_lock();
return(value);
}
}
else {
value = symbol->n_value;
if((symbol->n_type & N_TYPE) != N_ABS)
value += image->vmaddr_slide;
*((long *)lazy_symbol_pointer_address) = value;
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_bind_lazy_symbol_reference);
release_lock();
return(value);
}
}
symbol_name = (char *)
(image->vmaddr_slide +
image->linkedit_segment->vmaddr +
image->st->stroff -
image->linkedit_segment->fileoff) +
symbol->n_un.n_strx;
lookup_symbol(symbol_name, get_primary_image(image, symbol),
get_hint(image, symbol), get_weak(symbol),
&defined_symbol, &defined_module, &defined_image,
&defined_library_image, NULL);
if(defined_symbol != NULL){
link_state = GET_LINK_STATE(*defined_module);
if(link_state == LINKED || link_state == FULLY_LINKED){
value = defined_symbol->n_value;
if((defined_symbol->n_type & N_TYPE) != N_ABS)
value += defined_image->vmaddr_slide;
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit +
dyld_image_vmaddr_slide;
#endif
*((long *)lazy_symbol_pointer_address) = value;
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_bind_lazy_symbol_reference);
release_lock();
return(value);
}
}
if(dyld_prebind_debug > 1)
print("dyld: %s: linking in non-prebound lazy symbol: %s\n",
executables_name, symbol_name);
if(force_flat_namespace == FALSE)
flat_reference = (image->mh->flags & MH_TWOLEVEL) != MH_TWOLEVEL;
else
flat_reference = TRUE;
add_to_undefined_list(symbol_name, symbol, image, FALSE,flat_reference);
link_in_need_modules(FALSE, FALSE, NULL);
lookup_symbol(symbol_name, get_primary_image(image, symbol),
get_hint(image, symbol), get_weak(symbol),
&defined_symbol, &defined_module, &defined_image,
&defined_library_image, NULL);
value = defined_symbol->n_value;
if((defined_symbol->n_type & N_TYPE) != N_ABS)
value += defined_image->vmaddr_slide;
#ifdef DYLD_PROFILING
if(strcmp(symbol_name, "__exit") == 0)
value = (unsigned long)profiling_exit + dyld_image_vmaddr_slide;
#endif
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_bind_lazy_symbol_reference);
release_lock();
return(value);
}
void
bind_symbol_by_name(
char *symbol_name,
unsigned long *address,
module_state **module,
struct nlist **symbol,
enum bool change_symbol_pointers)
{
struct nlist *defined_symbol;
module_state *defined_module;
struct image *defined_image;
struct library_image *defined_library_image;
enum link_state link_state;
unsigned long value;
set_lock();
DYLD_TRACE_SYMBOLS_ADDRESSED_START(DYLD_TRACE_bind_symbol_by_name,
address);
lookup_symbol(symbol_name, NULL, NULL, FALSE, &defined_symbol,
&defined_module, &defined_image, &defined_library_image,
NULL);
if(defined_symbol != NULL){
link_state = GET_LINK_STATE(*defined_module);
if(link_state == LINKED || link_state == FULLY_LINKED){
value = defined_symbol->n_value;
if((defined_symbol->n_type & N_TYPE) != N_ABS)
value += defined_image->vmaddr_slide;
if(change_symbol_pointers == TRUE)
change_symbol_pointers_in_flat_images(symbol_name,
value, FALSE);
if(address != NULL)
*address = value;
if(module != NULL)
*module = defined_module;
if(symbol != NULL)
*symbol = defined_symbol;
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_bind_symbol_by_name);
release_lock();
return;
}
}
if(dyld_prebind_debug > 1)
print("dyld: %s: linking in bind by name symbol: %s\n",
executables_name, symbol_name);
add_to_undefined_list(symbol_name, NULL, NULL, FALSE, TRUE);
link_in_need_modules(FALSE, FALSE, NULL);
lookup_symbol(symbol_name, NULL, NULL, FALSE, &defined_symbol,
&defined_module, &defined_image, &defined_library_image,
NULL);
value = defined_symbol->n_value;
if((defined_symbol->n_type & N_TYPE) != N_ABS)
value += defined_image->vmaddr_slide;
if(address != NULL)
*address = value;
if(module != NULL)
*module = defined_module;
if(symbol != NULL)
*symbol = defined_symbol;
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_bind_symbol_by_name);
release_lock();
}
enum bool
link_in_need_modules(
enum bool bind_now,
enum bool release_lock_flag,
struct object_image *reloc_just_this_object_image)
{
enum bool tried_to_use_prebinding_post_launch;
DYLD_TRACE_SYMBOLS_START(DYLD_TRACE_link_in_need_modules);
tried_to_use_prebinding_post_launch =
trying_to_use_prebinding_post_launch;
if(tried_to_use_prebinding_post_launch == TRUE){
find_twolevel_prebound_lib_subtrees();
undo_prebound_images(TRUE);
}
if(resolve_undefineds(bind_now, FALSE) == FALSE &&
return_on_error == TRUE){
unload_remove_on_error_libraries();
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_link_in_need_modules);
return(FALSE);
}
if(return_on_error == TRUE &&
check_and_report_undefineds(FALSE) == FALSE){
clear_state_changes_to_the_modules();
clear_being_linked_list(TRUE);
clear_undefined_list(TRUE);
unload_remove_on_error_libraries();
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_link_in_need_modules);
return(FALSE);
}
else if(reloc_just_this_object_image != NULL){
check_and_report_undefineds(TRUE);
}
if(reloc_just_this_object_image == NULL){
relocate_modules_being_linked(FALSE);
}
else{
resolve_non_lazy_symbol_pointers_in_image(
&reloc_just_this_object_image->image);
resolve_external_relocations_in_object_image(
reloc_just_this_object_image);
}
check_and_report_undefineds(reloc_just_this_object_image != NULL);
if(return_on_error == TRUE){
clear_remove_on_error_libraries();
return_on_error = FALSE;
}
if(tried_to_use_prebinding_post_launch == TRUE)
trying_to_use_prebinding_post_launch = FALSE;
call_registered_funcs_for_add_images();
call_registered_funcs_for_linked_modules();
call_image_init_routines(FALSE);
if(tried_to_use_prebinding_post_launch == TRUE){
call_module_initializers(FALSE, FALSE, TRUE);
clear_trying_to_use_prebinding_post_launch();
}
call_module_initializers(FALSE, bind_now, FALSE);
if(release_lock_flag){
release_lock();
}
DYLD_TRACE_SYMBOLS_END(DYLD_TRACE_link_in_need_modules);
return(TRUE);
}
enum bool
check_executable_for_overrides(
void)
{
unsigned long i;
char *symbol_name;
struct nlist *symbols;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct image *image;
linkedit_segment = object_images.images[0].image.linkedit_segment;
st = object_images.images[0].image.st;
dyst = object_images.images[0].image.dyst;
if(linkedit_segment == NULL || st == NULL || dyst == NULL)
return(TRUE);
symbols = (struct nlist *)
(linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
image = &object_images.images[0].image;
for(i = dyst->iextdefsym; i < dyst->iextdefsym + dyst->nextdefsym; i++){
symbol_name = (char *)
(image->linkedit_segment->vmaddr +
image->st->stroff -
image->linkedit_segment->fileoff) +
symbols[i].n_un.n_strx;
if(check_libraries_for_definition_and_refernce(symbol_name, NULL) ==
TRUE)
return(FALSE);
}
return(TRUE);
}
enum bool
check_libraries_for_overrides(
void)
{
unsigned long i, j;
struct library_images *q;
struct library_image *library_image;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct dylib_table_of_contents *tocs;
struct nlist *symbols;
char *strings, *symbol_name;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
library_image = &(q->images[i]);
linkedit_segment = library_image->image.linkedit_segment;
st = library_image->image.st;
dyst = library_image->image.dyst;
tocs = (struct dylib_table_of_contents *)
(library_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
symbols = (struct nlist *)
(library_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
strings = (char *)
(library_image->image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
for(j = 0; j < dyst->ntoc; j++){
symbol_name = strings +
symbols[tocs[j].symbol_index].n_un.n_strx;
if(check_libraries_for_definition_and_refernce(symbol_name,
library_image) == TRUE)
return(FALSE);
}
}
q = q->next_images;
}while(q != NULL);
return(TRUE);
}
static
enum bool
check_libraries_for_definition_and_refernce(
char *symbol_name,
struct library_image *library_image)
{
unsigned long i, j;
struct library_images *q;
struct segment_command *linkedit_segment;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct dylib_table_of_contents *tocs, *toc;
struct dylib_reference *dylib_references;
q = &library_images;
do{
for(i = 0; i < q->nimages; i++){
if(library_image == &(q->images[i]))
continue;
linkedit_segment = q->images[i].image.linkedit_segment;
st = q->images[i].image.st;
dyst = q->images[i].image.dyst;
tocs = (struct dylib_table_of_contents *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->tocoff -
linkedit_segment->fileoff);
toc_bsearch_symbols = (struct nlist *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->symoff -
linkedit_segment->fileoff);
toc_bsearch_strings = (char *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
st->stroff -
linkedit_segment->fileoff);
toc = inline_bsearch_toc(symbol_name, tocs, dyst->ntoc);
if(toc != NULL){
dylib_references = (struct dylib_reference *)
(q->images[i].image.vmaddr_slide +
linkedit_segment->vmaddr +
dyst->extrefsymoff -
linkedit_segment->fileoff);
for(j = 0; j < dyst->nextrefsyms; j++){
if(dylib_references[j].isym == toc->symbol_index &&
dylib_references[j].flags != REFERENCE_FLAG_DEFINED){
if(dyld_prebind_debug != 0 && prebinding == TRUE)
print("dyld: %s: trying to use prebound "
"libraries failed due to overridden "
"symbols\n", executables_name);
prebinding = FALSE;
return(TRUE);
}
}
}
}
q = q->next_images;
}while(q != NULL);
return(FALSE);
}
void
discard_symbol(
struct image *image,
struct nlist *symbol)
{
kern_return_t r;
if((r = vm_protect(mach_task_self(),
image->linkedit_segment->vmaddr +
image->vmaddr_slide,
(vm_size_t)image->linkedit_segment->vmsize, FALSE,
VM_PROT_WRITE | VM_PROT_READ)) != KERN_SUCCESS){
mach_error(r, "can't set vm_protection on segment: %.16s "
"for: %s", image->linkedit_segment->segname,
image->name);
link_edit_error(DYLD_MACH_RESOURCE, r, image->name);
}
symbol->n_desc |= N_DESC_DISCARDED;
if((r = vm_protect(mach_task_self(),
image->linkedit_segment->vmaddr +
image->vmaddr_slide,
(vm_size_t)image->linkedit_segment->vmsize, FALSE,
image->linkedit_segment->initprot)) != KERN_SUCCESS){
mach_error(r, "can't set vm_protection on segment: %.16s "
"for: %s", image->linkedit_segment->segname,
image->name);
link_edit_error(DYLD_MACH_RESOURCE, r, image->name);
}
}