#ifdef SHLIB
#include "shlib.h"
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "stuff/openstep_mach.h"
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include <mach-o/ldsyms.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <libc.h>
#include <stdio.h>
#include <mach/mach.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#else
#include <mach/kern_return.h>
#endif
#include <ar.h>
#ifndef AR_EFMT1
#define AR_EFMT1 "#1/"
#endif
#include <mach-o/ranlib.h>
#include "stuff/arch.h"
#include "stuff/best_arch.h"
#include "stuff/guess_short_name.h"
#include "stuff/macosx_deployment_target.h"
#include "ld.h"
#include "pass1.h"
#include "live_refs.h"
#include "objects.h"
#include "fvmlibs.h"
#include "dylibs.h"
#include "sections.h"
#include "symbols.h"
#include "sets.h"
#include "layout.h"
#ifndef KLD
#include "debugcompunit.h"
#include "debugline.h"
#endif
#ifndef RLD
__private_extern__ enum bool search_paths_first = FALSE;
__private_extern__ char **search_dirs = NULL;
__private_extern__ unsigned long nsearch_dirs = 0;
__private_extern__ char **ld_library_paths = NULL;
__private_extern__ unsigned long nld_library_paths = 0;
__private_extern__ char *standard_dirs[] = {
"/lib/",
"/usr/lib/",
"/usr/local/lib/",
NULL
};
__private_extern__ char **framework_dirs = NULL;
__private_extern__ unsigned long nframework_dirs = 0;
__private_extern__ char *standard_framework_dirs[] = {
#ifdef __OPENSTEP__
"/LocalLibrary/Frameworks/",
"/NextLibrary/Frameworks/",
#else
#ifdef __GONZO_BUNSEN_BEAKER__
"/Local/Library/Frameworks/",
#else
"/Library/Frameworks/",
#endif
"/Network/Library/Frameworks/",
"/System/Library/Frameworks/",
#endif
NULL
};
__private_extern__ struct merged_segment *base_obj_segments = NULL;
#endif
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
static struct stat stat_buf = { 0 };
__private_extern__ char *bsearch_strings = NULL;
#ifndef RLD
__private_extern__ struct nlist *bsearch_symbols = NULL;
__private_extern__ struct dynamic_library *dynamic_libs = NULL;
__private_extern__ unsigned int indirect_library_ratio = 1;
static enum bool indirect_dylib = FALSE;
static void search_for_file(
char *base_name,
char **file_name,
int *fd);
static void search_for_framework(
char *name,
char **file_name,
int *fd);
static void search_paths_for_lname(
const char *lname_argument,
char **file_name,
int *fd);
static void search_path_for_lname(
const char *dir,
const char *lname_argument,
char **file_name,
int *fd);
#endif
static void pass1_fat(
char *file_name,
char *file_addr,
unsigned long file_size,
enum bool base_name,
enum bool dylib_only,
enum bool bundle_loader,
enum bool force_weak);
static void pass1_archive(
char *file_name,
char *file_addr,
unsigned long file_size,
enum bool base_name,
enum bool from_fat_file,
enum bool bundle_loader,
enum bool force_weak);
static enum bool check_archive_arch(
char *file_name,
char *file_addr,
unsigned long file_size);
static enum bool check_extend_format_1(
char *name,
struct ar_hdr *ar_hdr,
unsigned long size_left,
unsigned long *member_name_size);
static void pass1_object(
char *file_name,
char *file_addr,
unsigned long file_size,
enum bool base_name,
enum bool from_fat_file,
enum bool dylib_only,
enum bool bundle_loader,
enum bool force_weak);
#ifndef RLD
static void load_init_dylib_module(
struct dynamic_library *q);
static enum bool setup_sub_images(
struct dynamic_library *p);
static void check_dylibs_for_definition(
struct merged_symbol *merged_symbol,
enum bool prebind_check,
enum bool twolevel_namespace_check);
static enum bool check_dylibs_for_reference(
struct merged_symbol *merged_symbol);
static enum bool open_dylib(
struct dynamic_library *p);
static enum bool set_sub_frameworks_ordinals(
struct dynamic_library *umbrella);
static enum bool set_sub_umbrella_sub_library_ordinal(
struct dynamic_library *sub);
static void set_isub_image(
struct dynamic_library *p,
struct dynamic_library *sub);
static int nlist_bsearch(
const char *symbol_name,
const struct nlist *symbol);
#endif
static int ranlib_bsearch(
const char *symbol_name,
const struct ranlib *ran);
#endif
static void check_cur_obj(
enum bool dylib_only,
enum bool bundle_loader);
#ifndef KLD
static void read_dwarf_info(void);
#endif
static void check_size_offset(
unsigned long size,
unsigned long offset,
unsigned long align,
char *size_str,
char *offset_str,
unsigned long cmd);
static void check_size_offset_sect(
unsigned long size,
unsigned long offset,
unsigned long align,
char *size_str,
char *offset_str,
unsigned long cmd,
unsigned long sect,
char *segname,
char *sectname);
#ifndef RLD
static void collect_base_obj_segments(
void);
static void add_base_obj_segment(
struct segment_command *sg,
char *filename);
static char *mkstr(
const char *args,
...);
#endif
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
__private_extern__
void
pass1(
char *name,
enum bool lname,
enum bool base_name,
enum bool framework_name,
enum bool bundle_loader,
enum bool force_weak)
{
int fd;
char *file_name;
#ifndef RLD
char *p, *type;
#endif
kern_return_t r;
unsigned long file_size;
char *file_addr;
struct fat_header *fat_header;
#ifdef __MWERKS__
enum bool dummy;
dummy = lname;
dummy = base_name;
dummy = framework_name;
#endif
#ifdef DEBUG
file_name = NULL;
#endif
fd = -1;
#ifndef RLD
if(lname){
if(name[0] != '-' || name[1] != 'l')
fatal("Internal error: pass1() called with name of: %s and "
"lname == TRUE", name);
p = &name[2];
p = strrchr(p, '.');
if(p != NULL && strcmp(p, ".o") == 0){
p = &name[2];
search_for_file(p, &file_name, &fd);
if(fd == -1)
fatal("can't locate file for: %s", name);
}
else{
p = NULL;
if(dynamic == TRUE){
if(search_paths_first == TRUE){
search_paths_for_lname(&name[2], &file_name, &fd);
}
else{
p = mkstr("lib", &name[2], ".dylib", NULL);
search_for_file(p, &file_name, &fd);
if(fd == -1){
p = mkstr("lib", &name[2], ".a", NULL);
search_for_file(p, &file_name, &fd);
}
}
}
else{
p = mkstr("lib", &name[2], ".a", NULL);
search_for_file(p, &file_name, &fd);
}
if(fd == -1)
fatal("can't locate file for: %s", name);
if(p != NULL)
free(p);
}
}
else if(framework_name){
type = strrchr(name, ',');
if(type != NULL && type[1] != '\0'){
*type = '\0';
type++;
p = mkstr(name, ".framework/", name, type, NULL);
search_for_framework(p, &file_name, &fd);
if(fd == -1)
warning("can't locate framework for: -framework %s,%s "
"using suffix %s", name, type, type);
}
else
type = NULL;
if(fd == -1){
p = mkstr(name, ".framework/", name, NULL);
search_for_framework(p, &file_name, &fd);
}
if(fd == -1){
if(type != NULL)
fatal("can't locate framework for: -framework %s,%s",
name, type);
else
fatal("can't locate framework for: -framework %s", name);
}
}
else
#endif
{
if((fd = open(name, O_RDONLY, 0)) == -1){
system_error("can't open: %s", name);
return;
}
file_name = name;
}
if(fstat(fd, &stat_buf) == -1){
system_fatal("can't stat file: %s", file_name);
close(fd);
return;
}
file_size = stat_buf.st_size;
if(file_size == 0){
error("file: %s is empty (not an object or archive)", file_name);
close(fd);
return;
}
if((r = map_fd((int)fd, (vm_offset_t)0, (vm_offset_t *)&file_addr,
(boolean_t)TRUE, (vm_size_t)file_size)) != KERN_SUCCESS){
close(fd);
mach_fatal(r, "can't map file: %s", file_name);
}
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() map_fd: addr = 0x%0x size = 0x%x\n",
(unsigned int)file_addr, (unsigned int)file_size);
#endif
close(fd);
if(sizeof(struct fat_header) > file_size){
error("truncated or malformed file: %s (file size too small to be "
"any kind of object or library)", file_name);
return;
}
fat_header = (struct fat_header *)file_addr;
#ifdef __BIG_ENDIAN__
if(fat_header->magic == FAT_MAGIC)
#endif
#ifdef __LITTLE_ENDIAN__
if(fat_header->magic == SWAP_LONG(FAT_MAGIC))
#endif
{
#ifdef RLD
new_archive_or_fat(file_name, file_addr, file_size);
#endif
pass1_fat(file_name, file_addr, file_size, base_name, FALSE,
bundle_loader, force_weak);
}
else if(file_size >= SARMAG && strncmp(file_addr, ARMAG, SARMAG) == 0){
pass1_archive(file_name, file_addr, file_size, base_name, FALSE,
bundle_loader, force_weak);
}
else{
pass1_object(file_name, file_addr, file_size, base_name, FALSE,
FALSE, bundle_loader, force_weak);
}
#ifdef VM_SYNC_DEACTIVATE
vm_msync(mach_task_self(), (vm_address_t)file_addr,
(vm_size_t)file_size, VM_SYNC_DEACTIVATE);
#endif
}
#ifndef RLD
static
void
search_for_file(
char *base_name,
char **file_name,
int *fd)
{
unsigned long i;
*fd = -1;
for(i = 0; i < nsearch_dirs ; i++){
*file_name = mkstr(search_dirs[i], "/", base_name, NULL);
if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
break;
free(*file_name);
}
if(*fd == -1){
for(i = 0; i < nld_library_paths ; i++){
*file_name = mkstr(ld_library_paths[i], "/", base_name, NULL);
if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
break;
free(*file_name);
}
}
if(*fd == -1){
for(i = 0; standard_dirs[i] != NULL ; i++){
*file_name = mkstr(standard_dirs[i], base_name, NULL);
if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
break;
free(*file_name);
}
}
}
static
void
search_for_framework(
char *name,
char **file_name,
int *fd)
{
unsigned long i;
*fd = -1;
for(i = 0; i < nframework_dirs ; i++){
*file_name = mkstr(framework_dirs[i], "/", name, NULL);
if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
break;
free(*file_name);
}
if(*fd == -1){
for(i = 0; standard_framework_dirs[i] != NULL ; i++){
*file_name = mkstr(standard_framework_dirs[i], name, NULL);
if((*fd = open(*file_name, O_RDONLY, 0)) != -1)
break;
free(*file_name);
}
}
}
static
void
search_paths_for_lname(
const char *lname_argument,
char **file_name,
int *fd)
{
unsigned long i;
*fd = -1;
for(i = 0; i < nsearch_dirs ; i++){
search_path_for_lname(search_dirs[i], lname_argument, file_name,fd);
if(*fd != -1)
return;
}
for(i = 0; i < nld_library_paths ; i++){
search_path_for_lname(ld_library_paths[i], lname_argument,
file_name, fd);
if(*fd != -1)
return;
}
for(i = 0; standard_dirs[i] != NULL ; i++){
search_path_for_lname(standard_dirs[i],lname_argument,file_name,fd);
if(*fd != -1)
return;
}
}
static
void
search_path_for_lname(
const char *dir,
const char *lname_argument,
char **file_name,
int *fd)
{
*file_name = mkstr(dir, "/", "lib", lname_argument, ".dylib", NULL);
if((*fd = open(*file_name, O_RDONLY)) != -1)
return;
free(*file_name);
*file_name = mkstr(dir, "/", "lib", lname_argument, ".a", NULL);
if((*fd = open(*file_name, O_RDONLY)) != -1)
return;
free(*file_name);
}
#endif
static
void
pass1_fat(
char *file_name,
char *file_addr,
unsigned long file_size,
enum bool base_name,
enum bool dylib_only,
enum bool bundle_loader,
enum bool force_weak)
{
struct fat_header *fat_header;
#ifdef __LITTLE_ENDIAN__
struct fat_header struct_fat_header;
#endif
struct fat_arch *fat_archs, *best_fat_arch;
unsigned long previous_errors;
char *arch_addr;
unsigned long arch_size;
#if !(defined(KLD) && defined(__STATIC__))
struct arch_flag host_arch_flag;
#endif
const char *prev_arch;
fat_header = (struct fat_header *)file_addr;
#ifdef __LITTLE_ENDIAN__
struct_fat_header = *fat_header;
swap_fat_header(&struct_fat_header, host_byte_sex);
fat_header = &struct_fat_header;
#endif
if(sizeof(struct fat_header) + fat_header->nfat_arch *
sizeof(struct fat_arch) > file_size){
error("fat file: %s truncated or malformed (fat_arch structs "
"would extend past the end of the file)", file_name);
return;
}
#ifdef __BIG_ENDIAN__
fat_archs = (struct fat_arch *)(file_addr + sizeof(struct fat_header));
#endif
#ifdef __LITTLE_ENDIAN__
fat_archs = allocate(fat_header->nfat_arch * sizeof(struct fat_arch));
memcpy(fat_archs, file_addr + sizeof(struct fat_header),
fat_header->nfat_arch * sizeof(struct fat_arch));
swap_fat_arch(fat_archs, fat_header->nfat_arch, host_byte_sex);
#endif
previous_errors = errors;
errors = 0;
check_fat(file_name, file_size, fat_header, fat_archs, NULL, 0);
if(errors)
goto pass1_fat_return;
if(arch_flag.cputype != 0){
best_fat_arch = cpusubtype_findbestarch(
arch_flag.cputype, arch_flag.cpusubtype,
fat_archs, fat_header->nfat_arch);
if(best_fat_arch == NULL){
if(no_arch_warnings == TRUE)
goto pass1_fat_return;
if(arch_flag.name != NULL){
if(arch_errors_fatal == TRUE){
error("fat file: %s does not contain an architecture "
"that matches the specified -arch flag: %s ",
file_name, arch_flag.name);
}
else
warning("fat file: %s does not contain an architecture "
"that matches the specified -arch flag: %s "
"(file ignored)", file_name, arch_flag.name);
}
else{
prev_arch = get_arch_name_from_types(arch_flag.cputype,
arch_flag.cpusubtype);
if(arch_errors_fatal == TRUE){
error("fat file: %s does not contain an architecture "
"that matches the objects files (architecture %s) "
"previously loaded", file_name, prev_arch);
}
else
warning("fat file: %s does not contain an architecture "
"that matches the objects files (architecture %s) "
"previously loaded (file ignored)", file_name,
prev_arch);
}
goto pass1_fat_return;
}
arch_addr = file_addr + best_fat_arch->offset;
arch_size = best_fat_arch->size;
if(arch_size >= SARMAG &&
strncmp(arch_addr, ARMAG, SARMAG) == 0){
if(dylib_only == TRUE){
if(arch_flag.name != NULL){
error("fat file: %s (for architecture %s) is not a "
"dynamic shared library", file_name,
arch_flag.name);
}
else{
prev_arch = get_arch_name_from_types(arch_flag.cputype,
arch_flag.cpusubtype);
error("fat file: %s (for architecture %s) is not a "
"dynamic shared library", file_name, prev_arch);
}
goto pass1_fat_return;
}
pass1_archive(file_name, arch_addr, arch_size,
base_name, TRUE, bundle_loader, force_weak);
}
else{
pass1_object(file_name, arch_addr, arch_size, base_name, TRUE,
dylib_only, bundle_loader, force_weak);
}
goto pass1_fat_return;
}
#if !(defined(KLD) && defined(__STATIC__))
if(fat_header->nfat_arch == 1){
arch_addr = file_addr + fat_archs[0].offset;
arch_size = fat_archs[0].size;
if(arch_size >= SARMAG &&
strncmp(arch_addr, ARMAG, SARMAG) == 0){
if(dylib_only == TRUE){
error("fat file: %s (for architecture %s) is not a dynamic "
"shared library", file_name, get_arch_name_from_types(
fat_archs[0].cputype, fat_archs[0].cpusubtype));
goto pass1_fat_return;
}
pass1_archive(file_name, arch_addr, arch_size, base_name, TRUE,
bundle_loader, force_weak);
}
else{
pass1_object(file_name, arch_addr, arch_size, base_name, TRUE,
dylib_only, bundle_loader, force_weak);
}
goto pass1_fat_return;
}
if(get_arch_from_host(NULL, &host_arch_flag) == 0)
fatal("can't determine the host architecture (specify an "
"-arch flag or fix get_arch_from_host() )");
best_fat_arch = cpusubtype_findbestarch(
host_arch_flag.cputype, host_arch_flag.cpusubtype,
fat_archs, fat_header->nfat_arch);
if(best_fat_arch != NULL){
arch_addr = file_addr + best_fat_arch->offset;
arch_size = best_fat_arch->size;
if(arch_size >= SARMAG &&
strncmp(arch_addr, ARMAG, SARMAG) == 0){
if(dylib_only == TRUE){
error("fat file: %s (for architecture %s) is not a dynamic "
"shared library", file_name, get_arch_name_from_types(
best_fat_arch->cputype, best_fat_arch->cpusubtype));
goto pass1_fat_return;
}
pass1_archive(file_name, arch_addr, arch_size,
base_name, TRUE, bundle_loader, force_weak);
}
else{
pass1_object(file_name, arch_addr, arch_size, base_name, TRUE,
dylib_only, bundle_loader, force_weak);
}
goto pass1_fat_return;
}
fatal("-arch flag must be specified (fat file: %s does not contain the "
"host architecture or just one architecture)", file_name);
#endif
pass1_fat_return:
errors += previous_errors;
#ifdef __LITTLE_ENDIAN__
free(fat_archs);
#endif
return;
}
__private_extern__
void
check_fat(
char *file_name,
unsigned long file_size,
struct fat_header *fat_header,
struct fat_arch *fat_archs,
char *ar_name,
unsigned long ar_name_size)
{
unsigned long i, j;
if(fat_header->nfat_arch == 0){
if(ar_name != NULL)
error("fat file: %s(%.*s) malformed (contains zero "
"architecture types)", file_name, (int)ar_name_size,
ar_name);
else
error("fat file: %s malformed (contains zero architecture "
"types)", file_name);
return;
}
for(i = 0; i < fat_header->nfat_arch; i++){
if(fat_archs[i].offset + fat_archs[i].size > file_size){
if(ar_name != NULL)
error("fat file: %s(%.*s) truncated or malformed (offset "
"plus size of cputype (%d) cpusubtype (%d) extends "
"past the end of the file)", file_name,
(int)ar_name_size, ar_name, fat_archs[i].cputype,
fat_archs[i].cpusubtype);
else
error("fat file: %s truncated or malformed (offset plus "
"size of cputype (%d) cpusubtype (%d) extends past "
"the end of the file)", file_name,
fat_archs[i].cputype, fat_archs[i].cpusubtype);
return;
}
if(fat_archs[i].cputype == 0){
if(ar_name != NULL)
error("fat file: %s(%.*s) fat_archs %lu cputype is zero (a "
"reserved value)", file_name, (int)ar_name_size,
ar_name, i);
else
error("fat file: %s fat_archs %lu cputype is zero (a "
"reserved value)", file_name, i);
return;
}
if(fat_archs[i].align > MAXSECTALIGN){
if(ar_name != NULL)
error("fat file: %s(%.*s) align (2^%u) too large for "
"cputype (%d) cpusubtype (%d) (maximum 2^%d)",
file_name, (int)ar_name_size, ar_name,
fat_archs[i].align, fat_archs[i].cputype,
fat_archs[i].cpusubtype, MAXSECTALIGN);
else
error("fat file: %s align (2^%u) too large for cputype "
"(%d) cpusubtype (%d) (maximum 2^%d)", file_name,
fat_archs[i].align, fat_archs[i].cputype,
fat_archs[i].cpusubtype, MAXSECTALIGN);
return;
}
if(fat_archs[i].offset %
(1 << fat_archs[i].align) != 0){
if(ar_name != NULL)
error("fat file: %s(%.*s) offset: %u for cputype (%d) "
"cpusubtype (%d)) not aligned on it's alignment "
"(2^%u)", file_name, (int)ar_name_size, ar_name,
fat_archs[i].offset, fat_archs[i].cputype,
fat_archs[i].cpusubtype, fat_archs[i].align);
else
error("fat file: %s offset: %u for cputype (%d) "
"cpusubtype (%d)) not aligned on it's alignment "
"(2^%u)", file_name, fat_archs[i].offset,
fat_archs[i].cputype, fat_archs[i].cpusubtype,
fat_archs[i].align);
return;
}
}
for(i = 0; i < fat_header->nfat_arch; i++){
for(j = i + 1; j < fat_header->nfat_arch; j++){
if(fat_archs[i].cputype == fat_archs[j].cputype &&
fat_archs[i].cpusubtype == fat_archs[j].cpusubtype){
if(ar_name != NULL)
error("fat file: %s(%.*s) contains two of the same "
"architecture (cputype (%d) cpusubtype (%d))",
file_name, (int)ar_name_size, ar_name,
fat_archs[i].cputype, fat_archs[i].cpusubtype);
else
error("fat file: %s contains two of the same "
"architecture (cputype (%d) cpusubtype (%d))",
file_name, fat_archs[i].cputype,
fat_archs[i].cpusubtype);
return;
}
}
}
return;
}
static
void
pass1_archive(
char *file_name,
char *file_addr,
unsigned long file_size,
enum bool base_name,
enum bool from_fat_file,
enum bool bundle_loader,
enum bool force_weak)
{
unsigned long i, j, offset;
#ifndef RLD
unsigned long *loaded_offsets, nloaded_offsets;
enum bool loaded_offset;
struct ar_hdr *ar_hdr;
unsigned long length;
struct dynamic_library *p;
#endif
struct ar_hdr *symdef_ar_hdr;
char *symdef_ar_name, *ar_name;
unsigned long symdef_length, nranlibs, string_size, ar_name_size;
struct ranlib *ranlibs, *ranlib;
struct undefined_list *undefined;
struct merged_symbol *merged_symbol;
enum bool member_loaded;
enum byte_sex toc_byte_sex;
enum bool ld_trace_archive_printed;
#ifndef RLD
unsigned long ar_size;
struct fat_header *fat_header;
#ifdef __LITTLE_ENDIAN__
struct fat_header struct_fat_header;
#endif
struct fat_arch *fat_archs, *best_fat_arch;
char *arch_addr;
unsigned long arch_size;
struct arch_flag host_arch_flag;
const char *prev_arch;
arch_addr = NULL;
arch_size = 0;
#endif
#ifdef __MWERKS__
{
enum bool dummy;
dummy = base_name;
dummy = from_fat_file;
}
#endif
ld_trace_archive_printed = FALSE;
if(check_archive_arch(file_name, file_addr, file_size) == FALSE)
return;
offset = SARMAG;
#ifndef RLD
if(base_name)
fatal("base file of incremental link (argument of -A): %s should't "
"be an archive", file_name);
if(bundle_loader)
fatal("-bundle_loader argument: %s should't be an archive",
file_name);
if(archive_all == TRUE){
if(offset + sizeof(struct ar_hdr) > file_size){
error("truncated or malformed archive: %s (archive header of "
"first member extends past the end of the file, can't "
"load from it)", file_name);
return;
}
symdef_ar_hdr = (struct ar_hdr *)(file_addr + offset);
if(strncmp(symdef_ar_hdr->ar_name, AR_EFMT1,
sizeof(AR_EFMT1)-1) == 0)
ar_name = file_addr + offset + sizeof(struct ar_hdr);
else
ar_name = symdef_ar_hdr->ar_name;
if(strncmp(ar_name, SYMDEF, sizeof(SYMDEF)-1) == 0){
offset += sizeof(struct ar_hdr);
symdef_length = strtol(symdef_ar_hdr->ar_size, NULL, 10);
if(offset + symdef_length > file_size){
error("truncated or malformed archive: %s (table of "
"contents extends past the end of the file, can't "
"load from it)", file_name);
return;
}
offset += rnd(symdef_length, sizeof(short));
}
if(ld_trace_archives == TRUE && ld_trace_archive_printed == FALSE){
char resolvedname[MAXPATHLEN];
if(realpath(file_name, resolvedname) !=
NULL)
ld_trace("[Logging for XBS] Used static "
"archive: %s\n", resolvedname);
else
ld_trace("[Logging for XBS] Used static "
"archive: %s\n", file_name);
ld_trace_archive_printed = TRUE;
}
while(offset < file_size){
if(offset + sizeof(struct ar_hdr) > file_size){
error("truncated or malformed archive: %s at offset %lu "
"(archive header of next member extends past the end "
"of the file, can't load from it)", file_name,offset);
return;
}
ar_hdr = (struct ar_hdr *)(file_addr + offset);
if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1)-1) == 0){
ar_name = file_addr + offset + sizeof(struct ar_hdr);
ar_name_size = strtoul(ar_hdr->ar_name +
sizeof(AR_EFMT1) - 1, NULL, 10);
i = ar_name_size;
}
else{
ar_name = ar_hdr->ar_name;
ar_name_size = 0;
i = size_ar_name(ar_hdr);
}
offset += sizeof(struct ar_hdr) + ar_name_size;
ar_size = strtol(ar_hdr->ar_size, NULL, 10) - ar_name_size;
if(offset + ar_size > file_size){
error("truncated or malformed archive: %s (member %.*s "
"extends past the end of the file, can't load from "
"it)", file_name, (int)i, ar_name);
return;
}
fat_header = (struct fat_header *)(file_addr + offset);
if(ar_size >= sizeof(struct fat_header) &&
#ifdef __BIG_ENDIAN__
fat_header->magic == FAT_MAGIC)
#endif
#ifdef __LITTLE_ENDIAN__
fat_header->magic == SWAP_LONG(FAT_MAGIC))
#endif
{
#ifdef __LITTLE_ENDIAN__
struct_fat_header = *fat_header;
swap_fat_header(&struct_fat_header, host_byte_sex);
fat_header = &struct_fat_header;
#endif
if(sizeof(struct fat_header) + fat_header->nfat_arch *
sizeof(struct fat_arch) > ar_size){
error("fat file: %s(%.*s) truncated or malformed "
"(fat_arch structs would extend past the end of "
"the file)", file_name, (int)i, ar_name);
return;
}
#ifdef __BIG_ENDIAN__
fat_archs = (struct fat_arch *)(file_addr + offset +
sizeof(struct fat_header));
#endif
#ifdef __LITTLE_ENDIAN__
fat_archs = allocate(fat_header->nfat_arch *
sizeof(struct fat_arch));
memcpy(fat_archs, file_addr + offset +
sizeof(struct fat_header),
fat_header->nfat_arch * sizeof(struct fat_arch));
swap_fat_arch(fat_archs, fat_header->nfat_arch,
host_byte_sex);
#endif
check_fat(file_name, ar_size, fat_header, fat_archs,
ar_name, i);
if(errors)
return;
if(arch_flag.cputype != 0){
best_fat_arch = cpusubtype_findbestarch(
arch_flag.cputype, arch_flag.cpusubtype,
fat_archs, fat_header->nfat_arch);
if(best_fat_arch == NULL){
if(no_arch_warnings == TRUE)
return;
if(arch_flag.name != NULL){
if(arch_errors_fatal == TRUE){
error("fat file: %s(%.*s) does not contain "
"an architecture that matches the "
"specified -arch flag: %s", file_name,
(int)i, ar_name, arch_flag.name);
}
else
warning("fat file: %s(%.*s) does not "
"contain an architecture that matches "
"the specified -arch flag: %s (file "
"ignored)", file_name, (int)i,
ar_name, arch_flag.name);
}
else{
prev_arch = get_arch_name_from_types(
arch_flag.cputype, arch_flag.cpusubtype);
if(arch_errors_fatal == TRUE){
error("fat file: %s(%.*s) does not contain "
"an architecture that matches the "
"objects files (architecture %s) "
"previously loaded", file_name,
(int)i, ar_name, prev_arch);
}
else
warning("fat file: %s(%.*s) does not "
"contain an architecture that matches "
"the objects files (architecture %s) "
"previously loaded (file ignored)",
file_name, (int)i, ar_name, prev_arch);
}
return;
}
arch_addr = file_addr + offset + best_fat_arch->offset;
arch_size = best_fat_arch->size;
}
else if(fat_header->nfat_arch == 1){
arch_addr = file_addr + offset + fat_archs[0].offset;
arch_size = fat_archs[0].size;
}
else{
if(get_arch_from_host(NULL, &host_arch_flag) == 0)
fatal("can't determine the host architecture "
"(specify an -arch flag or fix "
"get_arch_from_host() )");
best_fat_arch = cpusubtype_findbestarch(
host_arch_flag.cputype, host_arch_flag.cpusubtype,
fat_archs, fat_header->nfat_arch);
if(best_fat_arch != NULL){
arch_addr = file_addr + offset +
best_fat_arch->offset;
arch_size = best_fat_arch->size;
}
else
fatal("-arch flag must be specified (fat file: "
"%s(%.*s) does not contain the host "
"architecture or just one architecture)",
file_name, (int)i, ar_name);
}
cur_obj = new_object_file();
cur_obj->file_name = file_name;
cur_obj->obj_addr = arch_addr;
cur_obj->obj_size = arch_size;
cur_obj->ar_hdr = ar_hdr;
cur_obj->ar_name = ar_name;
cur_obj->ar_name_size = i;
#ifdef __LITTLE_ENDIAN__
free(fat_archs);
#endif
goto down;
}
cur_obj = new_object_file();
cur_obj->file_name = file_name;
cur_obj->obj_addr = file_addr + offset;
cur_obj->ar_hdr = ar_hdr;
cur_obj->ar_name = ar_name;
cur_obj->ar_name_size = i;
cur_obj->obj_size = ar_size;
down:
if(whyload){
print_obj_name(cur_obj);
print("loaded because of -all_load flag\n");
}
merge(FALSE, FALSE, force_weak);
length = rnd(ar_size + ar_name_size, sizeof(short));
offset = (offset - ar_name_size) + length;
}
return;
}
#endif
if(undefined_list.next == &undefined_list && archive_ObjC == FALSE)
return;
#ifdef RLD
if(from_fat_file == FALSE)
new_archive_or_fat(file_name, file_addr, file_size);
#endif
if(offset == file_size){
warning("empty archive: %s (can't load from it)", file_name);
return;
}
if(offset + sizeof(struct ar_hdr) > file_size){
error("truncated or malformed archive: %s (archive header of first "
"member extends past the end of the file, can't load from "
" it)", file_name);
return;
}
symdef_ar_hdr = (struct ar_hdr *)(file_addr + offset);
if(strncmp(symdef_ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1)-1) == 0){
symdef_ar_name = file_addr + offset + sizeof(struct ar_hdr);
ar_name_size = strtoul(symdef_ar_hdr->ar_name +
sizeof(AR_EFMT1) - 1, NULL, 10);
}
else{
symdef_ar_name = symdef_ar_hdr->ar_name;
ar_name_size = 0;
}
offset += sizeof(struct ar_hdr) + ar_name_size;
if(strncmp(symdef_ar_name, SYMDEF, sizeof(SYMDEF) - 1) != 0){
error("archive: %s has no table of contents, add one with "
"ranlib(1) (can't load from it)", file_name);
return;
}
symdef_length = strtol(symdef_ar_hdr->ar_size, NULL, 10) - ar_name_size;
if(symdef_length < 2 * sizeof(long)){
error("size of table of contents for archive: %s too small to be "
"a valid table of contents (can't load from it)", file_name);
return;
}
if(offset + symdef_length > file_size){
error("truncated or malformed archive: %s (table of contents "
"extends past the end of the file, can't load from it)",
file_name);
return;
}
toc_byte_sex = get_toc_byte_sex(file_addr, file_size);
nranlibs = *((long *)(file_addr + offset));
if(toc_byte_sex != host_byte_sex)
nranlibs = SWAP_LONG(nranlibs);
nranlibs = nranlibs / sizeof(struct ranlib);
offset += sizeof(long);
ranlibs = (struct ranlib *)(file_addr + offset);
offset += sizeof(struct ranlib) * nranlibs;
if(nranlibs == 0){
warning("empty table of contents: %s (can't load from it)",
file_name);
return;
}
if(offset - (2 * sizeof(long) + ar_name_size + sizeof(struct ar_hdr) +
SARMAG) > symdef_length){
error("truncated or malformed archive: %s (ranlib structures in "
"table of contents extends past the end of the table of "
"contents, can't load from it)", file_name);
return;
}
string_size = *((long *)(file_addr + offset));
if(toc_byte_sex != host_byte_sex)
string_size = SWAP_LONG(string_size);
offset += sizeof(long);
bsearch_strings = file_addr + offset;
offset += string_size;
if(offset - (2 * sizeof(long) + ar_name_size + sizeof(struct ar_hdr) +
SARMAG) > symdef_length){
error("truncated or malformed archive: %s (ranlib strings in "
"table of contents extends past the end of the table of "
"contents, can't load from it)", file_name);
return;
}
if(symdef_length == 2 * sizeof(long)){
warning("empty table of contents for archive: %s (can't load from "
"it)", file_name);
return;
}
if(toc_byte_sex != host_byte_sex)
swap_ranlib(ranlibs, nranlibs, host_byte_sex);
for(i = 0; i < nranlibs; i++){
if(ranlibs[i].ran_un.ran_strx >= string_size){
error("malformed table of contents in: %s (ranlib struct %lu "
"has bad string index, can't load from it)", file_name,i);
return;
}
if(ranlibs[i].ran_off + sizeof(struct ar_hdr) >= file_size){
error("malformed table of contents in: %s (ranlib struct %lu "
"has bad library member offset, can't load from it)",
file_name, i);
return;
}
#if defined(mc68000) || defined(__i386__)
if(ranlibs[i].ran_off % sizeof(short) != 0){
error("malformed table of contents in: %s (ranlib struct %lu "
"library member offset not a multiple of %lu bytes, can't"
" load from it)", file_name, i, sizeof(short));
return;
}
#else
if(ranlibs[i].ran_off % sizeof(long) != 0){
error("malformed table of contents in: %s (ranlib struct %lu "
"library member offset not a multiple of %lu bytes, can't"
" load from it)", file_name, i, sizeof(long));
return;
}
#endif
}
#ifndef RLD
if(archive_ObjC == TRUE){
loaded_offsets = allocate(nranlibs * sizeof(unsigned long));
nloaded_offsets = 0;
for(i = 0; i < nranlibs; i++){
if(strncmp(bsearch_strings + ranlibs[i].ran_un.ran_strx,
".objc_class_name",
sizeof(".objc_class_name") - 1) != 0 &&
strncmp(bsearch_strings + ranlibs[i].ran_un.ran_strx,
".objc_category_name",
sizeof(".objc_category_name") - 1) != 0)
continue;
loaded_offset = FALSE;
for(j = 0; j < nloaded_offsets; j++){
if(loaded_offsets[j] == ranlibs[i].ran_off){
loaded_offset = TRUE;
break;
}
}
if(loaded_offset == TRUE)
continue;
loaded_offsets[nloaded_offsets++] = ranlibs[i].ran_off;
if(ld_trace_archives == TRUE &&
ld_trace_archive_printed == FALSE){
char resolvedname[MAXPATHLEN];
if(realpath(file_name, resolvedname) !=
NULL)
ld_trace("[Logging for XBS] Used static "
"archive: %s\n", resolvedname);
else
ld_trace("[Logging for XBS] Used static "
"archive: %s\n", file_name);
ld_trace_archive_printed = TRUE;
}
cur_obj = new_object_file();
cur_obj->file_name = file_name;
cur_obj->ar_hdr = (struct ar_hdr *)(file_addr +
ranlibs[i].ran_off);
if(strncmp(cur_obj->ar_hdr->ar_name, AR_EFMT1,
sizeof(AR_EFMT1) - 1) == 0){
ar_name = file_addr + ranlibs[i].ran_off +
sizeof(struct ar_hdr);
ar_name_size = strtoul(cur_obj->ar_hdr->ar_name +
sizeof(AR_EFMT1) - 1, NULL, 10);
j = ar_name_size;
}
else{
ar_name = cur_obj->ar_hdr->ar_name;
ar_name_size = 0;
j = size_ar_name(cur_obj->ar_hdr);
}
cur_obj->ar_name = ar_name;
cur_obj->ar_name_size = j;
cur_obj->obj_addr = file_addr + ranlibs[i].ran_off +
sizeof(struct ar_hdr) + ar_name_size;
cur_obj->obj_size = strtol(cur_obj->ar_hdr->ar_size,
NULL, 10) - ar_name_size;
if(ranlibs[i].ran_off + sizeof(struct ar_hdr) + ar_name_size +
cur_obj->obj_size > file_size){
error("malformed library: %s (member %.*s "
"extends past the end of the file, can't "
"load from it)", file_name, (int)j, ar_name);
return;
}
if(whyload){
print_obj_name(cur_obj);
print("loaded because of -ObjC flag to get symbol: %s\n",
bsearch_strings + ranlibs[i].ran_un.ran_strx);
}
merge(FALSE, FALSE, force_weak);
}
free(loaded_offsets);
}
if(dynamic_libs != NULL){
p = add_dynamic_lib(SORTED_ARCHIVE, NULL, NULL);
if(strncmp(symdef_ar_name, SYMDEF_SORTED,
sizeof(SYMDEF_SORTED) - 1) == 0){
p->type = SORTED_ARCHIVE;
#ifdef notdef
warning("archive library: %s appears after reference to "
"dynamic shared library and will be searched as a "
"dynamic shared library which only the first member "
"that defines a symbol will ever be loaded", file_name);
#endif
}
else{
p->type = UNSORTED_ARCHIVE;
#ifdef notdef
warning("table of contents of library: %s not sorted slower "
"link editing will result (use the ranlib(1) -s "
"option), also library appears after reference to "
"dynamic shared library and will be searched as a "
"dynamic shared library which only the first member "
"that defines a symbol will ever be loaded", file_name);
#endif
}
p->file_name = file_name;
p->file_addr = file_addr;
p->file_size = file_size;
p->nranlibs = nranlibs;
p->ranlibs = ranlibs;
p->ranlib_strings = bsearch_strings;
return;
}
#endif
if(strncmp(symdef_ar_name, SYMDEF_SORTED,
sizeof(SYMDEF_SORTED) - 1) == 0){
for(undefined = undefined_list.next;
undefined != &undefined_list;
){
if(undefined->merged_symbol->nlist.n_type != (N_UNDF | N_EXT) ||
undefined->merged_symbol->nlist.n_value != 0){
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
continue;
}
ranlib = bsearch(undefined->merged_symbol->nlist.n_un.n_name,
ranlibs, nranlibs, sizeof(struct ranlib),
(int (*)(const void *, const void *))ranlib_bsearch);
if(ranlib != NULL){
if(ld_trace_archives == TRUE &&
ld_trace_archive_printed == FALSE){
char resolvedname[MAXPATHLEN];
if(realpath(file_name, resolvedname) != NULL)
ld_trace("[Logging for XBS] Used "
"static archive: %s\n", resolvedname);
else
ld_trace("[Logging for XBS] Used "
"static archive: %s\n", file_name);
ld_trace_archive_printed = TRUE;
}
cur_obj = new_object_file();
#ifdef RLD
cur_obj->file_name = allocate(strlen(file_name) + 1);
strcpy(cur_obj->file_name, file_name);
cur_obj->from_fat_file = from_fat_file;
#else
cur_obj->file_name = file_name;
#endif
cur_obj->ar_hdr = (struct ar_hdr *)(file_addr +
ranlib->ran_off);
if(strncmp(cur_obj->ar_hdr->ar_name, AR_EFMT1,
sizeof(AR_EFMT1)-1) == 0){
ar_name = file_addr + ranlib->ran_off +
sizeof(struct ar_hdr);
ar_name_size = strtoul(cur_obj->ar_hdr->ar_name +
sizeof(AR_EFMT1) - 1, NULL, 10);
j = ar_name_size;
}
else{
ar_name = cur_obj->ar_hdr->ar_name;
ar_name_size = 0;
j = size_ar_name(cur_obj->ar_hdr);
}
cur_obj->ar_name = ar_name;
cur_obj->ar_name_size = j;
cur_obj->obj_addr = file_addr + ranlib->ran_off +
sizeof(struct ar_hdr) + ar_name_size;
cur_obj->obj_size = strtol(cur_obj->ar_hdr->ar_size, NULL,
10) - ar_name_size;
if(ranlib->ran_off + sizeof(struct ar_hdr) + ar_name_size +
cur_obj->obj_size > file_size){
error("malformed library: %s (member %.*s extends past "
"the end of the file, can't load from it)",
file_name, (int)j, ar_name);
return;
}
if(whyload){
print_obj_name(cur_obj);
print("loaded to resolve symbol: %s\n",
undefined->merged_symbol->nlist.n_un.n_name);
}
merge(FALSE, FALSE, force_weak);
if(errors == 0 &&
undefined->merged_symbol->nlist.n_type == (N_UNDF|N_EXT)
&& undefined->merged_symbol->nlist.n_value == 0){
error("malformed table of contents in library: %s "
"(member %.*s did not define symbol %s)",
file_name, (int)j, ar_name,
undefined->merged_symbol->nlist.n_un.n_name);
}
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
continue;
}
undefined = undefined->next;
}
}
else{
member_loaded = TRUE;
while(member_loaded == TRUE && errors == 0){
member_loaded = FALSE;
for(i = 0; i < nranlibs; i++){
merged_symbol = lookup_symbol(bsearch_strings +
ranlibs[i].ran_un.ran_strx);
if(merged_symbol->name_len != 0){
if(merged_symbol->nlist.n_type == (N_UNDF | N_EXT) &&
merged_symbol->nlist.n_value == 0){
if(ld_trace_archives == TRUE &&
ld_trace_archive_printed == FALSE){
char resolvedname[MAXPATHLEN];
if(realpath(file_name, resolvedname) != NULL)
ld_trace("[Logging for XBS] "
"Used static archive: %s\n",
resolvedname);
else
ld_trace("[Logging for XBS] "
"Used static archive: %s\n",
file_name);
ld_trace_archive_printed = TRUE;
}
cur_obj = new_object_file();
#ifdef RLD
cur_obj->file_name = allocate(strlen(file_name) +1);
strcpy(cur_obj->file_name, file_name);
cur_obj->from_fat_file = from_fat_file;
#else
cur_obj->file_name = file_name;
#endif
cur_obj->ar_hdr = (struct ar_hdr *)(file_addr +
ranlibs[i].ran_off);
if(strncmp(cur_obj->ar_hdr->ar_name, AR_EFMT1,
sizeof(AR_EFMT1)-1) == 0){
ar_name = file_addr + ranlibs[i].ran_off +
sizeof(struct ar_hdr);
ar_name_size =
strtoul(cur_obj->ar_hdr->ar_name +
sizeof(AR_EFMT1) - 1, NULL, 10);
j = ar_name_size;
}
else{
ar_name = cur_obj->ar_hdr->ar_name;
ar_name_size = 0;
j = size_ar_name(cur_obj->ar_hdr);
}
cur_obj->ar_name = ar_name;
cur_obj->ar_name_size = j;
cur_obj->obj_addr = file_addr + ranlibs[i].ran_off +
sizeof(struct ar_hdr) + ar_name_size;
cur_obj->obj_size = strtol(cur_obj->ar_hdr->ar_size,
NULL, 10) - ar_name_size;
if(ranlibs[i].ran_off + sizeof(struct ar_hdr) +
ar_name_size + cur_obj->obj_size > file_size){
error("malformed library: %s (member %.*s "
"extends past the end of the file, can't "
"load from it)", file_name, (int)j,
ar_name);
return;
}
if(whyload){
print_obj_name(cur_obj);
print("loaded to resolve symbol: %s\n",
merged_symbol->nlist.n_un.n_name);
}
merge(FALSE, FALSE, force_weak);
if(errors == 0 &&
merged_symbol->nlist.n_type == (N_UNDF | N_EXT)
&& merged_symbol->nlist.n_value == 0){
error("malformed table of contents in library: "
"%s (member %.*s did not defined "
"symbol %s)", file_name, (int)j, ar_name,
merged_symbol->nlist.n_un.n_name);
}
for(j = i; j + 1 < nranlibs; j++){
if(ranlibs[i].ran_off != ranlibs[j + 1].ran_off)
break;
}
i = j;
member_loaded = TRUE;
}
}
}
}
}
}
__private_extern__
enum byte_sex
get_toc_byte_sex(
char *addr,
uint32_t size)
{
uint32_t magic;
uint32_t ar_name_size;
struct ar_hdr *ar_hdr;
char *p;
ar_hdr = (struct ar_hdr *)(addr + SARMAG);
p = addr + SARMAG + sizeof(struct ar_hdr) +
rnd(strtoul(ar_hdr->ar_size, NULL, 10), sizeof(short));
while(p + sizeof(struct ar_hdr) + sizeof(uint32_t) < addr + size){
ar_hdr = (struct ar_hdr *)p;
if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0)
ar_name_size = strtoul(ar_hdr->ar_name + sizeof(AR_EFMT1) - 1,
NULL, 10);
else
ar_name_size = 0;
p += sizeof(struct ar_hdr);
memcpy(&magic, p + ar_name_size, sizeof(uint32_t));
if(magic == MH_MAGIC || magic == MH_MAGIC_64)
return(get_host_byte_sex());
else if(magic == SWAP_INT(MH_MAGIC) ||
magic == SWAP_INT(MH_MAGIC_64))
return(get_host_byte_sex() == BIG_ENDIAN_BYTE_SEX ?
LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX);
p += rnd(strtoul(ar_hdr->ar_size, NULL, 10), sizeof(short));
}
return(UNKNOWN_BYTE_SEX);
}
static
enum bool
check_archive_arch(
char *file_name,
char *file_addr,
unsigned long file_size)
{
unsigned long offset, obj_size, length;
struct ar_hdr *symdef_ar_hdr, *ar_hdr;
unsigned long symdef_length, ar_name_size;
char *obj_addr, *ar_name;
struct mach_header mh;
cpu_type_t cputype;
cpu_subtype_t cpusubtype;
enum bool mixed_types;
const char *new_arch, *prev_arch;
cputype = 0;
cpusubtype = 0;
mixed_types = FALSE;
offset = SARMAG;
if(offset == file_size){
warning("empty archive: %s (can't load from it)", file_name);
return(FALSE);
}
if(offset + sizeof(struct ar_hdr) > file_size){
error("truncated or malformed archive: %s (archive header of "
"first member extends past the end of the file, can't "
"load from it)", file_name);
return(FALSE);
}
symdef_ar_hdr = (struct ar_hdr *)(file_addr + offset);
if(strncmp(symdef_ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1)-1) == 0){
if(check_extend_format_1(file_name, symdef_ar_hdr,
file_size - (offset +sizeof(struct ar_hdr)),
&ar_name_size) == FALSE)
return(FALSE);
ar_name = file_addr + offset + sizeof(struct ar_hdr);
}
else{
ar_name = symdef_ar_hdr->ar_name;
ar_name_size = 0;
}
if(strncmp(ar_name, SYMDEF, sizeof(SYMDEF) - 1) == 0){
offset += sizeof(struct ar_hdr);
symdef_length = strtol(symdef_ar_hdr->ar_size, NULL, 10);
if(offset + symdef_length > file_size){
error("truncated or malformed archive: %s (table of "
"contents extends past the end of the file, can't "
"load from it)", file_name);
return(FALSE);
}
offset += rnd(symdef_length, sizeof(short));
}
while(offset < file_size){
if(offset + sizeof(struct ar_hdr) > file_size){
error("truncated or malformed archive: %s at offset %lu "
"(archive header of next member extends past the end "
"of the file, can't load from it)", file_name, offset);
return(FALSE);
}
ar_hdr = (struct ar_hdr *)(file_addr + offset);
offset += sizeof(struct ar_hdr);
if(strncmp(ar_hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0){
if(check_extend_format_1(file_name, ar_hdr, file_size - offset,
&ar_name_size) == FALSE)
return(FALSE);
ar_name = file_addr + offset;
}
else{
ar_name = ar_hdr->ar_name;
ar_name_size = 0;
}
offset += ar_name_size;
obj_addr = file_addr + offset;
obj_size = strtol(ar_hdr->ar_size, NULL, 10);
obj_size -= ar_name_size;
if(offset + obj_size > file_size){
error("truncated or malformed archive: %s at offset %lu "
"(member extends past the end of the file, can't load "
"from it)", file_name, offset);
return(FALSE);
}
if(obj_size >= sizeof(struct mach_header)){
memcpy(&mh, obj_addr, sizeof(struct mach_header));
if(mh.magic == SWAP_LONG(MH_MAGIC))
swap_mach_header(&mh, host_byte_sex);
if(mh.magic == MH_MAGIC){
if(cputype == 0){
cputype = mh.cputype;
cpusubtype = mh.cpusubtype;
}
else if(cputype != mh.cputype){
mixed_types = TRUE;
}
}
}
length = rnd(obj_size, sizeof(short));
offset += length;
}
if(arch_flag.cputype != 0 && mixed_types == FALSE &&
arch_flag.cputype != cputype && cputype != 0){
if(no_arch_warnings == TRUE)
return(FALSE);
new_arch = get_arch_name_from_types(cputype, cpusubtype);
prev_arch = get_arch_name_from_types(arch_flag.cputype,
arch_flag.cpusubtype);
if(arch_flag.name != NULL)
warning("%s archive's cputype (%d, architecture %s) does "
"not match cputype (%d) for specified -arch flag: "
"%s (can't load from it)", file_name, cputype, new_arch,
arch_flag.cputype, arch_flag.name);
else
warning("%s archive's cputype (%d, architecture %s) does "
"not match cputype (%d architecture %s) of objects "
"files previously loaded (can't load from it)", file_name,
cputype, new_arch, arch_flag.cputype, prev_arch);
return(FALSE);
}
return(TRUE);
}
static
enum bool
check_extend_format_1(
char *name,
struct ar_hdr *ar_hdr,
unsigned long size_left,
unsigned long *member_name_size)
{
char *p, *endp, buf[sizeof(ar_hdr->ar_name)+1];
unsigned long ar_name_size;
*member_name_size = 0;
buf[sizeof(ar_hdr->ar_name)] = '\0';
memcpy(buf, ar_hdr->ar_name, sizeof(ar_hdr->ar_name));
p = buf + sizeof(AR_EFMT1) - 1;
if(isdigit(*p) == 0){
error("truncated or malformed archive: %s (ar_name: %.*s for "
"archive extend format #1 starts with non-digit)", name,
(int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
return(FALSE);
}
ar_name_size = strtoul(p, &endp, 10);
if(ar_name_size == ULONG_MAX && errno == ERANGE){
error("truncated or malformed archive: %s (size in ar_name: %.*s "
"for archive extend format #1 overflows unsigned long)",
name, (int)sizeof(ar_hdr->ar_name), ar_hdr->ar_name);
return(FALSE);
}
while(*endp == ' ' && *endp != '\0')
endp++;
if(*endp != '\0'){
error("truncated or malformed archive: %s (size in ar_name: %.*s "
"for archive extend format #1 contains non-digit and "
"non-space characters)", name, (int)sizeof(ar_hdr->ar_name),
ar_hdr->ar_name);
return(FALSE);
}
if(ar_name_size > size_left){
error("truncated or malformed archive: %s (archive name of member "
"extends past the end of the file)", name);
return(FALSE);
}
*member_name_size = ar_name_size;
return(TRUE);
}
static
void
pass1_object(
char *file_name,
char *file_addr,
unsigned long file_size,
enum bool base_name,
enum bool from_fat_file,
enum bool dylib_only,
enum bool bundle_loader,
enum bool force_weak)
{
#ifdef __MWERKS__
enum bool dummy;
dummy = base_name;
dummy = from_fat_file;
#endif
cur_obj = new_object_file();
#ifdef RLD
cur_obj->file_name = allocate(strlen(file_name) + 1);
strcpy(cur_obj->file_name, file_name);
cur_obj->from_fat_file = from_fat_file;
#else
cur_obj->file_name = file_name;
#endif
cur_obj->obj_addr = file_addr;
cur_obj->obj_size = file_size;
#ifndef RLD
if(base_name == TRUE)
base_obj = cur_obj;
#endif
merge(dylib_only, bundle_loader, force_weak);
#ifndef RLD
if(base_name == TRUE)
collect_base_obj_segments();
#endif
return;
}
#ifndef RLD
__private_extern__
void
search_dynamic_libs(
void)
{
struct dynamic_library *p, *q, *dep, *prev;
unsigned long i, j, nmodules, size, ar_name_size;
enum bool removed, some_images_setup;
char *ar_name;
struct mach_header *mh;
struct load_command *lc;
struct dylib_command *dl;
struct segment_command *sg;
struct undefined_list *undefined;
enum bool found;
struct dylib_table_of_contents *toc;
struct ranlib *ranlib;
enum bool bind_at_load_warning;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
unsigned long library_ordinal;
char *umbrella_install_name, *short_name, *has_suffix;
enum bool is_framework, set_some_ordinals, non_set_ordinals;
struct nlist *extdef_symbols, *extdef;
library_ordinal = 1;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB && p->dl->cmd == LC_ID_DYLIB){
if(twolevel_namespace == TRUE){
if(library_ordinal > MAX_LIBRARY_ORDINAL)
fatal("too many dynamic libraries used, maximum is: %d "
"when -twolevel_namespace is in effect",
MAX_LIBRARY_ORDINAL);
}
p->definition_obj->library_ordinal = library_ordinal;
library_ordinal++;
p->dependent_images =
allocate(p->definition_obj->nload_dylibs *
sizeof(struct dynamic_library *));
}
else if(p->type == BUNDLE_LOADER){
p->definition_obj->library_ordinal = EXECUTABLE_ORDINAL;
}
}
indirect_dylib = TRUE;
prev = NULL;
for(p = dynamic_libs; p != NULL; p = p->next){
removed = FALSE;
if(p->type == DYLIB &&
(p->dl->cmd == LC_LOAD_DYLIB ||
p->dl->cmd == LC_LOAD_WEAK_DYLIB ||
p->dl->cmd == LC_REEXPORT_DYLIB)){
if(open_dylib(p) == FALSE){
if(prebinding == TRUE){
warning("prebinding disabled because dependent "
"library: %s can't be searched", p->dylib_file !=
NULL ? p->file_name : p->dylib_name);
if(ld_trace_prebinding_disabled == TRUE)
ld_trace("[Logging for XBS] prebinding"
" disabled for %s because dependent library: "
"%s can't be searched\n", final_output !=
NULL ? final_output : outputfile,
p->dylib_file != NULL ? p->file_name :
p->dylib_name);
prebinding = FALSE;
}
if(prev == NULL)
dynamic_libs = p->next;
else
prev->next = p->next;
removed = TRUE;
}
else{
p->dependent_images =
allocate(p->definition_obj->nload_dylibs *
sizeof(struct dynamic_library *));
}
}
if(removed == FALSE &&
p->type == DYLIB && p->dl->cmd == LC_ID_DYLIB){
mh = (struct mach_header *)p->definition_obj->obj_addr;
if(prebinding == TRUE &&
(mh->flags & MH_PREBOUND) != MH_PREBOUND){
warning("prebinding disabled because dependent library: %s "
"is not prebound", p->dylib_file != NULL ?
p->file_name : p->dylib_name);
if(ld_trace_prebinding_disabled == TRUE)
ld_trace("[Logging for XBS] prebinding "
"disabled for %s because dependent library: %s "
"is not prebound\n", final_output != NULL ?
final_output : outputfile, p->dylib_file !=
NULL ? p->file_name : p->dylib_name);
prebinding = FALSE;
}
lc = (struct load_command *)
((char *)p->definition_obj->obj_addr +
sizeof(struct mach_header));
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_LOAD_DYLIB ||
lc->cmd == LC_LOAD_WEAK_DYLIB ||
lc->cmd == LC_REEXPORT_DYLIB){
dl = (struct dylib_command *)lc;
dep = add_dynamic_lib(DYLIB, dl, p->definition_obj);
p->dependent_images[p->ndependent_images++] = dep;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
if(removed == FALSE)
prev = p;
}
indirect_dylib = FALSE;
#ifdef DEBUG
if(debug & (1 << 22)){
print("dynamic library search list and ordinals before sub "
"assignments:\n");
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
if(p->dylib_file != NULL)
printf(" %s ordinal %lu (using file %s)\n",
p->dylib_name, p->definition_obj->library_ordinal,
p->file_name);
else{
short_name = guess_short_name(p->dylib_name,
&is_framework, &has_suffix);
printf(" %s oridinal %lu\n", short_name != NULL ?
short_name : p->dylib_name,
p->definition_obj->library_ordinal);
}
}
else
printf(" %s (archive)\n", p->file_name);
}
}
#endif
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type != DYLIB)
continue;
if(p->umbrella_name == NULL){
umbrella_install_name = (char *)p->dl +
p->dl->dylib.name.offset;
short_name = guess_short_name(umbrella_install_name,
&is_framework, &has_suffix);
if(short_name != NULL && is_framework == TRUE)
p->umbrella_name = short_name;
else if(short_name != NULL && is_framework == FALSE)
p->library_name = short_name;
}
}
do{
some_images_setup = FALSE;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type != DYLIB)
continue;
if(p->sub_images_setup == FALSE)
some_images_setup |= setup_sub_images(p);
}
}while(some_images_setup == TRUE);
do{
set_some_ordinals = FALSE;
non_set_ordinals = FALSE;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type != DYLIB)
continue;
if(p->definition_obj->library_ordinal != 0 &&
p->umbrella_name != NULL)
set_some_ordinals |= set_sub_frameworks_ordinals(p);
else
non_set_ordinals = TRUE;
}
if(non_set_ordinals == TRUE){
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type != DYLIB)
continue;
if(p->definition_obj->library_ordinal == 0 &&
(p->umbrella_name != NULL ||
p->library_name != NULL)){
set_some_ordinals |=
set_sub_umbrella_sub_library_ordinal(p);
}
}
}
}while(set_some_ordinals == TRUE);
#ifdef DEBUG
if(debug & (1 << 22)){
print("dynamic library search list and ordinals after sub "
"assignments:\n");
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
if(p->dylib_file != NULL)
printf(" %s ordinal %lu isub_image %lu "
"(using file %s)\n", p->dylib_name,
p->definition_obj->library_ordinal,
p->definition_obj->isub_image, p->file_name);
else{
short_name = guess_short_name(p->dylib_name,
&is_framework, &has_suffix);
printf(" %s oridinal %lu isub_image %lu\n",
short_name != NULL ? short_name : p->dylib_name,
p->definition_obj->library_ordinal,
p->definition_obj->isub_image);
}
print(" ndependent_images = %lu\n",p->ndependent_images);
for(i = 0; i < p->ndependent_images; i++){
dep = p->dependent_images[i];
short_name = guess_short_name(dep->dylib_name,
&is_framework, &has_suffix);
printf(" [%lu] %s\n", i, short_name != NULL ?
short_name : dep->dylib_name);
}
print(" nsub_images = %lu\n",p->nsub_images);
for(i = 0; i < p->nsub_images; i++){
dep = p->sub_images[i];
short_name = guess_short_name(dep->dylib_name,
&is_framework, &has_suffix);
printf(" [%lu] %s\n", i, short_name != NULL ?
short_name : dep->dylib_name);
}
}
else
printf(" %s (archive)\n", p->file_name);
}
}
#endif
if((twolevel_namespace == TRUE) &&
(force_flat_namespace == FALSE) &&
(filetype != MH_OBJECT)){
struct dynamic_library* last_library;
unsigned int total_library_count;
unsigned int direct_library_count;
last_library = NULL;
total_library_count = 0;
direct_library_count = 0;
for(p = dynamic_libs; p != NULL; p = p->next){
total_library_count += 1;
if((p->type == DYLIB) &&
(p->definition_obj->library_ordinal == 0)){
if(last_library == NULL)
dynamic_libs = p->next;
else
last_library->next = p->next;
}
else{
last_library = p;
direct_library_count += 1;
}
}
if(direct_library_count != 0)
indirect_library_ratio =
total_library_count / direct_library_count;
}
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
if(p->dl->cmd == LC_ID_DYLIB){
p->tocs = (struct dylib_table_of_contents *)(
p->definition_obj->obj_addr +
p->definition_obj->dysymtab->tocoff);
p->strings = p->definition_obj->obj_addr +
p->definition_obj->symtab->stroff;
p->symbols = (struct nlist *)(
p->definition_obj->obj_addr +
p->definition_obj->symtab->symoff);
if(p->definition_obj->swapped)
swap_nlist(p->symbols,
p->definition_obj->symtab->nsyms,
host_byte_sex);
p->mods = (struct dylib_module *)(
p->definition_obj->obj_addr +
p->definition_obj->dysymtab->modtaboff);
if(prebinding == TRUE && filetype == MH_EXECUTE){
nmodules = p->definition_obj->dysymtab->nmodtab +
(p->definition_obj->dysymtab->nmodtab >> 2);
if(nmodules < 64)
nmodules = 64;
size = sizeof(struct prebound_dylib_command) +
rnd(strlen(p->dylib_name) + 1, sizeof(long)) +
rnd(nmodules / 8, sizeof(long));
p->pbdylib = allocate(size);
memset(p->pbdylib, '\0', size);
p->pbdylib->cmd = LC_PREBOUND_DYLIB;
p->pbdylib->cmdsize = size;
p->pbdylib->name.offset =
sizeof(struct prebound_dylib_command);
strcpy(((char *)p->pbdylib) +
sizeof(struct prebound_dylib_command),
p->dylib_name);
p->pbdylib->nmodules =
p->definition_obj->dysymtab->nmodtab;
p->pbdylib->linked_modules.offset =
sizeof(struct prebound_dylib_command) +
rnd(strlen(p->dylib_name) + 1, sizeof(long));
p->linked_modules = ((char *)p->pbdylib) +
sizeof(struct prebound_dylib_command) +
rnd(strlen(p->dylib_name) + 1, sizeof(long));
}
}
}
if(p->type == BUNDLE_LOADER){
p->strings = p->definition_obj->obj_addr +
p->definition_obj->symtab->stroff;
p->symbols = (struct nlist *)(
p->definition_obj->obj_addr +
p->definition_obj->symtab->symoff);
if(p->definition_obj->swapped)
swap_nlist(p->symbols,
p->definition_obj->symtab->nsyms,
host_byte_sex);
}
}
if(prebinding == TRUE){
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB && p->dl->cmd == LC_ID_DYLIB){
mh = (struct mach_header *)p->definition_obj->obj_addr;
lc = (struct load_command *)
((char *)p->definition_obj->obj_addr +
sizeof(struct mach_header));
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
add_dylib_segment(sg, p->dylib_name,
(mh->flags & MH_SPLIT_SEGS) == MH_SPLIT_SEGS);
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
}
#ifdef DEBUG
if(debug & (1 << 22)){
print("dynamic library search list:\n");
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
if(p->dylib_file != NULL)
printf("\t%s (using file %s)\n", p->dylib_name,
p->file_name);
else{
short_name = guess_short_name(p->dylib_name,
&is_framework, &has_suffix);
printf("\t%s\n", short_name != NULL ?
short_name : p->dylib_name);
}
}
else
printf("\t%s (archive)\n", p->file_name);
}
}
#endif
if(ld_trace_dylibs == TRUE){
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
char resolvedname[MAXPATHLEN];
if(realpath(p->definition_obj->file_name, resolvedname) !=
NULL)
ld_trace("[Logging for XBS] Used dynamic "
"library: %s\n", resolvedname);
else
ld_trace("[Logging for XBS] Used dynamic "
"library: %s\n", p->definition_obj->file_name);
}
}
}
for(undefined = undefined_list.next;
undefined != &undefined_list;
){
if(undefined->merged_symbol->twolevel_reference == TRUE){
library_ordinal = GET_LIBRARY_ORDINAL(
undefined->merged_symbol->nlist.n_desc);
if(library_ordinal == SELF_LIBRARY_ORDINAL)
p = undefined->merged_symbol->referencing_library;
else if(library_ordinal == DYNAMIC_LOOKUP_ORDINAL)
fatal("internal error: search_dynamic_libs() with a "
"merged_symbol (%s) on the undefined list with "
"twolevel_reference == TRUE and library_ordinal == "
"DYNAMIC_LOOKUP_ORDINAL", undefined->merged_symbol->
nlist.n_un.n_name);
else
p = undefined->merged_symbol->referencing_library->
dependent_images[library_ordinal - 1];
q = p;
if(p->dl->cmd == LC_LOAD_DYLIB ||
p->dl->cmd == LC_LOAD_WEAK_DYLIB ||
p->dl->cmd == LC_REEXPORT_DYLIB)
goto undefined_twolevel_reference;
bsearch_strings = q->strings;
bsearch_symbols = q->symbols;
toc = bsearch(undefined->merged_symbol->nlist.n_un.n_name,
q->tocs, q->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
if(toc == NULL){
for(i = 0; toc == NULL && i < p->nsub_images; i++){
q = p->sub_images[i];
if(q->dl->cmd == LC_LOAD_DYLIB ||
q->dl->cmd == LC_LOAD_WEAK_DYLIB ||
q->dl->cmd == LC_REEXPORT_DYLIB)
break;
bsearch_strings = q->strings;
bsearch_symbols = q->symbols;
toc = bsearch(undefined->merged_symbol->
nlist.n_un.n_name, q->tocs,
q->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
}
}
if(toc != NULL){
if(is_dylib_module_loaded(q->mods + toc->module_index) ==
FALSE){
cur_obj = new_object_file();
*cur_obj = *(q->definition_obj);
cur_obj->dylib_module = q->mods + toc->module_index;
if(q->linked_modules != NULL)
q->linked_modules[toc->module_index / 8] |=
1 << toc->module_index % 8;
if(whyload){
print_obj_name(cur_obj);
print("loaded to resolve symbol: %s ",
undefined->merged_symbol->nlist.n_un.n_name);
dep = undefined->merged_symbol->referencing_library;
if(dep->umbrella_name != NULL)
short_name = dep->umbrella_name;
else if(dep->library_name != NULL)
short_name = dep->library_name;
else
short_name = dep->dylib_name;
print("referenced from %s\n", short_name);
}
merge_dylib_module_symbols(q);
load_init_dylib_module(q);
}
if(!Yflag)
free(undefined->merged_symbol);
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
}
else{
undefined_twolevel_reference:
undefined = undefined->next;
}
continue;
}
if(undefined->merged_symbol->nlist.n_type != (N_UNDF | N_EXT) ||
undefined->merged_symbol->nlist.n_value != 0){
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
continue;
}
if(twolevel_namespace == TRUE){
for(p = dynamic_libs; p != NULL; p = p->next)
p->twolevel_searched = FALSE;
}
found = FALSE;
for(p = dynamic_libs; p != NULL && found == FALSE; p = p->next){
switch(p->type){
case DYLIB:
if(twolevel_namespace == TRUE &&
p->twolevel_searched == TRUE)
break;
if(p->dl->cmd == LC_LOAD_DYLIB ||
p->dl->cmd == LC_LOAD_WEAK_DYLIB ||
p->dl->cmd == LC_REEXPORT_DYLIB)
break;
q = p;
bsearch_strings = q->strings;
bsearch_symbols = q->symbols;
toc = bsearch(undefined->merged_symbol->nlist.n_un.n_name,
q->tocs, q->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
if(toc == NULL && twolevel_namespace == TRUE){
q->twolevel_searched = TRUE;
for(i = 0; toc == NULL && i < p->nsub_images; i++){
q = p->sub_images[i];
q->twolevel_searched = TRUE;
if(q->dl->cmd == LC_LOAD_DYLIB ||
q->dl->cmd == LC_LOAD_WEAK_DYLIB ||
q->dl->cmd == LC_REEXPORT_DYLIB)
break;
if(q->definition_obj->library_ordinal == 0)
continue;
bsearch_strings = q->strings;
bsearch_symbols = q->symbols;
toc = bsearch(undefined->merged_symbol->
nlist.n_un.n_name, q->tocs,
q->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
}
}
if(toc != NULL){
cur_obj = new_object_file();
*cur_obj = *(q->definition_obj);
cur_obj->dylib_module = q->mods + toc->module_index;
if(q->linked_modules != NULL)
q->linked_modules[toc->module_index / 8] |=
1 << toc->module_index % 8;
if(whyload){
print_obj_name(cur_obj);
print("loaded to resolve symbol: %s\n",
undefined->merged_symbol->nlist.n_un.n_name);
}
merge_dylib_module_symbols(q);
if(errors == 0 &&
undefined->merged_symbol->nlist.n_type ==
(N_UNDF|N_EXT)
&& undefined->merged_symbol->nlist.n_value == 0){
error("malformed table of contents in library: "
"%s (module %s did not define symbol %s)",
cur_obj->file_name, bsearch_strings +
cur_obj->dylib_module->module_name,
undefined->merged_symbol->nlist.n_un.n_name);
}
if(twolevel_namespace == TRUE)
undefined->merged_symbol->itoc = toc - q->tocs;
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
found = TRUE;
load_init_dylib_module(q);
}
break;
case SORTED_ARCHIVE:
bsearch_strings = p->ranlib_strings;
ranlib = bsearch(undefined->merged_symbol->
nlist.n_un.n_name, p->ranlibs, p->nranlibs,
sizeof(struct ranlib),
(int (*)(const void *, const void *))
ranlib_bsearch);
if(ranlib != NULL){
if(ld_trace_archives == TRUE &&
p->ld_trace_archive_printed == FALSE){
char resolvedname[MAXPATHLEN];
if(realpath(p->file_name, resolvedname) != NULL)
ld_trace("[Logging for XBS] Used "
"static archive: %s\n", resolvedname);
else
ld_trace("[Logging for XBS] Used "
"static archive: %s\n", p->file_name);
p->ld_trace_archive_printed = TRUE;
}
cur_obj = new_object_file();
cur_obj->file_name = p->file_name;
cur_obj->ar_hdr = (struct ar_hdr *)(p->file_addr +
ranlib->ran_off);
if(strncmp(cur_obj->ar_hdr->ar_name, AR_EFMT1,
sizeof(AR_EFMT1)-1) == 0){
ar_name = p->file_addr + ranlib->ran_off +
sizeof(struct ar_hdr);
ar_name_size =
strtoul(cur_obj->ar_hdr->ar_name +
sizeof(AR_EFMT1) - 1, NULL, 10);
j = ar_name_size;
}
else{
ar_name = cur_obj->ar_hdr->ar_name;
ar_name_size = 0;
j = size_ar_name(cur_obj->ar_hdr);
}
cur_obj->ar_name = ar_name;
cur_obj->ar_name_size = j;
cur_obj->obj_addr = p->file_addr +
ranlib->ran_off +
sizeof(struct ar_hdr) +
ar_name_size;
cur_obj->obj_size = strtol(cur_obj->ar_hdr->ar_size,
NULL, 10) - ar_name_size;
if(ranlib->ran_off + sizeof(struct ar_hdr) +
ar_name_size + cur_obj->obj_size > p->file_size){
error("malformed library: %s (member %.*s extends "
"past the end of the file, can't load from "
"it)",p->file_name, (int)j, ar_name);
return;
}
if(whyload){
print_obj_name(cur_obj);
print("loaded to resolve symbol: %s\n",
undefined->merged_symbol->nlist.n_un.n_name);
}
merge(FALSE, FALSE, FALSE);
if(errors == 0 &&
undefined->merged_symbol->nlist.n_type ==
(N_UNDF|N_EXT)
&& undefined->merged_symbol->nlist.n_value == 0){
error("malformed table of contents in library: %s "
"(member %.*s did not define symbol %s)",
p->file_name, (int)j, ar_name,
undefined->merged_symbol->nlist.n_un.n_name);
}
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
found = TRUE;
}
break;
case UNSORTED_ARCHIVE:
for(i = 0; found == FALSE && i < p->nranlibs; i++){
if(strcmp(undefined->merged_symbol->nlist.n_un.n_name,
p->ranlib_strings +
p->ranlibs[i].ran_un.ran_strx) == 0){
if(ld_trace_archives == TRUE &&
p->ld_trace_archive_printed == FALSE){
char resolvedname[MAXPATHLEN];
if(realpath(p->file_name, resolvedname) != NULL)
ld_trace("[Logging for XBS] "
"Used static archive: %s\n",
resolvedname);
else
ld_trace("[Logging for XBS] "
"Used static archive: %s\n",
p->file_name);
p->ld_trace_archive_printed = TRUE;
}
cur_obj = new_object_file();
cur_obj->file_name = p->file_name;
cur_obj->ar_hdr = (struct ar_hdr *)(p->file_addr +
p->ranlibs[i].ran_off);
if(strncmp(cur_obj->ar_hdr->ar_name, AR_EFMT1,
sizeof(AR_EFMT1)-1) == 0){
ar_name = p->file_addr + p->ranlibs[i].ran_off +
sizeof(struct ar_hdr);
ar_name_size =
strtoul(cur_obj->ar_hdr->ar_name +
sizeof(AR_EFMT1) - 1, NULL, 10);
j = ar_name_size;
}
else{
ar_name = cur_obj->ar_hdr->ar_name;
ar_name_size = 0;
j = size_ar_name(cur_obj->ar_hdr);
}
cur_obj->ar_name = ar_name;
cur_obj->ar_name_size = j;
cur_obj->obj_addr = p->file_addr +
p->ranlibs[i].ran_off +
sizeof(struct ar_hdr) +
ar_name_size;
cur_obj->obj_size = strtol(cur_obj->ar_hdr->ar_size,
NULL, 10) - ar_name_size;
if(p->ranlibs[i].ran_off + sizeof(struct ar_hdr) +
ar_name_size + cur_obj->obj_size > p->file_size){
error("malformed library: %s (member %.*s "
"extends past the end of the file, can't "
"load from it)", p->file_name, (int)j,
ar_name);
return;
}
if(whyload){
print_obj_name(cur_obj);
print("loaded to resolve symbol: %s\n",
undefined->merged_symbol->nlist.n_un.n_name);
}
merge(FALSE, FALSE, FALSE);
if(errors == 0 &&
undefined->merged_symbol->nlist.n_type ==
(N_UNDF|N_EXT)
&& undefined->merged_symbol->nlist.n_value == 0){
error("malformed table of contents in library: "
"%s (member %.*s did not define symbol %s)",
p->file_name, (int)j, ar_name,
undefined->merged_symbol->nlist.n_un.n_name);
}
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
found = TRUE;
}
}
break;
case BUNDLE_LOADER:
bsearch_strings = p->definition_obj->obj_addr +
p->definition_obj->symtab->stroff;
extdef_symbols = (struct nlist *)(
p->definition_obj->obj_addr +
p->definition_obj->symtab->symoff) +
p->definition_obj->dysymtab->iextdefsym;
extdef =bsearch(undefined->merged_symbol->nlist.n_un.n_name,
extdef_symbols,
p->definition_obj->dysymtab->nextdefsym,
sizeof(struct nlist),
(int (*)(const void *, const void *))
nlist_bsearch);
if(extdef != NULL){
cur_obj = p->definition_obj;
if(whyload){
print_obj_name(cur_obj);
print("loaded to resolve symbol: %s\n",
undefined->merged_symbol->nlist.n_un.n_name);
}
merge_bundle_loader_symbols(p);
if(errors == 0 &&
undefined->merged_symbol->nlist.n_type ==
(N_UNDF|N_EXT)
&& undefined->merged_symbol->nlist.n_value == 0){
error("malformed external defined symbols of "
"-bundle_loader: %s (it did not define symbol "
"%s)", cur_obj->file_name,
undefined->merged_symbol->nlist.n_un.n_name);
}
undefined = undefined->next;
delete_from_undefined_list(undefined->prev);
found = TRUE;
}
break;
}
}
if(found == FALSE)
undefined = undefined->next;
}
if(filetype == MH_EXECUTE && bind_at_load == FALSE){
bind_at_load_warning = FALSE;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if(merged_symbol->defined_in_dylib != TRUE)
continue;
if(merged_symbol->coalesced_defined_in_dylib == TRUE)
continue;
if(twolevel_namespace == TRUE){
for(p = dynamic_libs; p != NULL; p = p->next)
p->twolevel_searched = FALSE;
}
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
if(twolevel_namespace == TRUE &&
p->twolevel_searched == TRUE)
break;
q = p;
if(q->dl->cmd == LC_LOAD_DYLIB ||
q->dl->cmd == LC_LOAD_WEAK_DYLIB ||
q->dl->cmd == LC_REEXPORT_DYLIB)
break;
bsearch_strings = q->strings;
bsearch_symbols = q->symbols;
toc = bsearch(merged_symbol->nlist.n_un.n_name,
q->tocs,q->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
if(toc == NULL && twolevel_namespace == TRUE){
q->twolevel_searched = TRUE;
for(j = 0;
toc == NULL && j < p->nsub_images;
j++){
q = p->sub_images[j];
q->twolevel_searched = TRUE;
if(q->dl->cmd == LC_LOAD_DYLIB ||
q->dl->cmd == LC_LOAD_WEAK_DYLIB ||
q->dl->cmd == LC_REEXPORT_DYLIB)
break;
bsearch_strings = q->strings;
bsearch_symbols = q->symbols;
toc = bsearch(merged_symbol->
nlist.n_un.n_name, q->tocs,
q->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
}
}
if(toc != NULL){
if(merged_symbol->definition_object->obj_addr
== q->definition_obj->obj_addr)
break;
if(merged_symbol->definition_object->obj_addr
!= q->definition_obj->obj_addr){
if(bind_at_load_warning == FALSE){
warning("suggest use of -bind_at_load, "
"as lazy binding may result in "
"errors or different symbols "
"being used");
bind_at_load_warning = TRUE;
}
printf("symbol %s used from dynamic "
"library %s(%s) not from earlier "
"dynamic library %s(%s)\n",
merged_symbol->nlist.n_un.n_name,
merged_symbol->definition_object->
file_name,
(merged_symbol->definition_object->
obj_addr + merged_symbol->
definition_object->symtab->stroff) +
merged_symbol->definition_object->
dylib_module->module_name,
q->dylib_name,
bsearch_strings + (q->mods +
toc->module_index)->module_name);
}
}
}
}
}
}
}
if(prebind_all_twolevel_modules == TRUE && prebinding == TRUE &&
filetype == MH_EXECUTE && force_flat_namespace == FALSE){
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB &&
p->dl->cmd == LC_ID_DYLIB &&
p->linked_modules != NULL){
mh = (struct mach_header *)(p->definition_obj->obj_addr);
if((mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL){
nmodules = p->definition_obj->dysymtab->nmodtab;
for(i = 0; i < nmodules; i++){
p->linked_modules[i / 8] |= 1 << i % 8;
}
}
}
}
}
}
static
void
load_init_dylib_module(
struct dynamic_library *q)
{
if(q->definition_obj->rc != NULL &&
q->definition_obj->init_module_loaded == FALSE){
if(is_dylib_module_loaded(q->mods +
q->definition_obj->rc->init_module) == FALSE){
cur_obj = new_object_file();
*cur_obj = *(q->definition_obj);
cur_obj->dylib_module = q->mods +
q->definition_obj->rc->init_module;
if(q->linked_modules != NULL)
q->linked_modules[q->definition_obj->rc->
init_module / 8] |= 1 <<
q->definition_obj->rc->init_module % 8;
if(whyload){
print_obj_name(cur_obj);
print("loaded for library initialization "
"routine\n");
}
merge_dylib_module_symbols(q);
}
q->definition_obj->init_module_loaded = TRUE;
}
}
static
enum bool
setup_sub_images(
struct dynamic_library *p)
{
unsigned long i, j, k, l, n, max_libraries;
struct mach_header *mh;
struct load_command *lc, *load_commands;
struct sub_umbrella_command *usub;
struct sub_library_command *lsub;
struct sub_framework_command *sub;
struct dynamic_library **deps;
char *sub_umbrella_name, *sub_library_name, *sub_framework_name;
enum bool found;
max_libraries = 0;
deps = p->dependent_images;
mh = (struct mach_header *)(p->definition_obj->obj_addr);
load_commands = (struct load_command *)((char *)mh +
sizeof(struct mach_header));
lc = load_commands;
for(i = 0; i < mh->ncmds; i++){
switch(lc->cmd){
case LC_SUB_UMBRELLA:
usub = (struct sub_umbrella_command *)lc;
sub_umbrella_name = (char *)usub + usub->sub_umbrella.offset;
for(j = 0; j < p->ndependent_images; j++){
if(deps[j]->umbrella_name != NULL &&
strcmp(sub_umbrella_name, deps[j]->umbrella_name) == 0){
if(deps[j]->sub_images_setup == FALSE)
return(FALSE);
max_libraries += 1 + deps[j]->nsub_images;
}
}
break;
case LC_SUB_LIBRARY:
lsub = (struct sub_library_command *)lc;
sub_library_name = (char *)lsub + lsub->sub_library.offset;
for(j = 0; j < p->ndependent_images; j++){
if(deps[j]->library_name != NULL &&
strcmp(sub_library_name, deps[j]->library_name) == 0){
if(deps[j]->sub_images_setup == FALSE)
return(FALSE);
max_libraries += 1 + deps[j]->nsub_images;
}
}
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
max_libraries += p->ndependent_images;
p->sub_images = allocate(max_libraries *
sizeof(struct dynamic_library *));
n = 0;
if(p->umbrella_name != NULL){
for(i = 0; i < p->ndependent_images; i++){
mh = (struct mach_header *)(deps[i]->definition_obj->obj_addr);
load_commands = (struct load_command *)((char *)mh +
sizeof(struct mach_header));
lc = load_commands;
for(j = 0; j < mh->ncmds; j++){
if(lc->cmd == LC_SUB_FRAMEWORK){
sub = (struct sub_framework_command *)lc;
sub_framework_name = (char *)sub + sub->umbrella.offset;
if(p->umbrella_name != NULL &&
strcmp(sub_framework_name, p->umbrella_name) == 0){
p->sub_images[n++] = deps[i];
if(p->force_weak_dylib == TRUE)
deps[i]->force_weak_dylib = TRUE;
goto next_dep;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
next_dep: ;
}
}
mh = (struct mach_header *)p->definition_obj->obj_addr;
load_commands = (struct load_command *)((char *)mh +
sizeof(struct mach_header));
lc = load_commands;
for(i = 0; i < mh->ncmds; i++){
switch(lc->cmd){
case LC_SUB_UMBRELLA:
usub = (struct sub_umbrella_command *)lc;
sub_umbrella_name = (char *)usub + usub->sub_umbrella.offset;
for(j = 0; j < p->ndependent_images; j++){
if(deps[j]->umbrella_name != NULL &&
strcmp(sub_umbrella_name, deps[j]->umbrella_name) == 0){
found = FALSE;
for(l = 0; l < n; l++){
if(p->sub_images[l] == deps[j]){
found = TRUE;
break;
}
}
if(found == FALSE){
p->sub_images[n++] = deps[j];
if(p->force_weak_dylib == TRUE)
deps[j]->force_weak_dylib = TRUE;
}
for(k = 0; k < deps[j]->nsub_images; k++){
found = FALSE;
for(l = 0; l < n; l++){
if(p->sub_images[l] == deps[j]->sub_images[k]){
found = TRUE;
break;
}
}
if(found == FALSE)
p->sub_images[n++] = deps[j]->sub_images[k];
}
}
}
break;
case LC_SUB_LIBRARY:
lsub = (struct sub_library_command *)lc;
sub_library_name = (char *)lsub + lsub->sub_library.offset;
for(j = 0; j < p->ndependent_images; j++){
if(deps[j]->library_name != NULL &&
strcmp(sub_library_name, deps[j]->library_name) == 0){
found = FALSE;
for(l = 0; l < n; l++){
if(p->sub_images[l] == deps[j]){
found = TRUE;
break;
}
}
if(found == FALSE)
p->sub_images[n++] = deps[j];
for(k = 0; k < deps[j]->nsub_images; k++){
found = FALSE;
for(l = 0; l < n; l++){
if(p->sub_images[l] == deps[j]->sub_images[k]){
found = TRUE;
break;
}
}
if(found == FALSE)
p->sub_images[n++] = deps[j]->sub_images[k];
}
}
}
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
p->nsub_images = n;
p->sub_images_setup = TRUE;
return(TRUE);
}
__private_extern__
void
prebinding_check_for_dylib_override_symbols(
void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
if(prebinding == TRUE){
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT)
continue;
check_dylibs_for_definition(merged_symbol, TRUE, FALSE);
}
}
}
}
__private_extern__
void
twolevel_namespace_check_for_unused_dylib_symbols(
void)
{
unsigned long i;
struct merged_symbol_list *merged_symbol_list;
struct merged_symbol *merged_symbol;
for(merged_symbol_list = merged_symbol_root == NULL ? NULL :
merged_symbol_root->list;
merged_symbol_list != NULL;
merged_symbol_list = merged_symbol_list->next){
for(i = 0; i < merged_symbol_list->used; i++){
merged_symbol = merged_symbol_list->symbols[i];
if((merged_symbol->nlist.n_type & N_PEXT) == N_PEXT)
continue;
check_dylibs_for_definition(merged_symbol, FALSE, TRUE);
}
}
}
static
void
check_dylibs_for_definition(
struct merged_symbol *merged_symbol,
enum bool prebind_check,
enum bool twolevel_namespace_check)
{
struct dynamic_library *p;
struct dylib_table_of_contents *toc;
static enum bool printed_override, printed_unused, merged_symbol_printed;
printed_override = FALSE;
printed_unused = FALSE;
merged_symbol_printed = FALSE;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
if(merged_symbol->defined_in_dylib == TRUE &&
p->definition_obj->file_name ==
merged_symbol->definition_object->file_name)
continue;
bsearch_strings = p->strings;
bsearch_symbols = p->symbols;
toc = bsearch(merged_symbol->nlist.n_un.n_name,
p->tocs, p->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
if(toc != NULL){
if(prebind_check == TRUE){
if(check_dylibs_for_reference(merged_symbol) == TRUE){
if(printed_override == FALSE){
if(ld_trace_prebinding_disabled == TRUE)
ld_trace("[Logging for XBS] "
"prebinding disabled for %s because "
"of symbols overridden in dependent "
"dynamic shared libraries\n",
final_output != NULL ? final_output :
outputfile);
warning("prebinding disabled because of symbols"
" overridden in dependent dynamic shared "
"libraries:");
printed_override = TRUE;
}
trace_merged_symbol(merged_symbol);
printf("%s(%s) definition of %s\n",
p->definition_obj->file_name,
p->strings +
p->mods[toc->module_index].module_name,
merged_symbol->nlist.n_un.n_name);
prebinding = FALSE;
}
}
if(twolevel_namespace_check == TRUE){
if(is_dylib_module_loaded(p->mods + toc->module_index)
== TRUE)
continue;
if(printed_unused == FALSE){
if(multiply_defined_unused_flag ==
MULTIPLY_DEFINED_ERROR)
error("unused multiple definitions of symbol "
"%s", merged_symbol->nlist.n_un.n_name);
else
warning("unused multiple definitions of symbol "
"%s", merged_symbol->nlist.n_un.n_name);
printed_unused = TRUE;
}
if(merged_symbol_printed == FALSE){
trace_merged_symbol(merged_symbol);
merged_symbol_printed = TRUE;
}
printf("%s(%s) unused definition of %s\n",
p->definition_obj->file_name,
p->strings +
p->mods[toc->module_index].module_name,
merged_symbol->nlist.n_un.n_name);
}
}
}
}
}
static
enum bool
check_dylibs_for_reference(
struct merged_symbol *merged_symbol)
{
struct dynamic_library *p;
struct dylib_table_of_contents *toc;
struct nlist *symbol;
struct dylib_reference *dylib_references;
unsigned long i, symbol_index;
struct mach_header *mh;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB){
mh = (struct mach_header *)(p->definition_obj->obj_addr);
if(force_flat_namespace == FALSE &&
(mh->flags & MH_TWOLEVEL) == MH_TWOLEVEL)
continue;
bsearch_strings = p->strings;
bsearch_symbols = p->symbols;
toc = bsearch(merged_symbol->nlist.n_un.n_name,
p->tocs, p->definition_obj->dysymtab->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))
dylib_bsearch);
if(toc != NULL){
symbol_index = toc->symbol_index;
}
else{
symbol = bsearch(merged_symbol->nlist.n_un.n_name,
bsearch_symbols +
p->definition_obj->dysymtab->iundefsym,
p->definition_obj->dysymtab->nundefsym,
sizeof(struct nlist),
(int (*)(const void *,const void *))nlist_bsearch);
if(symbol == NULL)
continue;
symbol_index = symbol - bsearch_symbols;
}
dylib_references = (struct dylib_reference *)
(p->definition_obj->obj_addr +
p->definition_obj->dysymtab->extrefsymoff);
for(i = 0; i < p->definition_obj->dysymtab->nextrefsyms; i++){
if(dylib_references[i].isym == symbol_index &&
(dylib_references[i].flags ==
REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
dylib_references[i].flags ==
REFERENCE_FLAG_UNDEFINED_LAZY))
return(TRUE);
}
}
}
return(FALSE);
}
static
enum bool
open_dylib(
struct dynamic_library *p)
{
unsigned long i, file_size;
char *colon, *file_name, *dylib_name, *file_addr;
int fd;
struct stat stat_buf;
kern_return_t r;
struct fat_header *fat_header;
struct mach_header *mh;
struct load_command *lc;
struct dylib_command *dl;
for(i = 0; i < ndylib_files; i++){
colon = strchr(dylib_files[i], ':');
*colon = '\0';
if(strcmp(p->dylib_name, dylib_files[i]) == 0){
p->dylib_file = dylib_files[i];
p->file_name = colon + 1;
*colon = ':';
break;
}
*colon = ':';
}
#if 0
if(p->dylib_file == NULL &&
(undefined_flag != UNDEFINED_SUPPRESS ||
prebinding == TRUE)){
if(p->definition_obj->ar_hdr != NULL)
warning("using file: %s for reference to dynamic shared library"
" from: %s(%.*s) because no -dylib_file specified",
p->dylib_name, p->definition_obj->file_name,
(int)p->definition_obj->ar_name_size,
p->definition_obj->ar_name);
else
warning("using file: %s for reference to dynamic shared library"
" from: %s because no -dylib_file specified",
p->dylib_name, p->definition_obj->file_name);
}
#endif
if(p->dylib_file != NULL)
file_name = p->file_name;
else{
if(executable_path != NULL &&
strncmp(p->dylib_name, "@executable_path",
sizeof("@executable_path") - 1) == 0){
file_name = mkstr(executable_path,
p->dylib_name + sizeof("@executable_path") -1,
NULL);
}
else{
file_name = p->dylib_name;
}
}
if((fd = open(file_name, O_RDONLY, 0)) == -1){
if(undefined_flag != UNDEFINED_SUPPRESS){
system_warning("can't open dynamic library: %s referenced "
"from: %s (checking for undefined symbols may be affected)",
file_name, p->definition_obj->file_name);
}
return(FALSE);
}
if(fstat(fd, &stat_buf) == -1){
system_error("can't stat dynamic library file: %s", file_name);
close(fd);
return(FALSE);
}
file_size = stat_buf.st_size;
if(file_size == 0){
error("file: %s is empty (not a dynamic library)", file_name);
close(fd);
return(FALSE);
}
if((r = map_fd((int)fd, (vm_offset_t)0, (vm_offset_t *)&file_addr,
(boolean_t)TRUE, (vm_size_t)file_size)) != KERN_SUCCESS){
close(fd);
mach_fatal(r, "can't map dynamic library file: %s", file_name);
}
close(fd);
cur_obj = NULL;
if(sizeof(struct fat_header) > file_size){
error("truncated or malformed dynamic library file: %s (file size "
"too small to be a dynamic library)", file_name);
return(FALSE);
}
fat_header = (struct fat_header *)file_addr;
#ifdef __BIG_ENDIAN__
if(fat_header->magic == FAT_MAGIC)
#endif
#ifdef __LITTLE_ENDIAN__
if(fat_header->magic == SWAP_LONG(FAT_MAGIC))
#endif
{
pass1_fat(file_name, file_addr, file_size, FALSE, TRUE, FALSE,
FALSE);
}
else{
pass1_object(file_name, file_addr, file_size, FALSE, FALSE, TRUE,
FALSE, FALSE);
}
if(errors)
return(FALSE);
if(cur_obj == NULL || cur_obj->dylib == FALSE)
return(FALSE);
dylib_name = NULL;
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){
dl = (struct dylib_command *)lc;
dylib_name = (char *)dl + dl->dylib.name.offset;
#ifdef notdef
if(strcmp(p->dylib_name, dylib_name) != 0){
error("wrong dynamic library: %s (the name in the "
"LC_ID_DYLIB command (%s) is not %s)", file_name,
dylib_name, p->dylib_name);
}
#endif
p->dl = dl;
p->definition_obj = cur_obj;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
return(TRUE);
}
static
enum bool
set_sub_frameworks_ordinals(
struct dynamic_library *umbrella)
{
enum bool set_some_ordinals;
struct dynamic_library *p;
unsigned long i;
struct mach_header *mh;
struct load_command *lc;
struct sub_framework_command *sub;
set_some_ordinals = FALSE;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type != DYLIB)
continue;
if(p->definition_obj->library_ordinal == 0){
mh = (struct mach_header *)p->definition_obj->obj_addr;
lc = (struct load_command *)
((char *)p->definition_obj->obj_addr +
sizeof(struct mach_header));
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_SUB_FRAMEWORK){
sub = (struct sub_framework_command *)lc;
if(strcmp((char *)sub + sub->umbrella.offset,
umbrella->umbrella_name) == 0){
p->definition_obj->library_ordinal =
umbrella->definition_obj->library_ordinal;
set_isub_image(p, p);
set_some_ordinals = TRUE;
break;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
return(set_some_ordinals);
}
static
enum bool
set_sub_umbrella_sub_library_ordinal(
struct dynamic_library *sub)
{
struct dynamic_library *p;
unsigned long i;
struct mach_header *mh;
struct load_command *lc;
struct sub_umbrella_command *usub;
struct sub_library_command *lsub;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type != DYLIB)
continue;
if(p->definition_obj->library_ordinal != 0){
mh = (struct mach_header *)p->definition_obj->obj_addr;
lc = (struct load_command *)
((char *)p->definition_obj->obj_addr +
sizeof(struct mach_header));
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_SUB_UMBRELLA){
usub = (struct sub_umbrella_command *)lc;
if(sub->umbrella_name != NULL &&
strcmp((char *)usub + usub->sub_umbrella.offset,
sub->umbrella_name) == 0){
sub->definition_obj->library_ordinal =
p->definition_obj->library_ordinal;
set_isub_image(p, sub);
return(TRUE);
}
}
else if(lc->cmd == LC_SUB_LIBRARY){
lsub = (struct sub_library_command *)lc;
if(sub->library_name != NULL &&
strcmp((char *)lsub + lsub->sub_library.offset,
sub->library_name) == 0){
sub->definition_obj->library_ordinal =
p->definition_obj->library_ordinal;
set_isub_image(p, sub);
return(TRUE);
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
return(FALSE);
}
static
void
set_isub_image(
struct dynamic_library *p,
struct dynamic_library *sub)
{
struct dynamic_library *q;
unsigned long j;
for(q = dynamic_libs; q != NULL; q = q->next){
if(q->type != DYLIB)
continue;
if(q->definition_obj->library_ordinal ==
p->definition_obj->library_ordinal){
for(j = 0; j < q->nsub_images; j++){
if(q->sub_images[j] == sub){
sub->definition_obj->isub_image = j + 1;
return;
}
}
}
}
}
__private_extern__
struct dynamic_library *
add_dynamic_lib(
enum library_type type,
struct dylib_command *dl,
struct object_file *definition_obj)
{
struct dynamic_library *p, *q;
char *dylib_name;
dylib_name = NULL;
if(type == DYLIB){
dylib_name = (char *)dl + dl->dylib.name.offset;
for(p = dynamic_libs; p != NULL; p = p->next){
if(p->type == DYLIB &&
strcmp(p->dylib_name, dylib_name) == 0){
if(p->dl->cmd == LC_ID_DYLIB){
if(dl->cmd == LC_ID_DYLIB){
if(dl->dylib.compatibility_version >
p->dl->dylib.compatibility_version){
p->dylib_name = dylib_name;
p->dl = dl;
p->definition_obj = definition_obj;
}
}
}
else{
if(dl->cmd == LC_ID_DYLIB){
p->dylib_name = dylib_name;
p->dl = dl;
p->definition_obj = definition_obj;
}
}
return(p);
}
}
}
p = allocate(sizeof(struct dynamic_library));
memset(p, '\0', sizeof(struct dynamic_library));
if(dynamic_libs == NULL)
dynamic_libs = p;
else{
for(q = dynamic_libs; q->next != NULL; q = q->next)
;
q->next = p;
}
if(type == DYLIB){
p->type = DYLIB;
p->dylib_name = dylib_name;
p->dl = dl;
p->definition_obj = definition_obj;
if(next_root != NULL && *dylib_name == '/'){
p->file_name = allocate(strlen(next_root) +
strlen(dylib_name) + 1);
strcpy(p->file_name, next_root);
strcat(p->file_name, dylib_name);
p->dylib_file = p->dylib_name;
}
}
if(type == BUNDLE_LOADER){
p->type = BUNDLE_LOADER;
p->dylib_name = NULL;
p->dl = NULL;
p->definition_obj = definition_obj;
}
return(p);
}
__private_extern__
int
dylib_bsearch(
const char *symbol_name,
const struct dylib_table_of_contents *toc)
{
return(strcmp(symbol_name,
bsearch_strings +
bsearch_symbols[toc->symbol_index].n_un.n_strx));
}
static
int
nlist_bsearch(
const char *symbol_name,
const struct nlist *symbol)
{
return(strcmp(symbol_name, bsearch_strings + symbol->n_un.n_strx));
}
#endif
static
int
ranlib_bsearch(
const char *symbol_name,
const struct ranlib *ran)
{
return(strcmp(symbol_name, bsearch_strings + ran->ran_un.ran_strx));
}
#endif
__private_extern__
void
merge(
enum bool dylib_only,
enum bool bundle_loader,
enum bool force_weak)
{
unsigned long previous_errors;
previous_errors = errors;
errors = 0;
if(trace){
print_obj_name(cur_obj);
print("\n");
}
check_cur_obj(dylib_only, bundle_loader);
if(errors)
goto merge_return;
if(dylib_only == TRUE)
goto merge_return;
#ifndef RLD
if(bundle_loader){
if(cur_obj->symtab != NULL)
(void)add_dynamic_lib(BUNDLE_LOADER, NULL, cur_obj);
goto merge_return;
}
#endif
if(cur_obj->fvmlib_stuff){
#ifndef RLD
merge_fvmlibs();
if(errors)
goto merge_return;
#else
if(cur_obj != base_obj){
error_with_cur_obj("can't dynamicly load fixed VM shared "
"library");
goto merge_return;
}
#endif
}
if(cur_obj->dylib_stuff){
#ifndef RLD
merge_dylibs(force_weak);
if(errors)
goto merge_return;
if(cur_obj->dylib)
goto merge_return;
if(cur_obj->dylinker)
goto merge_return;
#else
if(cur_obj != base_obj){
error_with_cur_obj("can't used dynamic libraries or dynamic "
"linker with rld based interfaces");
goto merge_return;
}
#endif
}
#ifndef KLD
if(strip_level < STRIP_DEBUG)
read_dwarf_info();
#endif
merge_sections();
if(errors)
goto merge_return;
merge_symbols();
if(errors)
goto merge_return;
merge_return:
errors += previous_errors;
}
static
void
check_cur_obj(
enum bool dylib_only,
enum bool bundle_loader)
{
unsigned long i, j, section_type;
uint32_t magic;
struct mach_header *mh;
struct mach_header_64 *mh64;
struct load_command l, *lc, *load_commands;
struct segment_command *sg;
struct section *s;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct routines_command *rc;
struct symseg_command *ss;
struct fvmlib_command *fl;
struct dylib_command *dl, *dlid;
struct dylinker_command *dyld, *dyldid;
struct sub_framework_command *sub;
struct sub_umbrella_command *usub;
struct sub_library_command *lsub;
struct sub_client_command *csub;
struct twolevel_hints_command *hints;
struct prebind_cksum_command *cs;
struct uuid_command *uuid;
char *fvmlib_name, *dylib_name, *dylib_id_name, *dylinker_name,
*umbrella_name, *sub_umbrella_name, *sub_library_name,*sub_client_name;
cpu_subtype_t new_cpusubtype;
const char *new_arch, *prev_arch;
const struct arch_flag *family_arch_flag;
uint32_t *indirect_symtab;
struct dylib_table_of_contents *tocs;
struct dylib_module *mods;
struct dylib_reference *refs;
#ifndef RLD
enum bool is_framework, allowable_client;
char *short_name, *has_suffix, *this_client_name;
#endif
static const struct symtab_command empty_symtab = { 0 };
static const struct dysymtab_command empty_dysymtab = { 0 };
#ifdef KLD
memset(&output_uuid_info, '\0', sizeof(struct uuid_info));
#endif
if(sizeof(struct mach_header) > cur_obj->obj_size){
error_with_cur_obj("truncated or malformed object (mach header "
"extends past the end of the file)");
return;
}
magic = *((uint32_t *)cur_obj->obj_addr);
if(magic == MH_MAGIC ||
magic == SWAP_LONG(MH_MAGIC)){
mh = (struct mach_header *)cur_obj->obj_addr;
if(magic == MH_MAGIC){
cur_obj->swapped = FALSE;
}
else{
cur_obj->swapped = TRUE;
swap_mach_header(mh, host_byte_sex);
}
}
else if(cur_obj->obj_size >= sizeof(struct mach_header_64) &&
(magic == MH_MAGIC_64 ||
magic == SWAP_LONG(MH_MAGIC_64))){
mh64 = (struct mach_header_64 *)cur_obj->obj_addr;
if(magic == MH_MAGIC_64){
cur_obj->swapped = FALSE;
}
else{
cur_obj->swapped = TRUE;
swap_mach_header_64(mh64, host_byte_sex);
}
if(!arch_flag.cputype) {
family_arch_flag = get_arch_family_from_cputype(mh64->cputype);
if(family_arch_flag == NULL){
error_with_cur_obj("cputype (%d) unknown (file not loaded)",
mh64->cputype);
return;
}
arch_flag.cputype = mh64->cputype;
if(force_cpusubtype_ALL == TRUE)
arch_flag.cpusubtype = family_arch_flag->cpusubtype;
else
arch_flag.cpusubtype = mh64->cpusubtype;
}
return;
}
else{
if(no_arch_warnings != TRUE)
error_with_cur_obj("bad magic number (not a Mach-O file)");
return;
}
if(mh->cputype != 0){
if(target_byte_sex == UNKNOWN_BYTE_SEX){
if(cur_obj->swapped == TRUE)
target_byte_sex = host_byte_sex == BIG_ENDIAN_BYTE_SEX ?
LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX;
else
target_byte_sex = host_byte_sex;
}
if(force_cpusubtype_ALL_for_cputype(mh->cputype) == TRUE)
force_cpusubtype_ALL = TRUE;
if(arch_flag.cputype){
if(arch_flag.cputype != mh->cputype){
new_arch = get_arch_name_from_types(mh->cputype,
mh->cpusubtype);
prev_arch = get_arch_name_from_types(arch_flag.cputype,
arch_flag.cpusubtype);
if(no_arch_warnings == TRUE)
return;
if(arch_flag.name != NULL){
if(arch_errors_fatal == TRUE){
error_with_cur_obj("cputype (%d, architecture %s) "
"does not match cputype (%d) for specified "
"-arch flag: %s", mh->cputype, new_arch,
arch_flag.cputype, arch_flag.name);
}
else
warning_with_cur_obj("cputype (%d, architecture %s)"
" does not match cputype (%d) for specified "
"-arch flag: %s (file not loaded)", mh->cputype,
new_arch, arch_flag.cputype, arch_flag.name);
}
else{
if(arch_errors_fatal == TRUE){
error_with_cur_obj("cputype (%d, architecture %s) "
"does not match cputype (%d architecture %s) "
"of objects files previously loaded",
mh->cputype, new_arch, arch_flag.cputype,
prev_arch);
}
else
warning_with_cur_obj("cputype (%d, architecture %s)"
" does not match cputype (%d architecture %s) "
"of objects files previously loaded (file not "
"loaded)", mh->cputype, new_arch,
arch_flag.cputype,prev_arch);
}
return;
}
if(force_cpusubtype_ALL == FALSE){
new_cpusubtype = cpusubtype_combine(arch_flag.cputype,
arch_flag.cpusubtype, mh->cpusubtype);
if(new_cpusubtype == -1){
new_arch = get_arch_name_from_types(mh->cputype,
mh->cpusubtype);
prev_arch = get_arch_name_from_types(arch_flag.cputype,
arch_flag.cpusubtype);
if(no_arch_warnings == TRUE)
return;
if(arch_flag.name != NULL){
if(arch_errors_fatal == TRUE){
error_with_cur_obj("cpusubtype (%d, "
"architecture %s) does not combine with "
"cpusubtype (%d) for specified -arch flag: "
"%s and -force_cpusubtype_ALL not "
"specified", mh->cpusubtype, new_arch,
arch_flag.cpusubtype, arch_flag.name);
}
else
warning_with_cur_obj("cpusubtype (%d, "
"architecture %s) does not combine with "
"cpusubtype (%d) for specified -arch flag: "
"%s and -force_cpusubtype_ALL not specified"
" (file not loaded)", mh->cpusubtype,
new_arch, arch_flag.cpusubtype,
arch_flag.name);
}
else{
if(arch_errors_fatal == TRUE){
error_with_cur_obj("cpusubtype (%d, "
"architecture %s) does not combine with "
"cpusubtype (%d, architecture %s) of "
"objects files previously loaded and "
"-force_cpusubtype_ALL not specified",
mh->cpusubtype, new_arch,
arch_flag.cpusubtype, prev_arch);
}
else
warning_with_cur_obj("cpusubtype (%d, "
"architecture %s) does not combine with "
"cpusubtype (%d, architecture %s) of "
"objects files previously loaded and "
"-force_cpusubtype_ALL not specified (file "
"not loaded)", mh->cpusubtype, new_arch,
arch_flag.cpusubtype, prev_arch);
}
return;
}
else{
if(specific_arch_flag == TRUE){
if(arch_flag.cpusubtype != new_cpusubtype){
new_arch = get_arch_name_from_types(mh->cputype,
mh->cpusubtype);
warning_with_cur_obj("cpusubtype (%d, "
"architecture %s) does not combine with "
"cpusubtype (%d) for specified -arch flag: %s "
"and -force_cpusubtype_ALL not specified (file "
"not loaded)", mh->cpusubtype, new_arch,
arch_flag.cpusubtype, arch_flag.name);
}
}
else if(mh->filetype != MH_DYLIB &&
bundle_loader == FALSE)
arch_flag.cpusubtype = new_cpusubtype;
}
}
else{
family_arch_flag =get_arch_family_from_cputype(mh->cputype);
if(family_arch_flag != NULL)
arch_flag.cpusubtype = family_arch_flag->cpusubtype;
else{
warning_with_cur_obj("cputype (%d) unknown (file not "
"loaded)", mh->cputype);
return;
}
}
}
else{
family_arch_flag = get_arch_family_from_cputype(mh->cputype);
if(family_arch_flag == NULL){
error_with_cur_obj("cputype (%d) unknown (file not loaded)",
mh->cputype);
return;
}
arch_flag.cputype = mh->cputype;
if(force_cpusubtype_ALL == TRUE)
arch_flag.cpusubtype = family_arch_flag->cpusubtype;
else
arch_flag.cpusubtype = mh->cpusubtype;
if(target_byte_sex != get_byte_sex_from_flag(family_arch_flag))
error_with_cur_obj("wrong bytesex for cputype (%d) for "
"-arch %s (bad object or this program out of sync with "
"get_arch_family_from_cputype() and get_byte_sex_"
"from_flag())", arch_flag.cputype,
family_arch_flag->name);
#if !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
if(macosx_deployment_target.major == 0)
get_macosx_deployment_target(&macosx_deployment_target);
#endif
}
}
if(mh->sizeofcmds + sizeof(struct mach_header) > cur_obj->obj_size){
error_with_cur_obj("truncated or malformed object (load commands "
"extend past the end of the file)");
return;
}
if((mh->flags & MH_INCRLINK) != 0){
error_with_cur_obj("was the output of an incremental link, can't "
"be link edited again");
return;
}
if((mh->flags & MH_DYLDLINK) != 0 &&
(mh->filetype != MH_DYLIB &&
mh->filetype != MH_DYLIB_STUB &&
mh->filetype != MH_DYLINKER) &&
bundle_loader == FALSE){
error_with_cur_obj("is input for the dynamic link editor, is not "
"relocatable by the static link editor again");
return;
}
cur_obj->dylib = (enum bool)(mh->filetype == MH_DYLIB ||
mh->filetype == MH_DYLIB_STUB);
dlid = NULL;
dylib_id_name = NULL;
if(cur_obj->dylib == TRUE && dynamic == FALSE){
error_with_cur_obj("incompatible, file is a dynamic shared library "
"(must specify \"-dynamic\" to be used)");
return;
}
if(dylib_only == TRUE && cur_obj->dylib == FALSE){
error_with_cur_obj("file is not a dynamic shared library");
return;
}
cur_obj->dylinker = (enum bool)(mh->filetype == MH_DYLINKER);
dyldid = NULL;
if(cur_obj->dylinker == TRUE && dynamic == FALSE){
error_with_cur_obj("incompatible, file is a dynamic link editor "
"(must specify \"-dynamic\" to be used)");
return;
}
load_commands = (struct load_command *)((char *)cur_obj->obj_addr +
sizeof(struct mach_header));
st = NULL;
dyst = NULL;
rc = NULL;
sub = NULL;
umbrella_name = NULL;
lc = load_commands;
for(i = 0; i < mh->ncmds; i++){
l = *lc;
if(cur_obj->swapped)
swap_load_command(&l, host_byte_sex);
if(l.cmdsize % sizeof(long) != 0){
error_with_cur_obj("load command %lu size not a multiple of "
"sizeof(long)", i);
return;
}
if(l.cmdsize <= 0){
error_with_cur_obj("load command %lu size is less than or equal"
" to zero", i);
return;
}
if((char *)lc + l.cmdsize >
(char *)load_commands + mh->sizeofcmds){
error_with_cur_obj("load command %lu extends past end of all "
"load commands", i);
return;
}
switch(l.cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
if(cur_obj->swapped)
swap_segment_command(sg, host_byte_sex);
if(sg->cmdsize != sizeof(struct segment_command) +
sg->nsects * sizeof(struct section)){
error_with_cur_obj("cmdsize field of load command %lu is "
"inconsistant for a segment command "
"with the number of sections it has", i);
return;
}
if(sg->flags == SG_FVMLIB){
if(sg->nsects != 0){
error_with_cur_obj("SG_FVMLIB segment %.16s contains "
"sections and shouldn't",
sg->segname);
return;
}
cur_obj->fvmlib_stuff = TRUE;
break;
}
check_size_offset(sg->filesize, sg->fileoff, sizeof(long),
"filesize", "fileoff", i);
if(errors)
return;
if(sg->nsects == 0){
if(strcmp(sg->segname, SEG_PAGEZERO) != 0 &&
strcmp(sg->segname, SEG_LINKEDIT) != 0 &&
strcmp(sg->segname, SEG_UNIXSTACK) != 0){
error_with_cur_obj("segment %.16s contains no "
"sections and can't be link-edited",
sg->segname);
return;
}
}
else{
cur_obj->section_maps = reallocate(cur_obj->section_maps,
(cur_obj->nsection_maps + sg->nsects) *
sizeof(struct section_map));
memset(cur_obj->section_maps + cur_obj->nsection_maps, '\0',
sg->nsects * sizeof(struct section_map));
}
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
if(cur_obj->swapped)
swap_section(s, sg->nsects, host_byte_sex);
for(j = 0 ; j < sg->nsects ; j++){
cur_obj->section_maps[cur_obj->nsection_maps++].s = s;
if(mh->filetype != MH_OBJECT &&
strcmp(sg->segname, s->segname) != 0){
error_with_cur_obj("segment name %.16s of section %lu "
"(%.16s,%.16s) in load command %lu does not "
"match segment name %.16s", s->segname, j,
s->segname, s->sectname, i, sg->segname);
return;
}
section_type = s->flags & SECTION_TYPE;
if(section_type != S_REGULAR &&
section_type != S_ZEROFILL &&
section_type != S_CSTRING_LITERALS &&
section_type != S_4BYTE_LITERALS &&
section_type != S_8BYTE_LITERALS &&
section_type != S_LITERAL_POINTERS &&
section_type != S_NON_LAZY_SYMBOL_POINTERS &&
section_type != S_LAZY_SYMBOL_POINTERS &&
section_type != S_SYMBOL_STUBS &&
section_type != S_COALESCED &&
section_type != S_MOD_INIT_FUNC_POINTERS &&
section_type != S_MOD_TERM_FUNC_POINTERS &&
section_type != S_DTRACE_DOF){
error_with_cur_obj("unknown flags (type) of section %lu"
" (%.16s,%.16s) in load command %lu",
j, s->segname, s->sectname, i);
return;
}
if((s->flags & S_ATTR_DEBUG) == S_ATTR_DEBUG &&
section_type != S_REGULAR){
error_with_cur_obj("malformed object, debug section %lu"
" (%.16s,%.16s) in load command %lu is not of type "
"S_REGULAR\n", j, s->segname, s->sectname, i);
return;
}
if(dynamic == FALSE){
if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_SYMBOL_STUBS ||
section_type == S_MOD_INIT_FUNC_POINTERS ||
section_type == S_MOD_TERM_FUNC_POINTERS){
error_with_cur_obj("incompatible, file contains "
"unsupported type of section %lu (%.16s,%.16s) "
"in load command %lu (must specify "
"\"-dynamic\" to be used)", j, s->segname,
s->sectname, i);
return;
}
}
#if defined(SA_RLD) || (defined(KLD) && defined(__STATIC__))
if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_SYMBOL_STUBS ||
section_type == S_MOD_INIT_FUNC_POINTERS ||
section_type == S_MOD_TERM_FUNC_POINTERS){
error_with_cur_obj("unsupported type of section %lu "
"(%.16s,%.16s) for %s in load command %lu", j,
s->segname, s->sectname, progname, i);
return;
}
#endif
if(s->align > MAXSECTALIGN){
error_with_cur_obj("align (%u) of section %lu "
"(%.16s,%.16s) in load command %lu greater "
"than maximum section alignment (%d)", s->align,
j, s->segname, s->sectname, i, MAXSECTALIGN);
return;
}
if(mh->filetype != MH_DYLIB_STUB &&
section_type != S_ZEROFILL){
check_size_offset_sect(s->size, s->offset, sizeof(char),
"size", "offset", i, j, s->segname, s->sectname);
if(errors)
return;
}
if(section_type == S_ZEROFILL ||
section_type == S_CSTRING_LITERALS ||
section_type == S_4BYTE_LITERALS ||
section_type == S_8BYTE_LITERALS ||
section_type == S_NON_LAZY_SYMBOL_POINTERS){
if(s->nreloc != 0){
error_with_cur_obj("section %lu (%.16s,%.16s) in "
"load command %lu has relocation entries which "
"it shouldn't for its type (flags)", j,
s->segname, s->sectname, i);
return;
}
}
else{
if(s->nreloc != 0){
if(mh->cputype == 0 && mh->cpusubtype == 0){
error_with_cur_obj("section %lu (%.16s,%.16s)"
"in load command %lu has relocation entries"
" but the cputype and cpusubtype for the "
"object are not set", j, s->segname,
s->sectname, i);
return;
}
}
else{
check_size_offset_sect(s->nreloc * sizeof(struct
relocation_info), s->reloff, sizeof(long),
"nreloc * sizeof(struct relocation_info)",
"reloff", i, j, s->segname, s->sectname);
if(errors)
return;
}
}
if(section_type == S_SYMBOL_STUBS && s->reserved2 == 0){
error_with_cur_obj("symbol stub section %lu "
"(%.16s,%.16s) in load command %lu, sizeof stub in "
"reserved2 field is zero", j, s->segname,
s->sectname, i);
return;
}
s++;
}
break;
case LC_SYMTAB:
if(st != NULL){
error_with_cur_obj("contains more than one LC_SYMTAB load "
"command");
return;
}
st = (struct symtab_command *)lc;
if(cur_obj->swapped)
swap_symtab_command(st, host_byte_sex);
if(st->cmdsize != sizeof(struct symtab_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_SYMTAB", i);
return;
}
check_size_offset(st->nsyms * sizeof(struct nlist), st->symoff,
sizeof(long), "nsyms * sizeof(struct nlist)",
"symoff", i);
if(errors)
return;
check_size_offset(st->strsize, st->stroff, sizeof(long),
"strsize", "stroff", i);
if(errors)
return;
cur_obj->symtab = st;
break;
case LC_DYSYMTAB:
if(dyst != NULL){
error_with_cur_obj("contains more than one LC_DYSYMTAB "
"load command");
return;
}
dyst = (struct dysymtab_command *)lc;
if(cur_obj->swapped)
swap_dysymtab_command(dyst, host_byte_sex);
if(dyst->cmdsize != sizeof(struct dysymtab_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_DYSYMTAB", i);
return;
}
check_size_offset(dyst->ntoc *
sizeof(struct dylib_table_of_contents),
dyst->tocoff, sizeof(long),
"ntoc * sizeof(struct dylib_table_of_contents)",
"tocoff", i);
if(dyst->ntoc == 0 && cur_obj->dylib == TRUE &&
dyst->nextdefsym != 0)
warning_with_cur_obj("shared library has no table of "
"contents entries (can't resolve "
"symbols from it)");
if(errors)
return;
check_size_offset(dyst->nmodtab * sizeof(struct dylib_module),
dyst->modtaboff, sizeof(long),
"nmodtab * sizeof(struct dylib_module)",
"modtaboff", i);
if(errors)
return;
check_size_offset(dyst->nextrefsyms *
sizeof(struct dylib_reference),
dyst->extrefsymoff, sizeof(long),
"nextrefsyms * sizeof(struct dylib_reference)",
"extrefsymoff", i);
if(errors)
return;
check_size_offset(dyst->nindirectsyms * sizeof(long),
dyst->indirectsymoff, sizeof(long),
"nindirectsyms * sizeof(long)",
"indirectsymoff", i);
if(errors)
return;
check_size_offset(dyst->nextrel *sizeof(struct relocation_info),
dyst->extreloff, sizeof(long),
"nextrel * sizeof(struct relocation_info)",
"extreloff", i);
if(errors)
return;
check_size_offset(dyst->nlocrel *sizeof(struct relocation_info),
dyst->locreloff, sizeof(long),
"nlocrel * sizeof(struct relocation_info)",
"locreloff", i);
if(errors)
return;
cur_obj->dysymtab = dyst;
break;
case LC_ROUTINES:
if(rc != NULL){
error_with_cur_obj("contains more than one LC_ROUTINES "
"load command");
return;
}
rc = (struct routines_command *)lc;
if(cur_obj->swapped)
swap_routines_command(rc, host_byte_sex);
if(rc->cmdsize != sizeof(struct routines_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_ROUTINES", i);
return;
}
if(errors)
return;
cur_obj->rc = rc;
break;
case LC_SYMSEG:
ss = (struct symseg_command *)lc;
if(cur_obj->swapped)
swap_symseg_command(ss, host_byte_sex);
if(ss->size != 0){
warning_with_cur_obj("contains obsolete LC_SYMSEG load "
"command with non-zero size (produced with a pre-1.0 "
"version of the compiler, please recompile)");
}
break;
case LC_IDFVMLIB:
if(filetype != MH_FVMLIB){
error_with_cur_obj("LC_IDFVMLIB load command in object "
"file (should not be in an input file to the link "
"editor for output filetypes other than MH_FVMLIB)");
return;
}
cur_obj->fvmlib_stuff = TRUE;
fl = (struct fvmlib_command *)lc;
if(cur_obj->swapped)
swap_fvmlib_command(fl, host_byte_sex);
break;
case LC_LOADFVMLIB:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_LOADFVMLIB load command in object "
"file (should not be in an input file to the link "
"editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" :
(filetype == MH_DYLIB ? "MH_DYLIB" : "MH_DYLINKER"));
return;
}
fl = (struct fvmlib_command *)lc;
if(cur_obj->swapped)
swap_fvmlib_command(fl, host_byte_sex);
if(fl->cmdsize < sizeof(struct fvmlib_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_LOADFVMLIB", i);
return;
}
if(fl->fvmlib.name.offset >= fl->cmdsize){
error_with_cur_obj("name.offset of load command %lu extends"
" past the end of the load command", i);
return;
}
fvmlib_name = (char *)fl + fl->fvmlib.name.offset;
for(j = 0 ; j < fl->cmdsize - fl->fvmlib.name.offset; j++){
if(fvmlib_name[j] == '\0')
break;
}
if(j >= fl->cmdsize - fl->fvmlib.name.offset){
error_with_cur_obj("library name of load command %lu "
"not null terminated", i);
return;
}
cur_obj->fvmlib_stuff = TRUE;
break;
case LC_ID_DYLIB:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_ID_DYLIB load command in object "
"file (should not be in an input file to the link "
"editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" : "MH_DYLINKER");
return;
}
if(mh->filetype != MH_DYLIB && mh->filetype != MH_DYLIB_STUB){
error_with_cur_obj("LC_ID_DYLIB load command in non-"
"%s filetype", mh->filetype == MH_DYLIB ? "MH_DYLIB" :
"MH_DYLIB_STUB");
return;
}
if(dlid != NULL){
error_with_cur_obj("malformed object (more than one "
"LC_ID_DYLIB load command in %s file)", mh->filetype ==
MH_DYLIB ? "MH_DYLIB" : "MH_DYLIB_STUB");
return;
}
dl = (struct dylib_command *)lc;
dlid = dl;
if(cur_obj->swapped)
swap_dylib_command(dl, host_byte_sex);
if(dl->cmdsize < sizeof(struct dylib_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_ID_DYLIB", i);
return;
}
if(dl->dylib.name.offset >= dl->cmdsize){
error_with_cur_obj("name.offset of load command %lu extends"
" past the end of the load command", i);
return;
}
dylib_id_name = (char *)dl + dl->dylib.name.offset;
for(j = 0 ; j < dl->cmdsize - dl->dylib.name.offset; j++){
if(dylib_id_name[j] == '\0')
break;
}
if(j >= dl->cmdsize - dl->dylib.name.offset){
error_with_cur_obj("library name of load command %lu "
"not null terminated", i);
return;
}
cur_obj->dylib_stuff = TRUE;
break;
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("%s load command in object "
"file (should not be in an input file to the link "
"editor for the output file type %s)",
l.cmd == LC_LOAD_DYLIB ? "LC_LOAD_DYLIB" :
"LC_LOAD_WEAK_DYLIB",
filetype == MH_FVMLIB ? "MH_FVMLIB" : "MH_DYLINKER");
return;
}
dl = (struct dylib_command *)lc;
if(cur_obj->swapped)
swap_dylib_command(dl, host_byte_sex);
if(dl->cmdsize < sizeof(struct dylib_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for %s", i, l.cmd == LC_LOAD_DYLIB ? "LC_LOAD_DYLIB" :
"LC_LOAD_WEAK_DYLIB");
return;
}
if(dl->dylib.name.offset >= dl->cmdsize){
error_with_cur_obj("name.offset of load command %lu extends"
" past the end of the load command", i);
return;
}
dylib_name = (char *)dl + dl->dylib.name.offset;
for(j = 0 ; j < dl->cmdsize - dl->dylib.name.offset; j++){
if(dylib_name[j] == '\0')
break;
}
if(j >= dl->cmdsize - dl->dylib.name.offset){
error_with_cur_obj("library name of load command %lu "
"not null terminated", i);
return;
}
cur_obj->dylib_stuff = TRUE;
cur_obj->nload_dylibs++;
break;
case LC_SUB_FRAMEWORK:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_SUB_FRAMEWORK load command in "
"object file (should not be in an input file to the "
"link editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" : "MH_DYLINKER");
return;
}
if(mh->filetype != MH_DYLIB && mh->filetype != MH_DYLIB_STUB){
error_with_cur_obj("LC_SUB_FRAMEWORK load command in non-"
"%s filetype", mh->filetype == MH_DYLIB ? "MH_DYLIB" :
"MH_DYLIB_STUB");
return;
}
if(sub != NULL){
error_with_cur_obj("malformed object (more than one "
"LC_SUB_FRAMEWORK load command in %s file)",
mh->filetype == MH_DYLIB ? "MH_DYLIB" :
"MH_DYLIB_STUB");
return;
}
sub = (struct sub_framework_command *)lc;
if(cur_obj->swapped)
swap_sub_framework_command(sub, host_byte_sex);
if(sub->cmdsize < sizeof(struct sub_framework_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_SUB_FRAMEWORK", i);
return;
}
if(sub->umbrella.offset >= sub->cmdsize){
error_with_cur_obj("umbrella.offset of load command %lu "
"extends past the end of the load command", i);
return;
}
umbrella_name = (char *)sub + sub->umbrella.offset;
for(j = 0 ; j < sub->cmdsize - sub->umbrella.offset; j++){
if(umbrella_name[j] == '\0')
break;
}
if(j >= sub->cmdsize - sub->umbrella.offset){
error_with_cur_obj("umbrella name of load command %lu "
"not null terminated", i);
return;
}
break;
case LC_SUB_UMBRELLA:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_SUB_UMBRELLA load command in "
"object file (should not be in an input file to the "
"link editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" : "MH_DYLINKER");
return;
}
if(mh->filetype != MH_DYLIB && mh->filetype != MH_DYLIB_STUB){
error_with_cur_obj("LC_SUB_UMBRELLA load command in non-"
"%s filetype", mh->filetype == MH_DYLIB ? "MH_DYLIB" :
"MH_DYLIB_STUB");
return;
}
usub = (struct sub_umbrella_command *)lc;
if(cur_obj->swapped)
swap_sub_umbrella_command(usub, host_byte_sex);
if(usub->cmdsize < sizeof(struct sub_umbrella_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_SUB_UMBRELLA", i);
return;
}
if(usub->sub_umbrella.offset >= usub->cmdsize){
error_with_cur_obj("sub_umbrella.offset of load command "
"%lu extends past the end of the load command", i);
return;
}
sub_umbrella_name = (char *)usub + usub->sub_umbrella.offset;
for(j = 0 ; j < usub->cmdsize - usub->sub_umbrella.offset; j++){
if(sub_umbrella_name[j] == '\0')
break;
}
if(j >= usub->cmdsize - usub->sub_umbrella.offset){
error_with_cur_obj("sub_umbrella name of load command %lu "
"not null terminated", i);
return;
}
break;
case LC_SUB_LIBRARY:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_SUB_LIBRARY load command in "
"object file (should not be in an input file to the "
"link editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" : "MH_DYLINKER");
return;
}
if(mh->filetype != MH_DYLIB && mh->filetype != MH_DYLIB_STUB){
error_with_cur_obj("LC_SUB_LIBRARY load command in non-"
"%s filetype", mh->filetype == MH_DYLIB ? "MH_DYLIB" :
"MH_DYLIB_STUB");
return;
}
lsub = (struct sub_library_command *)lc;
if(cur_obj->swapped)
swap_sub_library_command(lsub, host_byte_sex);
if(lsub->cmdsize < sizeof(struct sub_library_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_SUB_LIBRARY", i);
return;
}
if(lsub->sub_library.offset >= lsub->cmdsize){
error_with_cur_obj("sub_library.offset of load command "
"%lu extends past the end of the load command", i);
return;
}
sub_library_name = (char *)lsub + lsub->sub_library.offset;
for(j = 0 ; j < lsub->cmdsize - lsub->sub_library.offset; j++){
if(sub_library_name[j] == '\0')
break;
}
if(j >= lsub->cmdsize - lsub->sub_library.offset){
error_with_cur_obj("sub_library name of load command %lu "
"not null terminated", i);
return;
}
break;
case LC_SUB_CLIENT:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_SUB_CLIENT load command in "
"object file (should not be in an input file to the "
"link editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" : "MH_DYLINKER");
return;
}
if(mh->filetype != MH_DYLIB && mh->filetype != MH_DYLIB_STUB){
error_with_cur_obj("LC_SUB_CLIENT load command in non-"
"%s filetype", mh->filetype == MH_DYLIB ? "MH_DYLIB" :
"MH_DYLIB_STUB");
return;
}
csub = (struct sub_client_command *)lc;
if(cur_obj->swapped)
swap_sub_client_command(csub, host_byte_sex);
if(csub->cmdsize < sizeof(struct sub_client_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_SUB_CLIENT", i);
return;
}
if(csub->client.offset >= csub->cmdsize){
error_with_cur_obj("client.offset of load command %lu "
"extends past the end of the load command", i);
return;
}
sub_client_name = (char *)csub + csub->client.offset;
for(j = 0 ; j < csub->cmdsize - csub->client.offset; j++){
if(sub_client_name[j] == '\0')
break;
}
if(j >= csub->cmdsize - csub->client.offset){
error_with_cur_obj("sub_client name of load command %lu "
"not null terminated", i);
return;
}
break;
case LC_ID_DYLINKER:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_ID_DYLINKER load command in object "
"file (should not be in an input file to the link "
"editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" :
(filetype == MH_DYLIB ? "MH_DYLIB" : "MH_DYLINKER"));
return;
}
if(mh->filetype != MH_DYLINKER){
error_with_cur_obj("LC_ID_DYLINKER load command in non-"
"MH_DYLINKER filetype");
return;
}
if(dyldid != NULL){
error_with_cur_obj("malformed object (more than one "
"LC_ID_DYLINKER load command in MH_DYLINKER file)");
return;
}
dyld = (struct dylinker_command *)lc;
dyldid = dyld;
if(cur_obj->swapped)
swap_dylinker_command(dyld, host_byte_sex);
if(dyld->cmdsize < sizeof(struct dylinker_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_ID_DYLINKER", i);
return;
}
if(dyld->name.offset >= dyld->cmdsize){
error_with_cur_obj("name.offset of load command %lu extends"
" past the end of the load command", i);
return;
}
dylinker_name = (char *)dyld + dyld->name.offset;
for(j = 0 ; j < dyld->cmdsize - dyld->name.offset; j++){
if(dylinker_name[j] == '\0')
break;
}
if(j >= dyld->cmdsize - dyld->name.offset){
error_with_cur_obj("dynamic linker name of load command "
"%lu not null terminated", i);
return;
}
cur_obj->dylib_stuff = TRUE;
break;
case LC_LOAD_DYLINKER:
if(filetype == MH_FVMLIB ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER){
error_with_cur_obj("LC_LOAD_DYLINKER load command in object"
" file (should not be in an input file to the link "
"editor for the output file type %s)",
filetype == MH_FVMLIB ? "MH_FVMLIB" :
(filetype == MH_DYLIB ? "MH_DYLIB" : "MH_DYLINKER"));
return;
}
dyld = (struct dylinker_command *)lc;
if(cur_obj->swapped)
swap_dylinker_command(dyld, host_byte_sex);
if(dyld->cmdsize < sizeof(struct dylinker_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_LOAD_DYLINKER", i);
return;
}
if(dyld->name.offset >= dyld->cmdsize){
error_with_cur_obj("name.offset of load command %lu extends"
" past the end of the load command", i);
return;
}
dylinker_name = (char *)dyld + dyld->name.offset;
for(j = 0 ; j < dyld->cmdsize - dyld->name.offset; j++){
if(dylinker_name[j] == '\0')
break;
}
if(j >= dyld->cmdsize - dyld->name.offset){
error_with_cur_obj("dynamic linker name of load command "
"%lu not null terminated", i);
return;
}
cur_obj->dylib_stuff = TRUE;
break;
case LC_TWOLEVEL_HINTS:
hints = (struct twolevel_hints_command *)lc;
if(cur_obj->swapped)
swap_twolevel_hints_command(hints, host_byte_sex);
if(hints->cmdsize != sizeof(struct twolevel_hints_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_TWOLEVEL_HINTS", i);
return;
}
check_size_offset(hints->nhints * sizeof(struct twolevel_hint),
hints->offset, sizeof(long),
"nhints * sizeof(struct twolevel_hint)",
"offset", i);
if(errors)
return;
break;
case LC_PREBIND_CKSUM:
cs = (struct prebind_cksum_command *)lc;
if(cur_obj->swapped)
swap_prebind_cksum_command(cs, host_byte_sex);
if(cs->cmdsize != sizeof(struct prebind_cksum_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_PREBIND_CKSUM", i);
return;
}
if(errors)
return;
break;
case LC_UUID:
uuid = (struct uuid_command *)lc;
if(cur_obj->swapped)
swap_uuid_command(uuid, host_byte_sex);
if(uuid->cmdsize != sizeof(struct uuid_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_UUID", i);
return;
}
if(errors)
return;
#ifndef KLD
output_uuid_info.emit = TRUE;
#else
output_uuid_info.uuid_command.cmd = LC_UUID;
output_uuid_info.uuid_command.cmdsize =
sizeof(struct uuid_command);
memcpy(&(output_uuid_info.uuid_command.uuid[0]), uuid->uuid,
sizeof(uuid->uuid));
#endif
break;
case LC_UNIXTHREAD:
case LC_THREAD:
case LC_IDENT:
case LC_FVMFILE:
case LC_PREPAGE:
case LC_PREBOUND_DYLIB:
case LC_CODE_SIGNATURE:
case LC_SEGMENT_SPLIT_INFO:
if(cur_obj->swapped)
swap_load_command(lc, host_byte_sex);
break;
default:
error_with_cur_obj("load command %lu unknown cmd field", i);
return;
}
lc = (struct load_command *)((char *)lc + l.cmdsize);
}
if(bundle_loader){
if(cur_obj->dysymtab == NULL){
error_with_cur_obj("bundle loader does not have an LC_DYSYMTAB "
"command");
return;
}
cur_obj->bundle_loader = TRUE;
}
if(cur_obj->symtab == NULL){
if(cur_obj->dysymtab != NULL)
error_with_cur_obj("contains LC_DYSYMTAB load command without "
"a LC_SYMTAB load command");
cur_obj->symtab = (struct symtab_command *)&empty_symtab;
cur_obj->dysymtab = (struct dysymtab_command *)&empty_dysymtab;
}
else{
if(cur_obj->dysymtab == NULL){
cur_obj->dysymtab = (struct dysymtab_command *)&empty_dysymtab;
if(cur_obj->rc != NULL)
error_with_cur_obj("contains LC_ROUTINES load command "
"without a LC_DYSYMTAB load command");
}
else{
if(dyst->nlocalsym != 0 &&
dyst->ilocalsym > st->nsyms)
error_with_cur_obj("ilocalsym in LC_DYSYMTAB load "
"command extends past the end of the symbol table");
if(dyst->nlocalsym != 0 &&
dyst->ilocalsym + dyst->nlocalsym > st->nsyms)
error_with_cur_obj("ilocalsym plus nlocalsym in "
"LC_DYSYMTAB load command extends past the "
"end of the symbol table");
if(dyst->nextdefsym != 0 &&
dyst->iextdefsym > st->nsyms)
error_with_cur_obj("iextdefsym in LC_DYSYMTAB load "
"command extends past the end of the symbol table");
if(dyst->nextdefsym != 0 &&
dyst->iextdefsym + dyst->nextdefsym > st->nsyms)
error_with_cur_obj("iextdefsym plus nextdefsym in "
"LC_DYSYMTAB load command extends past the "
"end of the symbol table");
if(dyst->nundefsym != 0 &&
dyst->iundefsym > st->nsyms)
error_with_cur_obj("iundefsym in LC_DYSYMTAB load "
"command extends past the end of the symbol table");
if(dyst->nundefsym != 0 &&
dyst->iundefsym + dyst->nundefsym > st->nsyms)
error_with_cur_obj("iundefsym plus nundefsym in "
"LC_DYSYMTAB load command extends past the "
"end of the symbol table");
if(dyst->ntoc != 0){
tocs =(struct dylib_table_of_contents *)(cur_obj->obj_addr +
dyst->tocoff);
if(cur_obj->swapped)
swap_dylib_table_of_contents(tocs, dyst->ntoc,
host_byte_sex);
for(i = 0; i < dyst->ntoc; i++){
if(tocs[i].symbol_index > st->nsyms)
error_with_cur_obj("symbol_index field of table of "
"contents entry %lu past the end of the symbol "
"table", i);
if(tocs[i].module_index > dyst->nmodtab)
error_with_cur_obj("module_index field of table of "
"contents entry %lu past the end of the module "
"table", i);
}
}
if(dyst->nmodtab != 0){
mods = (struct dylib_module *)(cur_obj->obj_addr +
dyst->modtaboff);
if(cur_obj->swapped)
swap_dylib_module(mods, dyst->nmodtab, host_byte_sex);
for(i = 0; i < dyst->nmodtab; i++){
if(mods[i].module_name > st->strsize)
error_with_cur_obj("module_name field of module "
"table entry %lu past the end of the string "
"table", i);
if(mods[i].iextdefsym > st->nsyms)
error_with_cur_obj("iextdefsym field of module "
"table entry %lu past the end of the symbol "
"table", i);
if(mods[i].iextdefsym +
mods[i].nextdefsym > st->nsyms)
error_with_cur_obj("iextdefsym field plus "
"nextdefsym field of module table entry %lu "
"past the end of the symbol table", i);
if(mods[i].irefsym > dyst->nextrefsyms)
error_with_cur_obj("irefsym field of module table "
"entry %lu past the end of the reference table",
i);
if(mods[i].irefsym +
mods[i].nrefsym > dyst->nextrefsyms)
error_with_cur_obj("irefsym field plus "
"nrefsym field of module table entry %lu past "
"the end of the reference table", i);
if(mods[i].ilocalsym > st->nsyms)
error_with_cur_obj("ilocalsym field of module "
"table entry %lu past the end of the symbol "
"table", i);
if(mods[i].ilocalsym +
mods[i].nlocalsym > st->nsyms)
error_with_cur_obj("ilocalsym field plus "
"nlocalsym field of module table entry %lu "
"past the end of the symbol table", i);
}
}
if(dyst->nextrefsyms != 0){
refs = (struct dylib_reference *)(cur_obj->obj_addr +
dyst->extrefsymoff);
if(cur_obj->swapped)
swap_dylib_reference(refs, dyst->nextrefsyms,
host_byte_sex);
for(i = 0; i < dyst->nextrefsyms; i++){
if(refs[i].isym > st->nsyms)
error_with_cur_obj("isym field of reference table "
"entry %lu past the end of the symbol table",i);
}
}
if(dyst->nindirectsyms != 0){
indirect_symtab = (uint32_t *)(cur_obj->obj_addr +
dyst->indirectsymoff);
if(cur_obj->swapped)
swap_indirect_symbols(indirect_symtab,
dyst->nindirectsyms, host_byte_sex);
for(i = 0; i < dyst->nindirectsyms; i++){
if(indirect_symtab[i] != INDIRECT_SYMBOL_LOCAL &&
indirect_symtab[i] != INDIRECT_SYMBOL_ABS){
if(indirect_symtab[i] > st->nsyms)
error_with_cur_obj("indirect symbol table entry"
" %lu past the end of the symbol table", i);
}
}
}
if(rc != NULL && rc->init_module > dyst->nmodtab)
error_with_cur_obj("init_module field of LC_ROUTINES load "
"command past the end of the module table");
}
}
if((mh->filetype == MH_DYLIB || mh->filetype == MH_DYLIB_STUB) &&
dlid == NULL){
error_with_cur_obj("malformed object (no LC_ID_DYLIB load command "
"in %s file)", mh->filetype == MH_DYLIB ?
"MH_DYLIB" : "MH_DYLIB_STUB");
return;
}
if(mh->filetype == MH_DYLINKER && dyldid == NULL){
error_with_cur_obj("malformed object (no LC_ID_DYLINKER load "
"command in MH_DYLINKER file)");
return;
}
#ifndef RLD
if(indirect_dylib == FALSE && sub != NULL &&
(umbrella_framework_name == NULL ||
strcmp(umbrella_name, umbrella_framework_name) != 0)){
short_name = guess_short_name(dylib_id_name, &is_framework,
&has_suffix);
if(umbrella_framework_name != NULL)
this_client_name = umbrella_framework_name;
else
this_client_name = client_name;
allowable_client = FALSE;
if(this_client_name != NULL){
lc = load_commands;
for(i = 0; i < mh->ncmds; i++){
if(lc->cmd == LC_SUB_CLIENT){
csub = (struct sub_client_command *)lc;
sub_client_name = (char *)csub + csub->client.offset;
if(strcmp(sub_client_name, this_client_name) == 0){
allowable_client = TRUE;
break;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
if(allowable_client == FALSE){
if(short_name != NULL && is_framework == TRUE)
error_with_cur_obj("'%s.framework' is a subframework. "
"Link against the umbrella framework '%s.framework' "
"instead.", short_name, umbrella_name);
else
error_with_cur_obj("is a subframework. Link against the "
"umbrella framework '%s.framework' instead.",
umbrella_name);
}
}
#endif
}
#ifdef RLD
__private_extern__
void
merge_base_program(
char *basefile_name,
struct mach_header *basefile_addr,
struct segment_command *seg_linkedit,
struct nlist *symtab,
unsigned long nsyms,
char *strtab,
unsigned long strsize)
{
unsigned long i, j, section_type;
struct mach_header *mh;
struct load_command *lc, *load_commands;
struct segment_command *sg;
struct section *s;
struct symtab_command *st;
struct dysymtab_command *dyst;
static const struct symtab_command empty_symtab = { 0 };
static struct symtab_command base_program_symtab = { 0 };
cur_obj = new_object_file();
cur_obj->file_name = basefile_name;
cur_obj->obj_addr = (char *)basefile_addr;
cur_obj->obj_size = 0;
cur_obj->from_fat_file = FALSE;
base_obj = cur_obj;
mh = basefile_addr;
arch_flag.cputype = mh->cputype;
arch_flag.cpusubtype = mh->cpusubtype;
load_commands = (struct load_command *)((char *)cur_obj->obj_addr +
sizeof(struct mach_header));
st = NULL;
dyst = NULL;
lc = load_commands;
for(i = 0; i < mh->ncmds; i++){
if(lc->cmdsize % sizeof(long) != 0){
error_with_cur_obj("load command %lu size not a multiple of "
"sizeof(long)", i);
return;
}
if(lc->cmdsize <= 0){
error_with_cur_obj("load command %lu size is less than or equal"
" to zero", i);
return;
}
if((char *)lc + lc->cmdsize >
(char *)load_commands + mh->sizeofcmds){
error_with_cur_obj("load command %lu extends past end of all "
"load commands", i);
return;
}
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
if(sg->cmdsize != sizeof(struct segment_command) +
sg->nsects * sizeof(struct section)){
error_with_cur_obj("cmdsize field of load command %lu is "
"inconsistant for a segment command "
"with the number of sections it has", i);
return;
}
if(sg->flags == SG_FVMLIB){
if(sg->nsects != 0){
error_with_cur_obj("SG_FVMLIB segment %.16s contains "
"sections and shouldn't",
sg->segname);
return;
}
break;
}
if(sg->nsects == 0){
if(strcmp(sg->segname, SEG_PAGEZERO) != 0 &&
strcmp(sg->segname, SEG_LINKEDIT) != 0){
error_with_cur_obj("segment %.16s contains no "
"sections and can't be link-edited",
sg->segname);
return;
}
}
else{
cur_obj->section_maps = reallocate(cur_obj->section_maps,
(cur_obj->nsection_maps + sg->nsects) *
sizeof(struct section_map));
memset(cur_obj->section_maps + cur_obj->nsection_maps, '\0',
sg->nsects * sizeof(struct section_map));
}
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
cur_obj->section_maps[cur_obj->nsection_maps++].s = s;
if(mh->filetype != MH_OBJECT &&
strcmp(sg->segname, s->segname) != 0){
error_with_cur_obj("segment name %.16s of section %lu "
"(%.16s,%.16s) in load command %lu does not "
"match segment name %.16s", s->segname, j,
s->segname, s->sectname, i, sg->segname);
return;
}
section_type = s->flags & SECTION_TYPE;
if(section_type != S_REGULAR &&
section_type != S_ZEROFILL &&
section_type != S_CSTRING_LITERALS &&
section_type != S_4BYTE_LITERALS &&
section_type != S_8BYTE_LITERALS &&
section_type != S_LITERAL_POINTERS &&
section_type != S_NON_LAZY_SYMBOL_POINTERS &&
section_type != S_LAZY_SYMBOL_POINTERS &&
section_type != S_SYMBOL_STUBS &&
section_type != S_COALESCED &&
section_type != S_MOD_INIT_FUNC_POINTERS &&
section_type != S_MOD_TERM_FUNC_POINTERS &&
section_type != S_DTRACE_DOF){
error_with_cur_obj("unknown flags (type) of section %lu"
" (%.16s,%.16s) in load command %lu",
j, s->segname, s->sectname, i);
return;
}
if(s->align > MAXSECTALIGN){
error_with_cur_obj("align (%u) of section %lu "
"(%.16s,%.16s) in load command %lu greater "
"than maximum section alignment (%d)", s->align,
j, s->segname, s->sectname, i, MAXSECTALIGN);
return;
}
s++;
}
break;
case LC_SYMTAB:
if(st != NULL){
error_with_cur_obj("contains more than one LC_SYMTAB load "
"command");
return;
}
st = (struct symtab_command *)lc;
if(st->cmdsize != sizeof(struct symtab_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_SYMTAB", i);
return;
}
break;
case LC_DYSYMTAB:
if(dyst != NULL){
error_with_cur_obj("contains more than one LC_DYSYMTAB "
"load command");
return;
}
dyst = (struct dysymtab_command *)lc;
if(dyst->cmdsize != sizeof(struct dysymtab_command)){
error_with_cur_obj("cmdsize of load command %lu incorrect "
"for LC_DYSYMTAB", i);
return;
}
break;
case LC_SYMSEG:
case LC_IDFVMLIB:
case LC_LOADFVMLIB:
case LC_ID_DYLIB:
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
case LC_ID_DYLINKER:
case LC_LOAD_DYLINKER:
case LC_UNIXTHREAD:
case LC_THREAD:
case LC_IDENT:
case LC_FVMFILE:
case LC_PREPAGE:
break;
default:
error_with_cur_obj("load command %lu unknown cmd", i);
return;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(seg_linkedit == NULL){
base_program_symtab.cmd = LC_SYMTAB;
base_program_symtab.cmdsize = sizeof(struct symtab_command);
base_program_symtab.symoff = (long)symtab - (long)cur_obj->obj_addr;
base_program_symtab.nsyms = nsyms;
base_program_symtab.stroff = (long)strtab - (long)cur_obj->obj_addr;
base_program_symtab.strsize = strsize;
cur_obj->symtab = &base_program_symtab;
}
else if(st != NULL && st->nsyms != 0){
if(st->symoff < seg_linkedit->fileoff ||
st->symoff + st->nsyms * sizeof(struct nlist) >
seg_linkedit->fileoff + seg_linkedit->filesize){
error_with_cur_obj("symbol table is not contained in "
SEG_LINKEDIT " segment");
return;
}
if(st->stroff < seg_linkedit->fileoff ||
st->stroff + st->strsize >
seg_linkedit->fileoff + seg_linkedit->filesize){
error_with_cur_obj("string table is not contained in "
SEG_LINKEDIT " segment");
return;
}
base_program_symtab = *st;
base_program_symtab.symoff = (seg_linkedit->vmaddr + (st->symoff -
seg_linkedit->fileoff)) -
(long)cur_obj->obj_addr;
base_program_symtab.stroff = (seg_linkedit->vmaddr + (st->stroff -
seg_linkedit->fileoff)) -
(long)cur_obj->obj_addr;
cur_obj->symtab = &base_program_symtab;
}
else{
cur_obj->symtab = (struct symtab_command *)&empty_symtab;
}
merge_sections();
merge_symbols();
}
#endif
static
void
check_size_offset(
unsigned long size,
unsigned long offset,
unsigned long align,
char *size_str,
char *offset_str,
unsigned long cmd)
{
if(size != 0){
if(offset % align != 0){
#ifdef mc68000
warning_with_cur_obj("%s in load command %lu not aligned on %lu"
" byte boundary", offset_str, cmd, align);
#else
error_with_cur_obj("%s in load command %lu not aligned on %lu "
"byte boundary", offset_str, cmd, align);
#endif
return;
}
if(offset > cur_obj->obj_size){
error_with_cur_obj("%s in load command %lu extends past the "
"end of the file", offset_str, cmd);
return;
}
if(offset + size > cur_obj->obj_size){
error_with_cur_obj("%s plus %s in load command %lu extends past"
" the end of the file", offset_str, size_str,
cmd);
return;
}
}
}
static
void
check_size_offset_sect(
unsigned long size,
unsigned long offset,
unsigned long align,
char *size_str,
char *offset_str,
unsigned long cmd,
unsigned long sect,
char *segname,
char *sectname)
{
if(size != 0){
if(offset % align != 0){
#ifdef mc68000
warning_with_cur_obj("%s of section %lu (%.16s,%.16s) in load "
"command %lu not aligned on %lu byte boundary", offset_str,
sect, segname, sectname, cmd, align);
#else
error_with_cur_obj("%s of section %lu (%.16s,%.16s) in load "
"command %lu not aligned on %lu byte boundary", offset_str,
sect, segname, sectname, cmd, align);
#endif
return;
}
if(offset > cur_obj->obj_size){
error_with_cur_obj("%s of section %lu (%.16s,%.16s) in load "
"command %lu extends past the end of the file", offset_str,
sect, segname, sectname, cmd);
return;
}
if(offset + size > cur_obj->obj_size){
error_with_cur_obj("%s plus %s of section %lu (%.16s,%.16s) "
"in load command %lu extends past the end of the file",
offset_str, size_str, sect, segname, sectname, cmd);
return;
}
}
}
#ifndef RLD
static
void
collect_base_obj_segments(void)
{
unsigned long i;
struct mach_header *mh;
struct load_command *lc, *load_commands;
struct segment_command *sg;
mh = (struct mach_header *)base_obj->obj_addr;
load_commands = (struct load_command *)((char *)base_obj->obj_addr +
sizeof(struct mach_header));
lc = load_commands;
for(i = 0; i < mh->ncmds; i++){
switch(lc->cmd){
case LC_SEGMENT:
sg = (struct segment_command *)lc;
add_base_obj_segment(sg, base_obj->file_name);
break;
default:
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
add_base_obj_segment(
struct segment_command *sg,
char *filename)
{
struct merged_segment **p, *msg;
p = &base_obj_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 = filename;
}
#ifndef KLD
static int
symbol_address_compare (void *fail_p, const void *a_p, const void *b_p)
{
const struct nlist * const * aa = a_p;
const struct nlist * a = *aa;
const struct nlist * const * bb = b_p;
const struct nlist * b = *bb;
if (a->n_type & N_STAB)
*(int *)fail_p = 1;
if ((a->n_type & N_TYPE) != (b->n_type & N_TYPE))
return (a->n_type & N_TYPE) < (b->n_type & N_TYPE) ? -1 : 1;
if (a->n_value != b->n_value)
{
if (cur_obj->swapped)
return SWAP_LONG (a->n_value) < SWAP_LONG (b->n_value) ? -1 : 1;
else
return a->n_value < b->n_value ? -1 : 1;
}
else
return 0;
}
static void
read_dwarf_info(void)
{
enum { chunksize = 256 };
struct ld_chunk {
struct ld_chunk * next;
size_t filedata[chunksize];
};
int little_endian;
struct section * debug_info = NULL;
struct section * debug_line = NULL;
struct section * debug_abbrev = NULL;
const char * name;
const char * comp_dir;
uint64_t stmt_list;
int has_stabs = FALSE;
struct line_reader_data * lrd;
struct nlist *st;
struct nlist **sst;
struct ld_chunk * chunks;
struct ld_chunk * lastchunk;
size_t * symdata;
size_t lastused;
size_t num_line_syms = 0;
size_t dwarf_source_i;
size_t max_files = 0;
struct line_info li_start, li_end;
size_t i;
#if __LITTLE_ENDIAN__
little_endian = !cur_obj->swapped;
#else
little_endian = cur_obj->swapped;
#endif
for (i = 0; i < cur_obj->nsection_maps; i++)
{
struct section * s = cur_obj->section_maps[i].s;
if (strncmp (s->segname, "__DWARF", 16) != 0)
continue;
if (strncmp (s->sectname, "__debug_info", 16) == 0)
debug_info = s;
else if (strncmp (s->sectname, "__debug_line", 16) == 0)
debug_line = s;
else if (strncmp (s->sectname, "__debug_abbrev", 16) == 0)
debug_abbrev = s;
}
if (! debug_info || ! debug_abbrev || ! cur_obj->symtab
|| debug_info->size == 0)
return;
if (read_comp_unit ((const uint8_t *) cur_obj->obj_addr + debug_info->offset,
debug_info->size,
((const uint8_t *)cur_obj->obj_addr
+ debug_abbrev->offset),
debug_abbrev->size, little_endian,
&name, &comp_dir, &stmt_list)
&& name) {
cur_obj->dwarf_name = strdup (name);
if (comp_dir)
cur_obj->dwarf_comp_dir = strdup (comp_dir);
else
cur_obj->dwarf_comp_dir = NULL;
} else {
warning_with_cur_obj("could not understand DWARF debug information");
return;
}
if (! debug_line || stmt_list == (uint64_t) -1)
return;
st = (struct nlist *)(cur_obj->obj_addr + cur_obj->symtab->symoff);
sst = allocate (sizeof (struct nlist *) * cur_obj->symtab->nsyms);
for (i = 0; i < cur_obj->symtab->nsyms; i++)
sst[i] = st + i;
qsort_r (sst, cur_obj->symtab->nsyms, sizeof (struct nlist *), &has_stabs,
symbol_address_compare);
if (has_stabs) {
error_with_cur_obj("has both STABS and DWARF debugging info");
free (sst);
return;
}
if (stmt_list >= debug_line->size){
warning_with_cur_obj("offset in DWARF debug_info for line number data is too large");
free (sst);
return;
}
lrd = line_open ((const uint8_t *) cur_obj->obj_addr + debug_line->offset
+ stmt_list,
debug_line->size - stmt_list, little_endian);
if (! lrd) {
warning_with_cur_obj("could not understand DWARF line number information");
free (sst);
return;
}
chunks = allocate (sizeof (*chunks));
chunks->next = NULL;
lastchunk = chunks;
lastused = 0;
symdata = allocate (sizeof (size_t) * cur_obj->symtab->nsyms);
memset (symdata, 0, sizeof (size_t) * cur_obj->symtab->nsyms);
li_start.end_of_sequence = TRUE;
for (i = 0; i < cur_obj->symtab->nsyms; i++){
struct nlist * s = sst[i];
size_t idx = s - st;
struct ld_chunk * symchunk;
size_t n_value = s->n_value;
size_t limit, max_limit;
if ((s->n_type & N_TYPE) != N_SECT
|| s->n_sect == NO_SECT)
continue;
if (! (cur_obj->section_maps[s->n_sect - 1].s->flags
& (S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS)))
continue;
if (i + 1 < cur_obj->symtab->nsyms
&& (sst[i + 1]->n_type & N_TYPE) == N_SECT)
limit = sst[i + 1]->n_value;
else
limit = (uint32_t) -1;
if (cur_obj->swapped){
n_value = SWAP_LONG (n_value);
limit = SWAP_LONG (limit);
}
if (li_start.pc > n_value || li_end.pc <= n_value
|| li_start.end_of_sequence)
{
if (! line_find_addr (lrd, &li_start, &li_end, n_value)) {
if (li_start.end_of_sequence)
continue;
else
goto line_err;
}
if (li_start.file == li_end.file && ! li_end.end_of_sequence)
if (! line_next (lrd, &li_end, line_stop_file))
goto line_err;
}
symdata[idx] = lastused + 1;
symchunk = lastchunk;
num_line_syms++;
max_limit = 0;
for (;;)
{
size_t j;
struct ld_chunk * curchunk = symchunk;
if (li_start.file >= 0x10000000)
goto line_err;
if (li_end.pc > max_limit)
max_limit = li_end.pc;
for (j = symdata[idx]; j < lastused; j++)
{
if (j % chunksize == 0)
curchunk = curchunk->next;
if (curchunk->filedata[j % chunksize] == li_start.file)
goto skipfile;
}
lastchunk->filedata[lastused % chunksize] = li_start.file;
lastused++;
if (li_start.file >= max_files)
max_files = li_start.file + 1;
if (lastused % chunksize == 0)
{
lastchunk->next = allocate (sizeof (*chunks));
lastchunk = lastchunk->next;
lastchunk->next = NULL;
}
skipfile:
if (li_end.pc >= limit || li_end.end_of_sequence)
break;
li_start = li_end;
if (! line_next (lrd, &li_end, line_stop_file))
goto line_err;
}
if (limit > max_limit)
limit = max_limit;
lastchunk->filedata[lastused % chunksize] = (size_t) -1;
lastused++;
if (lastused % chunksize == 0)
{
lastchunk->next = allocate (sizeof (*chunks));
lastchunk = lastchunk->next;
lastchunk->next = NULL;
}
lastchunk->filedata[lastused % chunksize] = limit - n_value;
lastused++;
if (lastused % chunksize == 0)
{
lastchunk->next = allocate (sizeof (*chunks));
lastchunk = lastchunk->next;
lastchunk->next = NULL;
}
}
free (sst);
cur_obj->dwarf_paths = allocate (max_files * sizeof (const char *));
memset (cur_obj->dwarf_paths, 0, max_files * sizeof (const char *));
cur_obj->dwarf_num_paths = max_files;
cur_obj->dwarf_source_data = allocate ((lastused + num_line_syms*2 + 1)
* sizeof (size_t));
dwarf_source_i = 0;
for (i = 0; i < cur_obj->symtab->nsyms; i++)
if (symdata[i]) {
struct ld_chunk * symchunk = chunks;
size_t j;
size_t * limit_space;
cur_obj->dwarf_source_data[dwarf_source_i++] = i;
limit_space = cur_obj->dwarf_source_data + dwarf_source_i++;
for (j = 0; j < (symdata[i] - 1) / chunksize; j++)
symchunk = symchunk->next;
for (j = symdata[i] - 1;
symchunk->filedata[j % chunksize] != (size_t) -1;
j++) {
size_t filenum = symchunk->filedata[j % chunksize];
cur_obj->dwarf_source_data[dwarf_source_i++] = filenum | 0x80000000;
if (! cur_obj->dwarf_paths[filenum])
cur_obj->dwarf_paths[filenum] = line_file (lrd, filenum);
if (j % chunksize == chunksize - 1)
symchunk = symchunk->next;
}
j++;
if (j % chunksize == 0)
symchunk = symchunk->next;
*limit_space = symchunk->filedata[j % chunksize];
}
cur_obj->dwarf_source_data[dwarf_source_i++] = 0x7fffffff;
line_free (lrd);
free (symdata);
lastchunk = chunks;
while (lastchunk) {
struct ld_chunk * tmp = lastchunk->next;
free (lastchunk);
lastchunk = tmp;
};
return;
line_err:
line_free (lrd);
free (sst);
free (symdata);
lastchunk = chunks;
while (lastchunk) {
struct ld_chunk * tmp = lastchunk->next;
free (lastchunk);
lastchunk = tmp;
};
warning_with_cur_obj("invalid DWARF line number information");
return;
}
#endif
static
char *
mkstr(
const char *args,
...)
{
va_list ap;
char *s, *p;
unsigned long size;
size = 0;
if(args != NULL){
size += strlen(args);
va_start(ap, args);
p = (char *)va_arg(ap, char *);
while(p != NULL){
size += strlen(p);
p = (char *)va_arg(ap, char *);
}
}
s = allocate(size + 1);
*s = '\0';
if(args != NULL){
(void)strcat(s, args);
va_start(ap, args);
p = (char *)va_arg(ap, char *);
while(p != NULL){
(void)strcat(s, p);
p = (char *)va_arg(ap, char *);
}
va_end(ap);
}
return(s);
}
#endif