#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <mach/mach.h>
#include <time.h>
#else
#include <mach/kern_return.h>
#endif
#include <stdarg.h>
#include <string.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "stuff/guess_short_name.h"
#include "dylibs.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "pass1.h"
#include "sections.h"
__private_extern__ enum bool has_dynamic_linker_command = FALSE;
#ifndef RLD
__private_extern__ struct merged_dylib *merged_dylibs = NULL;
__private_extern__ struct merged_dylinker *merged_dylinker = NULL;
__private_extern__ struct merged_sub_frameworks *merged_sub_framework = NULL;
__private_extern__ struct merged_segment *dylib_segments = NULL;
__private_extern__ struct merged_sub_umbrella *merged_sub_umbrellas = NULL;
__private_extern__ struct merged_sub_library *merged_sub_librarys = NULL;
__private_extern__ struct merged_sub_client *merged_sub_clients = NULL;
static struct merged_dylib *lookup_merged_dylib(
struct dylib_command *dl);
__private_extern__
void
create_dylib_id_command(
void)
{
char *name;
unsigned long cmdsize;
struct dylib_command *dl;
struct merged_dylib *mdl;
if(dylib_install_name != NULL)
name = dylib_install_name;
else
name = outputfile;
cmdsize = sizeof(struct dylib_command) +
rnd(strlen(name) + 1, sizeof(long));
dl = allocate(cmdsize);
memset(dl, '\0', cmdsize);
dl->cmd = LC_ID_DYLIB;
dl->cmdsize = cmdsize;
dl->dylib.name.offset = sizeof(struct dylib_command);
dl->dylib.timestamp = time(0);
dl->dylib.current_version = dylib_current_version;
dl->dylib.compatibility_version = dylib_compatibility_version;
strcpy((char *)dl + sizeof(struct dylib_command), name);
mdl = allocate(sizeof(struct merged_dylib));
memset(mdl, '\0', sizeof(struct merged_dylib));
mdl->dylib_name = name;
mdl->dl = dl;
mdl->output_id = TRUE;
mdl->next = merged_dylibs;
merged_dylibs = mdl;
}
__private_extern__
void
merge_dylibs(
enum bool force_weak)
{
unsigned long i;
struct mach_header *mh;
struct load_command *lc;
struct dylib_command *dl;
struct dylinker_command *dyld;
char *dyld_name;
struct merged_dylib *mdl;
struct dynamic_library *p;
mh = (struct mach_header *)cur_obj->obj_addr;
lc = (struct load_command *)((char *)cur_obj->obj_addr +
sizeof(struct mach_header));
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_ID_DYLIB ||
lc->cmd == LC_LOAD_DYLIB ||
lc->cmd == LC_LOAD_WEAK_DYLIB ||
lc->cmd == LC_REEXPORT_DYLIB){
if((lc->cmd != LC_LOAD_DYLIB &&
lc->cmd != LC_LOAD_WEAK_DYLIB &&
lc->cmd != LC_REEXPORT_DYLIB) ||
(mh->filetype != MH_DYLIB &&
mh->filetype != MH_DYLIB_STUB) ){
dl = (struct dylib_command *)lc;
mdl = lookup_merged_dylib(dl);
if(filetype == MH_DYLIB && dylib_install_name != NULL &&
strcmp(mdl->dylib_name, dylib_install_name) == 0)
error_with_cur_obj("can't be linked because it has the "
"same install_name (%s) as the output",
dylib_install_name);
p = add_dynamic_lib(DYLIB, dl, cur_obj);
p->force_weak_dylib = force_weak;
mdl->dynamic_library = p;
}
}
else if(lc->cmd == LC_LOAD_DYLINKER || lc->cmd == LC_ID_DYLINKER){
dyld = (struct dylinker_command *)lc;
dyld_name = (char *)dyld + dyld->name.offset;
if(merged_dylinker == NULL){
merged_dylinker = allocate(sizeof(struct merged_dylinker));
memset(merged_dylinker, '\0',
sizeof(struct merged_dylinker));
merged_dylinker->dylinker_name = dyld_name;
merged_dylinker->definition_object = cur_obj;
merged_dylinker->dyld = dyld;
has_dynamic_linker_command = TRUE;
if(save_reloc == FALSE)
output_for_dyld = TRUE;
}
else if(strcmp(dyld_name, merged_dylinker->dylinker_name) != 0){
error("multiple dynamic linkers loaded (only one allowed)");
print_obj_name(merged_dylinker->definition_object);
print("loads dynamic linker %s\n",
merged_dylinker->dylinker_name);
print_obj_name(cur_obj);
print("loads dynamic linker %s\n", dyld_name);
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
struct merged_dylib *
lookup_merged_dylib(
struct dylib_command *dl)
{
char *dylib_name;
struct merged_dylib **p, *mdl;
dylib_name = (char *)dl + dl->dylib.name.offset;
p = &merged_dylibs;
while(*p){
mdl = *p;
if(strcmp(mdl->dylib_name, dylib_name) == 0){
if(mdl->dl->cmd == LC_ID_DYLIB){
if(dl->cmd == LC_ID_DYLIB){
if(dl->dylib.compatibility_version >
mdl->dl->dylib.compatibility_version){
if(strcmp(mdl->definition_object->file_name,
cur_obj->file_name) != 0)
warning("multiple references to dynamic shared "
"library: %s (from %s and %s, using %s "
"which has higher compatibility_version)",
dylib_name,
mdl->definition_object->file_name,
cur_obj->file_name, cur_obj->file_name);
mdl->dylib_name = dylib_name;
mdl->dl = dl;
mdl->definition_object = cur_obj;
}
}
}
else{
if(dl->cmd == LC_ID_DYLIB){
mdl->dylib_name = dylib_name;
mdl->dl = dl;
mdl->definition_object = cur_obj;
}
}
return(mdl);
}
p = &(mdl->next);
}
*p = allocate(sizeof(struct merged_dylib));
memset(*p, '\0', sizeof(struct merged_dylib));
mdl = *p;
mdl->dylib_name = dylib_name;
mdl->dl = dl;
mdl->definition_object = cur_obj;
mdl->output_id = FALSE;
return(mdl);
}
__private_extern__
void
create_dylinker_id_command(
void)
{
char *name;
unsigned long cmdsize;
struct dylinker_command *dyld;
struct merged_dylinker *mdyld;
if(dylinker_install_name != NULL)
name = dylinker_install_name;
else
name = outputfile;
cmdsize = sizeof(struct dylinker_command) +
rnd(strlen(name) + 1, sizeof(long));
dyld = allocate(cmdsize);
memset(dyld, '\0', cmdsize);
dyld->cmd = LC_ID_DYLINKER;
dyld->cmdsize = cmdsize;
dyld->name.offset = sizeof(struct dylinker_command);
strcpy((char *)dyld + sizeof(struct dylinker_command), name);
mdyld = allocate(sizeof(struct merged_dylinker));
memset(mdyld, '\0', sizeof(struct merged_dylinker));
mdyld->dylinker_name = name;
mdyld->dyld = dyld;
merged_dylinker = mdyld;
}
__private_extern__
void
create_sub_framework_command(
void)
{
char *name;
unsigned long cmdsize;
struct sub_framework_command *sub;
struct merged_sub_frameworks *msub;
name = umbrella_framework_name;
cmdsize = sizeof(struct sub_framework_command) +
rnd(strlen(name) + 1, sizeof(long));
sub = allocate(cmdsize);
memset(sub, '\0', cmdsize);
sub->cmd = LC_SUB_FRAMEWORK;
sub->cmdsize = cmdsize;
sub->umbrella.offset = sizeof(struct sub_framework_command);
strcpy((char *)sub + sizeof(struct sub_framework_command), name);
msub = allocate(sizeof(struct merged_sub_frameworks));
memset(msub, '\0', sizeof(struct merged_sub_frameworks));
msub->unbrell_name = name;
msub->sub = sub;
merged_sub_framework = msub;
}
__private_extern__
unsigned long
create_sub_umbrella_commands(
void)
{
unsigned long i;
char *name, *umbrella_framework_name, *has_suffix;
unsigned long cmdsize, sizeofcmds;
struct sub_umbrella_command *sub;
enum bool found, is_framework;
struct merged_dylib **p, *mdl;
sizeofcmds = 0;
merged_sub_umbrellas = allocate(sizeof(struct merged_sub_umbrella) *
nsub_umbrellas);
for(i = 0; i < nsub_umbrellas ; i++){
name = sub_umbrellas[i];
found = FALSE;
p = &merged_dylibs;
while(*p){
mdl = *p;
umbrella_framework_name = guess_short_name(mdl->dylib_name,
&is_framework, &has_suffix);
if(umbrella_framework_name != NULL &&
is_framework == TRUE &&
strcmp(umbrella_framework_name, name) == 0){
found = TRUE;
break;
}
p = &(mdl->next);
}
if(found == FALSE)
error("-sub_umbrella %s specified but no framework by that "
"name is linked in", name);
cmdsize = sizeof(struct sub_umbrella_command) +
rnd(strlen(name) + 1, sizeof(long));
sub = allocate(cmdsize);
memset(sub, '\0', cmdsize);
sub->cmd = LC_SUB_UMBRELLA;
sub->cmdsize = cmdsize;
sub->sub_umbrella.offset = sizeof(struct sub_umbrella_command);
strcpy((char *)sub + sizeof(struct sub_umbrella_command), name);
sizeofcmds += cmdsize;
merged_sub_umbrellas[i].sub = sub;
}
return(sizeofcmds);
}
__private_extern__
unsigned long
create_sub_library_commands(
void)
{
unsigned long i;
char *name, *library_name, *has_suffix;
unsigned long cmdsize, sizeofcmds;
struct sub_library_command *sub;
enum bool found, is_framework;
struct merged_dylib **p, *mdl;
sizeofcmds = 0;
merged_sub_librarys = allocate(sizeof(struct merged_sub_library) *
nsub_librarys);
for(i = 0; i < nsub_librarys ; i++){
name = sub_librarys[i];
found = FALSE;
p = &merged_dylibs;
while(*p){
mdl = *p;
library_name = guess_short_name(mdl->dylib_name,
&is_framework, &has_suffix);
if(library_name != NULL &&
is_framework == FALSE &&
strcmp(library_name, name) == 0){
found = TRUE;
break;
}
p = &(mdl->next);
}
if(found == FALSE)
error("-sub_library %s specified but no library by that "
"name is linked in", name);
cmdsize = sizeof(struct sub_library_command) +
rnd(strlen(name) + 1, sizeof(long));
sub = allocate(cmdsize);
memset(sub, '\0', cmdsize);
sub->cmd = LC_SUB_LIBRARY;
sub->cmdsize = cmdsize;
sub->sub_library.offset = sizeof(struct sub_library_command);
strcpy((char *)sub + sizeof(struct sub_library_command), name);
sizeofcmds += cmdsize;
merged_sub_librarys[i].sub = sub;
}
return(sizeofcmds);
}
__private_extern__
unsigned long
create_sub_client_commands(
void)
{
unsigned long i;
char *name;
unsigned long cmdsize, sizeofcmds;
struct sub_client_command *sub;
sizeofcmds = 0;
merged_sub_clients = allocate(sizeof(struct merged_sub_client) *
nallowable_clients);
for(i = 0; i < nallowable_clients ; i++){
name = allowable_clients[i];
cmdsize = sizeof(struct sub_client_command) +
rnd(strlen(name) + 1, sizeof(long));
sub = allocate(cmdsize);
memset(sub, '\0', cmdsize);
sub->cmd = LC_SUB_CLIENT;
sub->cmdsize = cmdsize;
sub->client.offset = sizeof(struct sub_client_command);
strcpy((char *)sub + sizeof(struct sub_client_command), name);
sizeofcmds += cmdsize;
merged_sub_clients[i].sub = sub;
}
return(sizeofcmds);
}
__private_extern__
void
add_dylib_segment(
struct segment_command *sg,
char *dylib_name,
enum bool split_dylib)
{
struct merged_segment **p, *msg;
p = &dylib_segments;
while(*p){
msg = *p;
p = &(msg->next);
}
*p = allocate(sizeof(struct merged_segment));
msg = *p;
memset(msg, '\0', sizeof(struct merged_segment));
msg->sg = *sg;
msg->filename = dylib_name;
msg->split_dylib = split_dylib;
}
#endif