#ifndef LIBRARY_API
#else
#include <mach-o/redo_prebinding.h>
#endif
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <limits.h>
#import <libc.h>
#import <malloc/malloc.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <mach-o/stab.h>
#import <mach-o/loader.h>
#import <mach-o/reloc.h>
#import <mach-o/hppa/reloc.h>
#import <mach-o/sparc/reloc.h>
#import <mach-o/ppc/reloc.h>
#import <mach-o/arm/reloc.h>
#import <stuff/breakout.h>
#import <stuff/best_arch.h>
#import <stuff/allocate.h>
#import <stuff/errors.h>
#import <stuff/rnd.h>
#import <stuff/hppa.h>
#import <stuff/execute.h>
#import <stuff/guess_short_name.h>
#import <stuff/seg_addr_table.h>
#import <stuff/macosx_deployment_target.h>
#include <mach-o/dyld.h>
#define U_ABS(l) (((int32_t)(l))<0 ? (uint32_t)(-(l)) : (l))
__private_extern__ char *progname = NULL;
static enum bool check_only = FALSE;
static enum bool seen_a_non_64_bit = FALSE;
static enum bool ignore_non_prebound = FALSE;
static enum bool zero_out_prebind_checksum = FALSE;
static enum bool check_for_non_prebound = FALSE;
static enum bool check_for_dylibs = FALSE;
static enum bool seen_a_dylib = FALSE;
static enum bool seen_a_non_dylib = FALSE;
static char *root_dir = NULL;
static char *executable_path = NULL;
#ifndef LIBRARY_API
char *seg_addr_table_name = NULL;
struct seg_addr_table *seg_addr_table = NULL;
uint32_t table_size = 0;
char *seg_addr_table_filename = NULL;
#endif
static uint32_t new_dylib_address = 0;
static uint32_t old_dylib_address = 0;
static uint32_t dylib_vmslide = 0;
static enum bool debug = FALSE;
static enum bool unprebinding = FALSE;
static enum bool arch_processed = FALSE;
enum link_state {
UNLINKED,
LINKED
};
static struct arch *arch = NULL;
static struct arch_flag arch_flag = { 0 };
static enum bool arch_swapped = FALSE;
static char *arch_name = NULL;
static struct nlist *arch_symbols = NULL;
static struct nlist_64 *arch_symbols64 = NULL;
static uint32_t arch_nsyms = 0;
static char *arch_strings = NULL;
static uint32_t arch_strsize = 0;
static struct dylib_table_of_contents *arch_tocs = NULL;
static uint32_t arch_ntoc = 0;
static struct dylib_module *arch_mods = NULL;
static struct dylib_module_64 *arch_mods64 = NULL;
static uint32_t arch_nmodtab = 0;
static struct dylib_reference *arch_refs = NULL;
static uint32_t arch_nextrefsyms = 0;
static struct twolevel_hint *arch_hints = NULL;
static uint32_t arch_nhints = 0;
static enum link_state arch_state = LINKED;
static uint32_t arch_seg1addr = 0;
static uint32_t arch_segs_read_write_addr = 0;
static enum bool arch_split_segs = FALSE;
static struct relocation_info *arch_extrelocs = NULL;
static struct relocation_info *arch_locrelocs = NULL;
static uint32_t arch_nextrel = 0;
static uint32_t arch_nlocrel = 0;
static uint32_t *arch_indirect_symtab = NULL;
static uint32_t arch_nindirectsyms = 0;
static enum bool arch_force_flat_namespace = FALSE;
static cpu_type_t arch_cant_be_missing = 0;
struct lib {
char *dylib_name;
char *file_name;
struct ofile *ofile;
dev_t dev;
ino_t ino;
struct symtab_command *st;
struct dysymtab_command *dyst;
struct routines_command *rc;
struct nlist *symbols;
struct nlist_64 *symbols64;
uint32_t nsyms;
char *strings;
uint32_t strsize;
struct dylib_table_of_contents *tocs;
uint32_t ntoc;
struct dylib_module *mods;
struct dylib_module_64 *mods64;
uint32_t nmodtab;
struct dylib_reference *refs;
uint32_t nextrefsyms;
enum link_state *module_states;
enum bool LC_PREBOUND_DYLIB_found;
uint32_t LC_PREBOUND_DYLIB_size;
uint32_t *dependent_images;
uint32_t ndependent_images;
char *umbrella_name;
char *library_name;
uint32_t name_size;
enum bool sub_images_setup;
uint32_t *sub_images;
uint32_t nsub_images;
enum bool two_level_debug_printed;
};
static struct lib *libs = NULL;
static uint32_t nlibs = 0;
static struct lib arch_lib;
static struct lib weak_lib;
static struct nlist weak_symbol = {
{ 0 },
N_ABS | N_EXT,
NO_SECT,
0,
0x0,
};
static enum link_state weak_module = LINKED;
struct segment {
char *file_name;
struct segment_command sg;
};
#ifndef LIBRARY_API
static void usage(
void);
static char * get_install_name(
struct arch *archs,
uint32_t narchs);
#endif
static enum bool has_resource_fork(
char *filename);
static void process_archs(
struct arch *archs,
uint32_t narchs,
enum bool has_resource_fork);
static uint32_t get_dylib_address(
void);
static void process_arch(void);
static void unprebind_arch(void);
static enum bool load_archs_libraries(void);
static enum bool load_library(
char *file_name,
struct dylib_command *dl_load,
enum bool time_stamps_must_match,
uint32_t *image_pointer);
static enum bool load_dependent_libraries(void);
static void print_two_level_info(
struct lib *lib);
static enum bool setup_sub_images(
struct lib *lib,
struct mach_header *lib_mh,
struct mach_header_64 *lib_mh64);
static void check_for_overlapping_segments(
uint32_t vmslide);
static void check_overlap(
struct segment *s1,
struct segment *s2);
static void setup_symbolic_info(enum bool missing_arch);
static void swap_arch_for_output(void);
static void check_symbolic_info_tables(
char *file_name,
struct mach_header *mh,
struct mach_header_64 *mh64,
uint32_t nlibrefs,
struct symtab_command *st,
struct dysymtab_command *dyst,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
uint32_t strsize,
struct dylib_table_of_contents *tocs,
uint32_t ntoc,
struct dylib_module *mods,
struct dylib_module_64 *mods64,
uint32_t nmodtab,
struct dylib_reference *refs,
uint32_t nextrefsyms);
static void check_for_dylib_override_symbols(void);
static void check_dylibs_for_definition(
char *file_name,
char *symbol_name);
static enum bool check_dylibs_for_reference(
char *symbol_name);
static char *bsearch_strings = NULL;
static struct nlist *bsearch_symbols = NULL;
static int dylib_bsearch(
const char *symbol_name,
const struct dylib_table_of_contents *toc);
static int nlist_bsearch(
const char *symbol_name,
const struct nlist *symbol);
static void setup_initial_undefined_list(void);
static void link_in_need_modules(void);
#define ARCH_LIB 0xffffffff
#define WEAK_LIB 0xfffffffe
struct symbol_list {
char *name;
struct nlist *symbol;
uint32_t ilib;
struct symbol_list *prev;
struct symbol_list *next;
};
static struct symbol_list undefined_list = {
NULL, NULL, 0, &undefined_list, &undefined_list
};
static void add_to_undefined_list(
char *name,
struct nlist *symbol,
uint32_t ilib);
static void link_library_module(
enum link_state *module_state,
struct lib *lib);
struct indr_loop_list {
struct nlist *symbol;
struct indr_loop_list *next;
};
#define NO_INDR_LOOP ((struct indr_loop_list *)1)
static struct lib *get_primary_lib(
uint32_t ilib,
struct nlist *symbol);
static struct lib *get_indr_lib(
char *symbol_name,
struct lib *lib);
static enum bool get_weak(
struct nlist *symbol);
static void lookup_symbol(
char *name,
struct lib *primary_lib,
enum bool weak,
struct nlist **symbol,
enum link_state **module_state,
struct lib **lib,
uint32_t *isub_image,
uint32_t *itoc,
struct indr_loop_list *indr_loop);
static enum bool lookup_symbol_in_arch(
char *name,
struct nlist **symbol,
enum link_state **module_state,
struct lib **lib,
uint32_t *isub_image,
uint32_t *itoc,
struct indr_loop_list *indr_loop);
static enum bool lookup_symbol_in_lib(
char *name,
struct lib *primary_lib,
struct nlist **symbol,
enum link_state **module_state,
struct lib **lib,
uint32_t *isub_image,
uint32_t *itoc,
struct indr_loop_list *indr_loop);
static void build_new_symbol_table(
uint32_t vmslide,
enum bool missing_arch);
static void setup_r_address_base(
void);
static void update_local_relocs(
uint32_t vmslide);
static void update_generic_local_relocs(
uint32_t vmslide);
static void update_hppa_local_relocs(
uint32_t vmslide);
static void update_sparc_local_relocs(
uint32_t vmslide);
static void update_ppc_local_relocs(
uint32_t vmslide);
static void update_arm_local_relocs(
uint32_t vmslide);
static void update_external_relocs(
uint32_t vmslide);
static void update_generic_external_relocs(
uint32_t vmslide);
static void update_hppa_external_relocs(
uint32_t vmslide);
static void update_sparc_external_relocs(
uint32_t vmslide);
static void update_ppc_external_relocs(
uint32_t vmslide);
static void update_arm_external_relocs(
uint32_t vmslide);
static char *contents_pointer_for_vmaddr(
uint32_t vmaddr,
uint32_t size);
static void update_symbol_pointers(
uint32_t vmslide);
static void update_self_modifying_stubs(
uint32_t vmslide);
static void reset_symbol_pointers(
uint32_t vmslide);
static void reset_self_modifying_stubs(
void);
static enum bool check_pb_la_ptr_reloc_cputype(
unsigned int reloc_type);
static void update_load_commands(
uint32_t vmslide);
static void message(
const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
#endif
;
static
inline
uint32_t
get_arch_long(
void *addr)
{
int32_t l;
memcpy(&l, addr, sizeof(uint32_t));
if(arch_swapped == TRUE)
return(SWAP_INT(l));
else
return(l);
}
static
inline
short
get_arch_short(
void *addr)
{
short s;
memcpy(&s, addr, sizeof(short));
if(arch_swapped == TRUE)
return(SWAP_SHORT(s));
else
return(s);
}
static
inline
char
get_arch_byte(
char *addr)
{
return(*addr);
}
static
inline
void
set_arch_long(
void *addr,
uint32_t value)
{
if(arch_swapped == TRUE)
value = SWAP_INT(value);
memcpy(addr, &value, sizeof(uint32_t));
}
static
inline
void
set_arch_short(
void *addr,
short value)
{
if(arch_swapped == TRUE)
value = SWAP_SHORT(value);
memcpy(addr, &value, sizeof(short));
}
static
inline
void
set_arch_byte(
char *addr,
char value)
{
*addr = value;
}
static
void
cleanup_libs()
{
uint32_t i;
for(i = 0; i < nlibs; i++){
if(libs[i].ofile != NULL)
ofile_unmap(libs[i].ofile);
}
}
#ifndef LIBRARY_API
int
main(
int argc,
char *argv[],
char *envp[])
{
int i;
char *input_file, *output_file, *objcunique;
struct arch *archs;
uint32_t narchs;
struct stat stat_buf;
enum bool verbose, calculate_input_prebind_cksum, write_to_stdout;
unsigned short mode;
uid_t uid;
gid_t gid;
struct seg_addr_table *entry;
char *install_name, *seg1addr_str, *endp;
input_file = NULL;
output_file = NULL;
archs = NULL;
narchs = 0;
errors = 0;
verbose = FALSE;
seg1addr_str = NULL;
write_to_stdout = FALSE;
progname = argv[0];
for(i = 1; i < argc; i++){
if(argv[i][0] == '-'){
if(strcmp(argv[i], "-o") == 0){
if(write_to_stdout)
fatal("-o cannot be used with the -s option");
if(i + 1 >= argc)
fatal("-o requires an argument");
if(output_file != NULL)
fatal("only one -o option allowed");
output_file = argv[i + 1];
i++;
}
else if(strcmp(argv[i], "-s") == 0){
if(output_file != NULL)
fatal("-s cannot be used with the -o option");
write_to_stdout = TRUE;
}
else if(strcmp(argv[i], "-r") == 0){
if(i + 1 >= argc)
fatal("-r requires an argument");
if(root_dir != NULL)
fatal("only one -r option allowed");
root_dir = argv[i + 1];
i++;
}
else if(strcmp(argv[i], "-e") == 0){
if(i + 1 >= argc)
fatal("-e requires an argument");
if(executable_path != NULL)
fatal("only one -e option allowed");
executable_path = argv[i + 1];
i++;
}
else if(strcmp(argv[i], "-seg_addr_table") == 0){
if(i + 1 >= argc)
fatal("-seg_addr_table requires an argument");
if(seg_addr_table_name != NULL)
fatal("only one -seg_addr_table option allowed");
if(seg1addr_str != NULL)
fatal("-seg_addr_table can't be used with "
"-seg1addr");
seg_addr_table_name = argv[i + 1];
seg_addr_table = parse_seg_addr_table(argv[i+1],
argv[i], argv[i+1], &table_size);
i++;
}
else if(strcmp(argv[i], "-seg_addr_table_filename") == 0){
if(i + 1 >= argc)
fatal("-seg_addr_table_filename requires an argument");
if(seg_addr_table_filename != NULL)
fatal("only one -seg_addr_table_filename option "
"allowed");
if(seg1addr_str != NULL)
fatal("-seg_addr_table_filename can't be used with "
"-seg1addr");
seg_addr_table_filename = argv[i + 1];
i++;
}
else if(strcmp(argv[i], "-seg1addr") == 0){
if(i + 1 >= argc)
fatal("-seg1addr requires an argument");
if(seg1addr_str != NULL)
fatal("only one -seg1addr option allowed");
if(seg_addr_table_filename != NULL ||
seg_addr_table_name != NULL)
fatal("-seg1addr can't be used with -seg_addr_table"
" or -seg_addr_table_filename");
seg1addr_str = argv[i + 1];
new_dylib_address = strtoul(argv[i + 1], &endp, 16);
if(*endp != '\0')
fatal("address for %s %s not a proper "
"hexadecimal number", argv[i], argv[i + 1]);
i++;
}
else if(strcmp(argv[i], "-c") == 0){
check_only = TRUE;
}
else if(strcmp(argv[i], "-i") == 0){
ignore_non_prebound = TRUE;
}
else if(strcmp(argv[i], "-z") == 0){
zero_out_prebind_checksum = TRUE;
}
else if(strcmp(argv[i], "-p") == 0){
check_for_non_prebound = TRUE;
}
else if(strcmp(argv[i], "-d") == 0){
check_for_dylibs = TRUE;
}
else if(strcmp(argv[i], "-debug") == 0){
debug = TRUE;
}
else if(strcmp(argv[i], "-v") == 0){
verbose = TRUE;
}
else if(strcmp(argv[i], "-u") == 0){
unprebinding = TRUE;
}
else{
fprintf(stderr, "%s: unknown option: %s\n", progname,
argv[i]);
usage();
}
}
else{
if(input_file != NULL)
fatal("only one input file allowed");
input_file = argv[i];
}
}
if(input_file == NULL){
fprintf(stderr, "%s no input file specified\n", progname);
usage();
}
if(check_only + check_for_non_prebound + check_for_dylibs > 1){
fprintf(stderr, "%s only one of -c, -p or -d can be specified\n",
progname);
usage();
}
if(zero_out_prebind_checksum == TRUE)
calculate_input_prebind_cksum = FALSE;
else
calculate_input_prebind_cksum = TRUE;
breakout(input_file, &archs, &narchs, calculate_input_prebind_cksum);
if(errors)
exit(2);
checkout(archs, narchs);
if(seg_addr_table != NULL && unprebinding == FALSE){
install_name = get_install_name(archs, narchs);
if(install_name != NULL || seg_addr_table_filename != NULL){
if(seg_addr_table_filename != NULL)
entry = search_seg_addr_table(seg_addr_table,
seg_addr_table_filename);
else
entry = search_seg_addr_table(seg_addr_table, install_name);
if(entry == NULL){
fprintf(stderr, "%s: no entry in -seg_addr_table %s for "
"input file's (%s) %s %s\n", progname,
seg_addr_table_name, input_file,
seg_addr_table_filename != NULL ?
"-seg_addr_table_filename" : "install name:",
seg_addr_table_filename != NULL ?
seg_addr_table_filename : install_name);
exit(2);
}
if(entry->split == TRUE)
new_dylib_address = entry->segs_read_only_addr;
else
new_dylib_address = entry->seg1addr;
if(new_dylib_address == 0){
fprintf(stderr, "%s: entry in -seg_addr_table %s for "
"input file's (%s) %s %s on line %u "
"has an address of zero\n", progname,
seg_addr_table_name, input_file,
seg_addr_table_filename != NULL ?
"-seg_addr_table_filename" : "install name:",
seg_addr_table_filename != NULL ?
seg_addr_table_filename : install_name,
entry->line);
exit(2);
}
}
}
process_archs(archs, narchs, has_resource_fork(input_file));
if(errors)
exit(2);
if(check_for_dylibs == TRUE){
if(seen_a_dylib == TRUE)
exit(0);
exit(1);
}
if(check_for_non_prebound == TRUE)
exit(0);
if(arch_processed == TRUE){
if(check_only == TRUE)
exit(1);
if(stat(input_file, &stat_buf) == -1)
system_error("can't stat input file: %s", input_file);
mode = stat_buf.st_mode & 07777;
uid = stat_buf.st_uid;
gid = stat_buf.st_gid;
if(output_file != NULL || write_to_stdout){
if(write_to_stdout)
output_file = NULL;
writeout(archs, narchs, output_file, mode, TRUE, FALSE, FALSE,
NULL);
if(errors){
if(write_to_stdout == FALSE)
unlink(output_file);
return(2);
}
}
else{
output_file = makestr(input_file, ".redo_prebinding", NULL);
writeout(archs, narchs, output_file, mode, TRUE, FALSE, FALSE,
NULL);
if(errors){
unlink(output_file);
return(2);
}
if(rename(output_file, input_file) == 1)
system_error("can't move temporary file: %s to input "
"file: %s\n", output_file, input_file);
free(output_file);
output_file = NULL;
}
objcunique = cmd_with_prefix("objcunique");
if(stat(objcunique, &stat_buf) != -1){
reset_execute_list();
add_execute_list(objcunique);
if(output_file != NULL)
add_execute_list(output_file);
else
add_execute_list(input_file);
add_execute_list("-prebind");
if(ignore_non_prebound == TRUE)
add_execute_list("-i");
if(root_dir != NULL){
add_execute_list("-r");
add_execute_list(root_dir);
}
if(execute_list(verbose) == 0)
fatal("internal objcunique command failed");
}
if(output_file != NULL){
if(chmod(output_file, mode) == -1)
system_error("can't set permissions on file: %s",
output_file);
if(chown(output_file, uid, gid) == -1)
system_error("can't set owner and group on file: %s",
output_file);
}
else if(write_to_stdout == FALSE){
if(chmod(input_file, mode) == -1)
system_error("can't set permissions on file: %s",
input_file);
if(chown(input_file, uid, gid) == -1)
system_error("can't set owner and group on file: %s",
input_file);
}
}
else{
if(check_only == TRUE)
exit(0);
}
free_archs(archs, narchs);
if(errors)
return(2);
else
return(0);
}
static
void
usage(
void)
{
fprintf(stderr, "Usage: %s [-c|-p|-d] [-i] [-z] [-u] [-r rootdir] "
"[-e executable_path] [-seg_addr_table table_file_name] "
"[-seg_addr_table_filename pathname] [-seg1addr address]"
"[-o output_file] [-s] input_file\n", progname);
exit(EXIT_FAILURE);
}
static
void
redo_exit(
int value)
{
exit(value);
}
static
void
message(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
}
#else
#include <setjmp.h>
#include <errno.h>
#include <mach/mach_error.h>
static jmp_buf library_env;
static char *error_message_buffer = NULL;
#define ERROR_MESSAGE_BUFFER_SIZE 8192
static char *last = NULL;
static uint32_t left = 0;
static enum object_file_type_retval object_file_type_archs(
struct arch *archs,
uint32_t narchs);
static
void
setup_error_message_buffer(
void)
{
if(error_message_buffer == NULL){
error_message_buffer = malloc(ERROR_MESSAGE_BUFFER_SIZE);
if(error_message_buffer == NULL)
system_fatal("virtual memory exhausted (malloc failed)");
error_message_buffer[0] = '\0';
error_message_buffer[ERROR_MESSAGE_BUFFER_SIZE - 1] = '\0';
last = error_message_buffer;
left = ERROR_MESSAGE_BUFFER_SIZE - 1;
}
}
static malloc_zone_t *library_zone = NULL;
static enum bool check_if_needed = FALSE;
static enum bool redo_prebinding_needed = FALSE;
static enum redo_prebinding_retval only_if_needed_retval;
static
void
reset_statics(
void)
{
check_only = FALSE;
seen_a_non_64_bit = FALSE;
ignore_non_prebound = FALSE;
check_for_non_prebound = FALSE;
check_for_dylibs = FALSE;
seen_a_dylib = FALSE;
seen_a_non_dylib = FALSE;
root_dir = NULL;
executable_path = NULL;
new_dylib_address = 0;
dylib_vmslide = 0;
debug = FALSE;
arch_processed = FALSE;
arch = NULL;
memset(&arch_flag, '\0', sizeof(struct arch_flag));
arch_swapped = FALSE;
arch_name = NULL;
arch_symbols = NULL;
arch_symbols64 = NULL;
arch_nsyms = 0;
arch_strings = NULL;
arch_strsize = 0;
arch_tocs = NULL;
arch_ntoc = 0;
arch_mods = NULL;
arch_mods64 = NULL;
arch_nmodtab = 0;
arch_refs = NULL;
arch_nextrefsyms = 0;
arch_hints = NULL;
arch_nhints = 0;
arch_state = LINKED;
arch_seg1addr = 0;
arch_segs_read_write_addr = 0;
arch_split_segs = FALSE;
arch_extrelocs = NULL;
arch_locrelocs = NULL;
arch_nextrel = 0;
arch_nlocrel = 0;
arch_indirect_symtab = NULL;
arch_nindirectsyms = 0;
arch_force_flat_namespace = FALSE;
arch_cant_be_missing = 0;
libs = NULL;
nlibs = 0;
memset(&arch_lib, '\0', sizeof(struct lib));
memset(&undefined_list, '\0', sizeof(struct symbol_list));
undefined_list.name = NULL;
undefined_list.symbol = NULL;
undefined_list.ilib = 0;
undefined_list.prev = &undefined_list;
undefined_list.next = &undefined_list;
error_message_buffer = NULL;
last = NULL;
left = 0;
errors = 0;
check_if_needed = FALSE;
redo_prebinding_needed = FALSE;
unprebinding = FALSE;
}
static
void
cleanup(
void)
{
cleanup_libs();
if(library_zone != NULL)
malloc_destroy_zone(library_zone);
library_zone = NULL;
}
char **
dependent_libs(
const char *file_name,
const char *program_name,
char **error_message)
{
struct arch * volatile archs;
volatile uint32_t narchs;
uint32_t i, j, k;
struct ofile * volatile ofile;
uint32_t ndependents;
char **dependents, *dylib_name;
struct load_command *lc;
struct dylib_command *dl_load;
enum bool found;
uint32_t ncmds;
reset_statics();
progname = (char *)program_name;
if(error_message != NULL)
*error_message = NULL;
ofile = NULL;
ndependents = 0;
dependents = NULL;
archs = NULL;
narchs = 0;
if(setjmp(library_env) != 0){
goto error_return;
}
ofile = breakout((char *)file_name, (struct arch **)&archs,
(uint32_t *)&narchs, FALSE);
if(errors)
goto error_return;
checkout(archs, narchs);
for(i = 0; i < narchs; i++){
arch = archs + i;
if(arch->type == OFILE_Mach_O &&
(arch->object->mh_filetype == MH_EXECUTE ||
arch->object->mh_filetype == MH_BUNDLE ||
arch->object->mh_filetype == MH_DYLIB)){
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(j = 0; j < ncmds; j++){
switch(lc->cmd){
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
ndependents++;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
dependents = (char **)malloc(sizeof(char *) * (ndependents + 1));
if(dependents == NULL)
system_fatal("virtual memory exhausted (malloc failed)");
ndependents = 0;
for(i = 0; i < narchs; i++){
arch = archs + i;
if(arch->type == OFILE_Mach_O &&
(arch->object->mh_filetype == MH_EXECUTE ||
arch->object->mh_filetype == MH_BUNDLE ||
arch->object->mh_filetype == MH_DYLIB)){
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(j = 0; j < ncmds; j++){
switch(lc->cmd){
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
dl_load = (struct dylib_command *)lc;
dylib_name = (char *)dl_load +
dl_load->dylib.name.offset;
found = FALSE;
for(k = 0; k < ndependents; k++){
if(strcmp(dependents[k], dylib_name) == 0){
found = TRUE;
break;
}
}
if(found == FALSE){
dependents[ndependents] =
(char *)malloc(strlen(dylib_name) + 1);
if(dependents[ndependents] == NULL)
system_fatal("virtual memory exhausted (malloc "
"failed)");
strcpy(dependents[ndependents], dylib_name);
ndependents++;
}
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
dependents[ndependents] = NULL;
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
cleanup();
return(dependents);
error_return:
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
cleanup();
if(error_message != NULL && error_message_buffer != NULL)
*error_message = error_message_buffer;
else if(error_message_buffer != NULL)
free(error_message_buffer);
return(NULL);
}
char *
install_name(
const char *file_name,
const char *program_name,
char **error_message)
{
struct arch * volatile archs;
volatile uint32_t narchs;
uint32_t i, j;
volatile struct ofile *ofile;
char *install_name, *dylib_name;
struct load_command *lc;
struct dylib_command *dl_id;
enum bool non_dylib_found;
uint32_t ncmds;
reset_statics();
progname = (char *)program_name;
if(error_message != NULL)
*error_message = NULL;
ofile = NULL;
archs = NULL;
narchs = 0;
install_name = NULL;
non_dylib_found = FALSE;
if(setjmp(library_env) != 0){
goto error_return;
}
ofile = breakout((char *)file_name, (struct arch **)&archs,
(uint32_t *)&narchs, FALSE);
if(errors)
goto error_return;
checkout(archs, narchs);
for(i = 0; i < narchs; i++){
arch = archs + i;
if(arch->type == OFILE_Mach_O &&
arch->object->mh_filetype == MH_DYLIB){
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(j = 0; j < ncmds; j++){
switch(lc->cmd){
case LC_ID_DYLIB:
dl_id = (struct dylib_command *)lc;
dylib_name = (char *)dl_id +
dl_id->dylib.name.offset;
if(install_name != NULL){
if(strcmp(install_name, dylib_name) != 0){
error("install names in all arch's don't "
"match");
goto error_return;
}
}
else{
install_name = dylib_name;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
else{
non_dylib_found = TRUE;
}
}
if(install_name != NULL && non_dylib_found == TRUE){
error("not all arch's are dylibs");
goto error_return;
}
if(install_name != NULL){
dylib_name = malloc(strlen(install_name) + 1);
strcpy(dylib_name, install_name);
install_name = dylib_name;
}
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap((struct ofile *)ofile);
cleanup();
return(install_name);
error_return:
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap((struct ofile *)ofile);
cleanup();
if(error_message != NULL && error_message_buffer != NULL)
*error_message = error_message_buffer;
else if(error_message_buffer != NULL)
free(error_message_buffer);
return(NULL);
}
enum redo_prebinding_retval
redo_prebinding(
const char *file_name,
const char *executable_path_arg,
const char *root_dir_arg,
const char *output_file,
const char *program_name,
char **error_message,
uint32_t slide_to_address,
int only_if_needed,
int zero_checksum,
cpu_type_t allow_missing_architectures,
uint32_t *throttle)
{
struct arch * volatile archs;
volatile uint32_t narchs;
struct ofile * volatile ofile;
struct stat stat_buf;
unsigned short mode;
uid_t uid;
gid_t gid;
enum bool calculate_input_prebind_cksum;
reset_statics();
progname = (char *)program_name;
if(error_message != NULL)
*error_message = NULL;
executable_path = (char *)executable_path_arg;
root_dir = (char *)root_dir_arg;
new_dylib_address = slide_to_address;
zero_out_prebind_checksum = zero_checksum;
arch_cant_be_missing = allow_missing_architectures;
ofile = NULL;
archs = NULL;
narchs = 0;
if(getenv("RP_IGNORE_NON_PREBOUND") != NULL)
ignore_non_prebound = TRUE;
if(only_if_needed != 0)
check_if_needed = TRUE;
else
check_if_needed = FALSE;
redo_prebinding_needed = FALSE;
only_if_needed_retval = REDO_PREBINDING_SUCCESS;
if(setjmp(library_env) != 0){
goto error_return;
}
if(zero_out_prebind_checksum == TRUE)
calculate_input_prebind_cksum = FALSE;
else
calculate_input_prebind_cksum = TRUE;
ofile = breakout((char *)file_name, (struct arch **)&archs,
(uint32_t *)&narchs,
calculate_input_prebind_cksum);
if(errors)
goto error_return;
checkout(archs, narchs);
if(errors)
goto error_return;
process_archs(archs, narchs, has_resource_fork((char *)file_name));
if(errors)
goto error_return;
if(check_if_needed == TRUE && redo_prebinding_needed == FALSE){
if(only_if_needed_retval == REDO_PREBINDING_SUCCESS)
only_if_needed_retval = REDO_PREBINDING_NOT_NEEDED;
goto error_return;
}
if(arch_processed == TRUE){
if(stat(file_name, &stat_buf) == -1)
system_error("can't stat input file: %s", file_name);
mode = stat_buf.st_mode & 06777;
uid = stat_buf.st_uid;
gid = stat_buf.st_gid;
if(output_file != NULL){
writeout(archs, narchs, (char *)output_file, mode, TRUE, FALSE,
FALSE, throttle);
if(errors){
unlink(output_file);
goto error_return;
}
}
else{
output_file = makestr(file_name, ".redo_prebinding", NULL);
writeout(archs, narchs, (char *)output_file, mode, TRUE, FALSE,
FALSE, throttle);
if(errors){
unlink(output_file);
goto error_return;
}
if(rename(output_file, file_name) == 1)
system_error("can't move temporary file: %s to input "
"file: %s\n", output_file, file_name);
free((char *)output_file);
output_file = NULL;
}
if(output_file != NULL){
if(chmod(output_file, mode) == -1)
system_error("can't set permissions on file: %s",
output_file);
if(chown(output_file, uid, gid) == -1)
system_error("can't set owner and group on file: %s",
output_file);
}
else{
if(chmod(file_name, mode) == -1)
system_error("can't set permissions on file: %s",
file_name);
if(chown(file_name, uid, gid) == -1)
system_error("can't set owner and group on file: %s",
file_name);
}
}
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
cleanup();
return(REDO_PREBINDING_SUCCESS);
error_return:
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
cleanup();
if(error_message != NULL && error_message_buffer != NULL)
*error_message = error_message_buffer;
else if(error_message_buffer != NULL)
free(error_message_buffer);
if(only_if_needed != 0 &&
only_if_needed_retval != REDO_PREBINDING_SUCCESS)
return(only_if_needed_retval);
return(REDO_PREBINDING_FAILURE);
}
enum redo_prebinding_retval
unprebind(
const char *file_name,
const char *output_file,
const char *program_name,
char **error_message,
int zero_checksum,
void *inbuf,
uint32_t inlen,
void **outbuf,
uint32_t *outlen)
{
struct arch * volatile archs;
volatile uint32_t narchs;
struct ofile * volatile ofile;
struct stat stat_buf;
unsigned short mode;
uid_t uid;
gid_t gid;
enum bool calculate_input_prebind_cksum, seen_archive;
reset_statics();
progname = (char *)program_name;
if(error_message != NULL)
*error_message = NULL;
new_dylib_address = 0;
zero_out_prebind_checksum = zero_checksum;
arch_cant_be_missing = FALSE;
ofile = NULL;
archs = NULL;
narchs = 0;
check_if_needed = TRUE;
only_if_needed_retval = REDO_PREBINDING_SUCCESS;
if(setjmp(library_env) != 0){
goto error_return;
}
if(zero_out_prebind_checksum == TRUE)
calculate_input_prebind_cksum = FALSE;
else
calculate_input_prebind_cksum = TRUE;
if(inbuf != NULL){
if(file_name == NULL)
file_name = "(from unprebind() call)";
ofile = breakout_mem(inbuf, inlen, (char *)file_name,
(struct arch **)&archs,
(uint32_t *)&narchs,
calculate_input_prebind_cksum);
}
else
ofile = breakout((char *)file_name, (struct arch **)&archs,
(uint32_t *)&narchs,
calculate_input_prebind_cksum);
if(errors)
goto error_return;
checkout(archs, narchs);
if(errors)
goto error_return;
unprebinding = TRUE;
process_archs(archs, narchs, has_resource_fork((char *)file_name));
if(errors)
goto error_return;
if(check_if_needed == TRUE && redo_prebinding_needed == FALSE){
if(only_if_needed_retval == REDO_PREBINDING_SUCCESS)
only_if_needed_retval = REDO_PREBINDING_NOT_NEEDED;
goto error_return;
}
if(arch_processed == TRUE){
if(inbuf == NULL){
if(stat(file_name, &stat_buf) == -1)
system_error("can't stat input file: %s", file_name);
mode = stat_buf.st_mode & 06777;
uid = stat_buf.st_uid;
gid = stat_buf.st_gid;
}
else{
mode = 00777;
uid = getuid();
gid = getgid();
}
if(output_file != NULL){
if(outbuf != NULL)
writeout_to_mem(archs, narchs, (char *)output_file, outbuf,
outlen, TRUE, FALSE, FALSE, &seen_archive);
else
writeout(archs, narchs, (char *)output_file, mode, TRUE,
FALSE, FALSE, NULL);
if(errors){
if(outbuf == NULL)
unlink(output_file);
goto error_return;
}
}
else{
output_file = makestr(file_name, ".redo_prebinding", NULL);
if(outbuf != NULL)
writeout_to_mem(archs, narchs, (char *)output_file, outbuf,
outlen, TRUE, FALSE, FALSE, &seen_archive);
else
writeout(archs, narchs, (char *)output_file, mode, TRUE,
FALSE, FALSE, NULL);
if(errors){
if(outbuf == NULL)
unlink(output_file);
goto error_return;
}
if(outbuf == NULL && rename(output_file, file_name) == 1)
system_error("can't move temporary file: %s to input "
"file: %s\n", output_file, file_name);
free((char *)output_file);
output_file = NULL;
}
if(output_file != NULL && outbuf == NULL){
if(chmod(output_file, mode) == -1)
system_error("can't set permissions on file: %s",
output_file);
if(chown(output_file, uid, gid) == -1)
system_error("can't set owner and group on file: %s",
output_file);
}
}
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
cleanup();
if(error_message_buffer != NULL)
free(error_message_buffer);
return(REDO_PREBINDING_SUCCESS);
error_return:
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
cleanup();
if(error_message != NULL && error_message_buffer != NULL)
*error_message = error_message_buffer;
else if(error_message_buffer != NULL)
free(error_message_buffer);
if(only_if_needed_retval != REDO_PREBINDING_SUCCESS)
return(only_if_needed_retval);
return(REDO_PREBINDING_FAILURE);
}
static enum needs_redo_prebinding_retval retval;
static
void
redo_exit(
int value)
{
switch(value){
case 1:
retval = PREBINDING_OUTOFDATE;
break;
case 2:
case 3:
retval = PREBINDING_UNKNOWN;
break;
default:
fprintf(stderr, "%s: internal error redo_exit() called with (%d) "
"unexpected value\n", progname, value);
exit(1);
}
longjmp(library_env, 1);
}
enum needs_redo_prebinding_retval
needs_redo_prebinding(
const char *file_name,
const char *executable_path_arg,
const char *root_dir_arg,
const char *program_name,
char **error_message,
uint32_t expected_address,
cpu_type_t allow_missing_architectures)
{
struct arch * volatile archs;
volatile uint32_t narchs;
struct ofile * volatile ofile;
reset_statics();
progname = (char *)program_name;
if(error_message != NULL)
*error_message = NULL;
executable_path = (char *)executable_path_arg;
root_dir = (char *)root_dir_arg;
new_dylib_address = expected_address;
arch_cant_be_missing = allow_missing_architectures;
ofile = NULL;
archs = NULL;
narchs = 0;
if(getenv("RP_IGNORE_NON_PREBOUND") != NULL)
ignore_non_prebound = TRUE;
check_only = TRUE;
retval = PREBINDING_UPTODATE;
if(setjmp(library_env) != 0){
goto return_point;
}
ofile = breakout((char *)file_name, (struct arch **)&archs,
(uint32_t *)&narchs, FALSE);
if(errors){
if(retval == PREBINDING_UPTODATE)
retval = PREBINDING_UNKNOWN;
goto return_point;
}
checkout(archs, narchs);
if(errors){
if(retval == PREBINDING_UPTODATE)
retval = PREBINDING_UNKNOWN;
goto return_point;
}
process_archs(archs, narchs, has_resource_fork((char *)file_name));
if(retval == PREBINDING_UPTODATE && seen_a_non_64_bit == FALSE)
retval = NOT_PREBOUND;
return_point:
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
cleanup();
if(error_message != NULL && error_message_buffer != NULL)
*error_message = error_message_buffer;
else if(error_message_buffer != NULL)
free(error_message_buffer);
return(retval);
}
enum object_file_type_retval
object_file_type(
const char *file_name,
const char *program_name,
char **error_message)
{
struct arch * volatile archs;
volatile uint32_t narchs;
struct ofile * volatile ofile;
enum object_file_type_retval retval;
reset_statics();
ofile = NULL;
progname = (char *)program_name;
if(error_message != NULL)
*error_message = NULL;
if(setjmp(library_env) != 0){
retval = OFT_FILE_ERROR;
goto done;
}
ofile = breakout((char *)file_name, (struct arch **)&archs,
(uint32_t *)&narchs, FALSE);
if(errors){
retval = OFT_FILE_ERROR;
goto done;
}
checkout(archs, narchs);
if(errors){
retval = OFT_FILE_ERROR;
goto done;
}
retval = object_file_type_archs(archs, narchs);
done:
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
if(error_message != NULL && error_message_buffer != NULL)
*error_message = error_message_buffer;
return(retval);
}
static
enum object_file_type_retval
object_file_type_archs(
struct arch *archs,
uint32_t narchs)
{
uint32_t i;
struct arch *arch;
enum bool type_determined;
enum object_file_type_retval retval, current;
retval = OFT_OTHER;
type_determined = FALSE;
for(i = 0; i < narchs; i++){
arch = archs + i;
if(arch->type == OFILE_ARCHIVE){
current = OFT_ARCHIVE;
}
else if(arch->type == OFILE_Mach_O){
switch(arch->object->mh_filetype){
case MH_EXECUTE:
current = OFT_EXECUTABLE;
break;
case MH_DYLIB:
current = OFT_DYLIB;
break;
case MH_BUNDLE:
current = OFT_BUNDLE;
break;
default:
current = OFT_OTHER;
break;
}
}
else
current = OFT_OTHER;
if(type_determined == TRUE && retval != current)
return(OFT_INCONSISTENT);
retval = current;
type_determined = TRUE;
}
return(retval);
}
int
get_prebind_cksums(
const char *file_name,
struct prebind_cksum_arch **cksums,
uint32_t *ncksums,
const char *program_name,
char **error_message)
{
uint32_t i;
struct arch * volatile archs;
struct arch *arch;
volatile uint32_t narchs;
struct ofile * volatile ofile;
int retval;
reset_statics();
progname = (char *)program_name;
if(error_message != NULL)
*error_message = NULL;
*cksums = NULL;
ofile = NULL;
if(setjmp(library_env) != 0){
retval = 1;
goto done;
}
ofile = breakout((char *)file_name, (struct arch **)&archs,
(uint32_t *)&narchs, FALSE);
if(errors){
retval = 1;
goto done;
}
checkout(archs, narchs);
if(errors){
retval = 1;
goto done;
}
*cksums = malloc(sizeof(struct prebind_cksum_arch) * narchs);
if(*cksums == NULL)
system_fatal("virtual memory exhausted (malloc failed)");
memset(*cksums, '\0', sizeof(struct prebind_cksum_arch) * narchs);
*ncksums = narchs;
for(i = 0; i < narchs; i++){
arch = (struct arch *)(archs + i);
if(arch->type == OFILE_Mach_O){
(*cksums)[i].cputype = arch->object->mh_cputype;
(*cksums)[i].cpusubtype = arch->object->mh_cpusubtype;
if(arch->object->cs != NULL){
(*cksums)[i].has_cksum = 1;
(*cksums)[i].cksum = arch->object->cs->cksum;
}
}
else if(arch->fat_arch != NULL){
(*cksums)[i].cputype = arch->fat_arch->cputype;
(*cksums)[i].cpusubtype = arch->fat_arch->cpusubtype;
}
}
retval = 0;
done:
free_archs(archs, narchs);
if(ofile != NULL)
ofile_unmap(ofile);
if(error_message != NULL && error_message_buffer != NULL)
*error_message = error_message_buffer;
return(retval);
}
#endif
#ifndef LIBRARY_API
static
char *
get_install_name(
struct arch *archs,
uint32_t narchs)
{
uint32_t i,j;
char *install_name;
struct load_command *lc, *load_commands;
struct dylib_command *dl_id;
uint32_t ncmds;
install_name = NULL;
for(i = 0; i < narchs; i++){
arch = archs + i;
if(arch->type == OFILE_Mach_O){
if(arch->object->mh_filetype == MH_DYLIB){
load_commands = arch->object->load_commands;
lc = load_commands;
dl_id = NULL;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(j = 0;
j < ncmds && dl_id == NULL;
j++){
switch(lc->cmd){
case LC_ID_DYLIB:
dl_id = (struct dylib_command *)lc;
if(install_name != NULL){
if(strcmp(install_name, (char *)dl_id +
dl_id->dylib.name.offset) != 0)
fatal_arch(arch, NULL, "fat archs have "
"different install_names (%s and %s)",
install_name, (char *)dl_id +
dl_id->dylib.name.offset);
}
else
install_name = (char *)dl_id +
dl_id->dylib.name.offset;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
}
return(install_name);
}
#endif
static
void
process_archs(
struct arch *archs,
uint32_t narchs,
enum bool has_resource_fork)
{
uint32_t i;
uint32_t mh_flags;
for(i = 0; i < narchs; i++){
arch = archs + i;
if(arch->type != OFILE_Mach_O){
if(check_for_dylibs == TRUE){
if(seen_a_dylib == TRUE)
exit(2);
seen_a_non_dylib = TRUE;
continue;
}
#ifdef LIBRARY_API
else if(check_only == TRUE){
retval = NOT_PREBINDABLE;
return;
}
#endif
else if(check_only == TRUE ||
ignore_non_prebound == TRUE ||
check_for_non_prebound == TRUE)
continue;
else{
fatal_arch(arch, NULL, "file is not a Mach-O file: ");
}
}
if(arch->object->mh == NULL){
arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
continue;
}
else{
seen_a_non_64_bit = TRUE;
}
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
if(arch->object->mh_filetype == MH_EXECUTE &&
(mh_flags & MH_DYLDLINK) != MH_DYLDLINK){
if(check_for_dylibs == TRUE){
if(seen_a_dylib == TRUE)
exit(2);
seen_a_non_dylib = TRUE;
}
#ifdef LIBRARY_API
else if(check_if_needed == TRUE){
only_if_needed_retval = REDO_PREBINDING_NOT_NEEDED;
return;
}
else if(check_only == TRUE){
retval = NOT_PREBINDABLE;
return;
}
#endif
else if(check_only == TRUE ||
ignore_non_prebound == TRUE ||
check_for_non_prebound == TRUE)
continue;
else{
fatal_arch(arch, NULL, "file is Mach-O executable that is"
"not dynamically linked: ");
}
}
if(arch->object->mh_filetype != MH_EXECUTE &&
arch->object->mh_filetype != MH_DYLIB &&
! (unprebinding && arch->object->mh_filetype == MH_BUNDLE)){
if(check_for_dylibs == TRUE){
if(seen_a_dylib == TRUE)
exit(2);
seen_a_non_dylib = TRUE;
}
#ifdef LIBRARY_API
else if(check_if_needed == TRUE){
only_if_needed_retval = REDO_PREBINDING_NOT_PREBOUND;
return;
}
else if(check_only == TRUE){
retval = NOT_PREBINDABLE;
return;
}
#endif
else if(check_only == TRUE ||
ignore_non_prebound == TRUE ||
check_for_non_prebound == TRUE)
continue;
else{
fatal_arch(arch, NULL, "file is not a Mach-O "
"executable or dynamic shared library file: ");
}
}
if(check_for_dylibs == TRUE){
if(arch->object->mh_filetype == MH_DYLIB){
if(seen_a_non_dylib == TRUE)
exit(2);
seen_a_dylib = TRUE;
}
else{
if(seen_a_dylib == TRUE)
exit(2);
seen_a_non_dylib = TRUE;
}
continue;
}
if((unprebinding == FALSE &&
(mh_flags & MH_PREBOUND) != MH_PREBOUND &&
(mh_flags & MH_PREBINDABLE) != MH_PREBINDABLE)){
if(check_for_non_prebound == TRUE){
if((mh_flags & MH_DYLDLINK) == MH_DYLDLINK)
exit(1);
continue;
}
#ifdef LIBRARY_API
else if(check_if_needed == TRUE){
if(arch_cant_be_missing != arch->object->mh_cputype){
continue;
}
only_if_needed_retval = REDO_PREBINDING_NOT_PREBOUND;
return;
}
else if(check_only == TRUE){
if(arch_cant_be_missing != arch->object->mh_cputype){
continue;
}
retval = NOT_PREBOUND;
return;
}
#endif
else if(check_only == TRUE || ignore_non_prebound == TRUE){
continue;
}
else
fatal_arch(arch, NULL, "file is not prebound: ");
}
#ifdef LIBRARY_API
else if(unprebinding == TRUE &&
(mh_flags & MH_PREBOUND) != MH_PREBOUND &&
(mh_flags & MH_DYLDLINK) != MH_DYLDLINK){
only_if_needed_retval = REDO_PREBINDING_NOT_PREBOUND;
return;
}
#endif
else if(unprebinding == TRUE &&
(mh_flags & MH_PREBOUND) != MH_PREBOUND &&
(mh_flags & MH_DYLDLINK) != MH_DYLDLINK){
continue;
}
if(check_for_non_prebound == TRUE)
continue;
if(has_resource_fork == TRUE)
fatal_arch(arch, NULL, "redoing the prebinding can't be done "
"because file has a resource fork or "
"type/creator: ");
if(unprebinding == TRUE)
unprebind_arch();
else
process_arch();
#ifdef LIBRARY_API
if(check_only == TRUE &&
(arch_cant_be_missing != 0 &&
arch_cant_be_missing == arch->object->mh_cputype))
return;
#endif
}
}
static
void
process_arch(
void)
{
uint32_t mh_flags;
if(libs != NULL){
cleanup_libs();
free(libs);
}
libs = NULL;
nlibs = 0;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
memset(&arch_lib, '\0', sizeof(struct lib));
arch_force_flat_namespace = (mh_flags & MH_FORCE_FLAT) == MH_FORCE_FLAT;
arch_flag.cputype = arch->object->mh_cputype;
arch_flag.cpusubtype = arch->object->mh_cpusubtype;
set_arch_flag_name(&arch_flag);
arch_name = arch_flag.name;
if(debug == TRUE)
printf("%s: processing file: %s (for architecture %s)\n",
progname, arch->file_name, arch_name);
if(arch->object->mh_filetype == MH_DYLIB){
old_dylib_address = get_dylib_address();
if(new_dylib_address != 0){
dylib_vmslide = new_dylib_address - old_dylib_address;
#ifdef LIBRARY_API
if(dylib_vmslide != 0)
redo_prebinding_needed = TRUE;
#endif
}
}
if(load_archs_libraries() == FALSE){
setup_symbolic_info(TRUE);
build_new_symbol_table(0, TRUE);
if(arch_swapped == TRUE)
swap_arch_for_output();
return;
}
if(load_dependent_libraries() == FALSE){
setup_symbolic_info(TRUE);
build_new_symbol_table(0, TRUE);
if(arch_swapped == TRUE)
swap_arch_for_output();
return;
}
if(nlibs == 0 && dylib_vmslide == 0){
return;
}
setup_symbolic_info(FALSE);
check_for_overlapping_segments(dylib_vmslide);
if((mh_flags & MH_TWOLEVEL) != MH_TWOLEVEL)
check_for_dylib_override_symbols();
setup_initial_undefined_list();
link_in_need_modules();
if(check_only == TRUE && new_dylib_address != 0){
if(old_dylib_address != new_dylib_address)
redo_exit(1);
}
if(check_only == TRUE)
return;
arch_processed = TRUE;
build_new_symbol_table(dylib_vmslide, FALSE);
setup_r_address_base();
if(dylib_vmslide != 0)
update_local_relocs(dylib_vmslide);
update_external_relocs(dylib_vmslide);
update_symbol_pointers(dylib_vmslide);
update_self_modifying_stubs(dylib_vmslide);
update_load_commands(dylib_vmslide);
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE){
if(arch->object->mh != NULL){
arch->object->mh->flags &= ~MH_PREBINDABLE;
arch->object->mh->flags |= MH_PREBOUND;
}
else{
arch->object->mh64->flags &= ~MH_PREBINDABLE;
arch->object->mh64->flags |= MH_PREBOUND;
}
}
if(arch_swapped == TRUE)
swap_arch_for_output();
}
static
void
unprebind_arch(
void)
{
uint32_t mh_flags;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
#ifdef LIBRARY_API
redo_prebinding_needed = TRUE;
#endif
arch_force_flat_namespace = (mh_flags & MH_FORCE_FLAT) ==
MH_FORCE_FLAT;
arch_flag.cputype = arch->object->mh_cputype;
arch_flag.cpusubtype = arch->object->mh_cpusubtype;
set_arch_flag_name(&arch_flag);
arch_name = arch_flag.name;
if(debug == TRUE)
printf("%s: unprebinding file: %s (for architecture %s)\n",
progname, arch->file_name, arch_name);
if(arch->object->mh_filetype == MH_DYLIB){
old_dylib_address = get_dylib_address();
new_dylib_address = 0;
dylib_vmslide = new_dylib_address - old_dylib_address;
}
else{
dylib_vmslide = 0;
}
setup_symbolic_info(TRUE);
update_load_commands(dylib_vmslide);
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
build_new_symbol_table(dylib_vmslide, FALSE);
struct macosx_deployment_target deployment_version;
get_macosx_deployment_target(&deployment_version);
if(deployment_version.major >= 3 && deployment_version.major < 4){
if((mh_flags & MH_PREBOUND) != MH_PREBOUND){
arch_processed = TRUE;
if(arch_swapped == TRUE)
swap_arch_for_output();
if(arch->object->mh != NULL)
arch->object->mh->flags |= MH_CANONICAL;
else
arch->object->mh64->flags |= MH_CANONICAL;
return;
}
}
setup_r_address_base();
if(dylib_vmslide != 0)
update_local_relocs(dylib_vmslide);
if((mh_flags & MH_CANONICAL) != MH_CANONICAL)
update_external_relocs(dylib_vmslide);
reset_symbol_pointers(dylib_vmslide);
reset_self_modifying_stubs();
arch_processed = TRUE;
if(deployment_version.major >= 3 && deployment_version.major < 4){
mh_flags &= ~MH_PREBOUND;
mh_flags |= MH_PREBINDABLE;
}
else{
if((mh_flags & MH_PREBOUND) == MH_PREBOUND){
mh_flags &= ~MH_PREBOUND;
mh_flags |= MH_PREBINDABLE;
}
}
mh_flags |= MH_CANONICAL;
if(arch->object->mh != NULL)
arch->object->mh->flags = mh_flags;
else
arch->object->mh64->flags = mh_flags;
if(arch_swapped == TRUE)
swap_arch_for_output();
}
static
uint32_t
get_dylib_address(
void)
{
uint32_t i, addr;
struct load_command *lc;
struct segment_command *sg;
uint32_t ncmds;
addr = 0;
sg = NULL;
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(i = 0; i < ncmds && sg == NULL; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
addr = sg->vmaddr;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
return(addr);
}
static
enum bool
load_archs_libraries(
void)
{
uint32_t i, ndependent_images;
struct load_command *lc, *load_commands;
struct dylib_command *dl_load, *dl_id;
uint32_t *dependent_images, *image_pointer;
char *suffix;
enum bool is_framework;
uint32_t ncmds;
load_commands = arch->object->load_commands;
ndependent_images = 0;
dependent_images = NULL;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
if(arch_force_flat_namespace == FALSE){
lc = load_commands;
for(i = 0; i < ncmds; i++){
switch(lc->cmd){
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
ndependent_images++;
break;
case LC_ID_DYLIB:
dl_id = (struct dylib_command *)lc;
arch_lib.file_name = arch->file_name;
arch_lib.dylib_name = (char *)dl_id +
dl_id->dylib.name.offset;
arch_lib.umbrella_name =
guess_short_name(arch_lib.dylib_name, &is_framework,
&suffix);
if(is_framework == TRUE){
arch_lib.name_size = strlen(arch_lib.umbrella_name);
}
else{
if(arch_lib.umbrella_name != NULL){
arch_lib.library_name = arch_lib.umbrella_name;
arch_lib.umbrella_name = NULL;
arch_lib.name_size = strlen(arch_lib.library_name);
}
}
if(suffix != NULL)
free(suffix);
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
dependent_images = allocate(sizeof(uint32_t) *
ndependent_images);
arch_lib.dependent_images = dependent_images;
arch_lib.ndependent_images = ndependent_images;
}
if(arch_lib.dylib_name == NULL){
arch_lib.dylib_name = "not a dylib";
arch_lib.file_name = arch->file_name;
}
lc = load_commands;
ndependent_images = 0;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_LOAD_DYLIB ||
lc->cmd == LC_LOAD_WEAK_DYLIB ||
lc->cmd == LC_REEXPORT_DYLIB){
if(dependent_images != NULL)
image_pointer = &(dependent_images[ndependent_images++]);
else
image_pointer = NULL;
dl_load = (struct dylib_command *)lc;
if(load_library(arch->file_name, dl_load, FALSE,
image_pointer) == FALSE)
return(FALSE);
}
if(lc->cmd == LC_ID_DYLIB && check_only == TRUE){
dl_load = (struct dylib_command *)lc;
if(load_library(arch->file_name, dl_load, TRUE, NULL) == FALSE)
return(FALSE);
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
return(TRUE);
}
static
enum bool
load_dependent_libraries(
void)
{
uint32_t i, j, ndependent_images;
struct load_command *lc;
struct dylib_command *dl_load;
uint32_t *dependent_images, *image_pointer;
enum bool some_images_setup;
uint32_t ncmds;
for(i = 0; i < nlibs; i++){
if(debug == TRUE)
printf("%s: loading libraries for library %s\n",
progname, libs[i].file_name);
ndependent_images = 0;
dependent_images = NULL;
if(arch_force_flat_namespace == FALSE){
lc = libs[i].ofile->load_commands;
if(libs[i].ofile->mh != NULL)
ncmds = libs[i].ofile->mh->ncmds;
else
ncmds = libs[i].ofile->mh64->ncmds;
for(j = 0; j < ncmds; j++){
switch(lc->cmd){
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_REEXPORT_DYLIB:
ndependent_images++;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
dependent_images = allocate(sizeof(uint32_t *) *
ndependent_images);
libs[i].dependent_images = dependent_images;
libs[i].ndependent_images = ndependent_images;
}
ndependent_images = 0;
lc = libs[i].ofile->load_commands;
if(libs[i].ofile->mh != NULL)
ncmds = libs[i].ofile->mh->ncmds;
else
ncmds = libs[i].ofile->mh64->ncmds;
for(j = 0; j < ncmds; j++){
if(lc->cmd == LC_LOAD_DYLIB ||
lc->cmd == LC_LOAD_WEAK_DYLIB ||
lc->cmd == LC_REEXPORT_DYLIB){
dl_load = (struct dylib_command *)lc;
if(dependent_images != NULL)
image_pointer = &(dependent_images[
ndependent_images++]);
else
image_pointer = NULL;
if(load_library(libs[i].ofile->file_name, dl_load, TRUE,
image_pointer) == FALSE)
return(FALSE);
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
if(arch_force_flat_namespace == FALSE){
do{
some_images_setup = FALSE;
if(arch_lib.sub_images_setup == FALSE){
some_images_setup |= setup_sub_images(&arch_lib,
arch->object->mh,
arch->object->mh64);
}
for(i = 0; i < nlibs; i++){
if(libs[i].sub_images_setup == FALSE){
some_images_setup |= setup_sub_images(&(libs[i]),
libs[i].ofile->mh,
libs[i].ofile->mh64);
}
}
}while(some_images_setup == TRUE);
if(debug == TRUE){
if(arch_lib.two_level_debug_printed == FALSE){
print_two_level_info(&arch_lib);
}
arch_lib.two_level_debug_printed = TRUE;
for(i = 0; i < nlibs; i++){
if(libs[i].two_level_debug_printed == FALSE){
print_two_level_info(libs + i);
}
libs[i].two_level_debug_printed = TRUE;
}
}
}
return(TRUE);
}
static
void
print_two_level_info(
struct lib *lib)
{
uint32_t j;
uint32_t *sp;
printf("two-level library: %s (file_name %s)",
lib->dylib_name, lib->file_name);
if(lib->umbrella_name != NULL)
printf(" umbrella_name = %.*s\n",
(int)(lib->name_size),
lib->umbrella_name);
else
printf(" umbrella_name = NULL\n");
if(lib->library_name != NULL)
printf(" library_name = %.*s\n",
(int)(lib->name_size),
lib->library_name);
else
printf(" library_name = NULL\n");
printf(" ndependent_images = %u\n",
lib->ndependent_images);
sp = lib->dependent_images;
for(j = 0;
j < lib->ndependent_images;
j++){
if(libs[sp[j]].umbrella_name != NULL)
printf("\t[%u] %.*s\n", j,
(int)libs[sp[j]].name_size,
libs[sp[j]].umbrella_name);
else if(libs[sp[j]].library_name != NULL)
printf("\t[%u] %.*s\n", j,
(int)libs[sp[j]].name_size,
libs[sp[j]].library_name);
else
printf("\t[%u] %s (file_name %s)\n", j,
libs[sp[j]].dylib_name,
libs[sp[j]].file_name);
}
printf(" nsub_images = %u\n",
lib->nsub_images);
sp = lib->sub_images;
for(j = 0; j < lib->nsub_images; j++){
if(libs[sp[j]].umbrella_name != NULL)
printf("\t[%u] %.*s\n", j,
(int)libs[sp[j]].name_size,
libs[sp[j]].umbrella_name);
else if(libs[sp[j]].library_name != NULL)
printf("\t[%u] %.*s\n", j,
(int)libs[sp[j]].name_size,
libs[sp[j]].library_name);
else
printf("\t[%u] %s (file_name %s)\n", j,
libs[sp[j]].dylib_name,
libs[sp[j]].file_name);
}
}
static
enum bool
setup_sub_images(
struct lib *lib,
struct mach_header *lib_mh,
struct mach_header_64 *lib_mh64)
{
uint32_t i, j, k, l, n, max_libraries;
struct mach_header *mh;
struct mach_header_64 *mh64;
struct load_command *lc, *load_commands;
struct sub_umbrella_command *usub;
struct sub_library_command *lsub;
struct sub_framework_command *sub;
struct dylib_command *dl_load;
uint32_t *deps;
char *sub_umbrella_name, *sub_library_name, *sub_framework_name,
*dylib_name;
enum bool found;
uint32_t ncmds;
max_libraries = 0;
deps = lib->dependent_images;
if(lib_mh != NULL){
mh = lib_mh;
mh64 = NULL;
load_commands = (struct load_command *)((char *)mh +
sizeof(struct mach_header));
ncmds = mh->ncmds;
}
else{
mh = NULL;
mh64 = lib_mh64;
load_commands = (struct load_command *)((char *)mh64 +
sizeof(struct mach_header_64));
ncmds = mh64->ncmds;
}
lc = load_commands;
for(i = 0; i < 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 < lib->ndependent_images; j++){
if(libs[deps[j]].umbrella_name != NULL &&
strncmp(sub_umbrella_name, libs[deps[j]].umbrella_name,
libs[deps[j]].name_size) == 0 &&
sub_umbrella_name[libs[deps[j]].name_size] == '\0'){
if(libs[deps[j]].sub_images_setup == FALSE)
return(FALSE);
max_libraries += 1 + libs[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 < lib->ndependent_images; j++){
if(libs[deps[j]].library_name != NULL &&
strncmp(sub_library_name, libs[deps[j]].library_name,
libs[deps[j]].name_size) == 0 &&
sub_library_name[libs[deps[j]].name_size] == '\0'){
if(libs[deps[j]].sub_images_setup == FALSE)
return(FALSE);
max_libraries += 1 + libs[deps[j]].nsub_images;
}
}
break;
case LC_REEXPORT_DYLIB:
dl_load = (struct dylib_command *)lc;
dylib_name = (char *)dl_load + dl_load->dylib.name.offset;
for(j = 0; j < lib->ndependent_images; j++){
if(libs[deps[j]].dylib_name != NULL &&
strcmp(dylib_name, libs[deps[j]].dylib_name) == 0){
if(libs[deps[j]].sub_images_setup == FALSE)
return(FALSE);
max_libraries += 1 + libs[deps[j]].nsub_images;
}
}
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
max_libraries += lib->ndependent_images;
lib->sub_images = allocate(sizeof(uint32_t) * max_libraries);
n = 0;
if(lib->umbrella_name != NULL){
for(i = 0; i < lib->ndependent_images; i++){
if(libs[deps[i]].ofile->mh != NULL){
mh = libs[deps[i]].ofile->mh;
load_commands = (struct load_command *)
((char *)(libs[deps[i]].ofile->mh) +
sizeof(struct mach_header));
lc = load_commands;
ncmds = libs[deps[i]].ofile->mh->ncmds;
}
else{
mh64 = libs[deps[i]].ofile->mh64;
load_commands = (struct load_command *)
((char *)(libs[deps[i]].ofile->mh64) +
sizeof(struct mach_header_64));
lc = load_commands;
ncmds = libs[deps[i]].ofile->mh64->ncmds;
}
for(j = 0; j < ncmds; j++){
if(lc->cmd == LC_SUB_FRAMEWORK){
sub = (struct sub_framework_command *)lc;
sub_framework_name = (char *)sub + sub->umbrella.offset;
if(lib->umbrella_name != NULL &&
strncmp(sub_framework_name,
lib->umbrella_name,
lib->name_size) == 0 &&
sub_framework_name[lib->name_size] =='\0'){
lib->sub_images[n++] = deps[i];
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
}
if(lib_mh != NULL){
mh = lib_mh;
mh64 = NULL;
load_commands = (struct load_command *)((char *)mh +
sizeof(struct mach_header));
ncmds = mh->ncmds;
}
else{
mh = NULL;
mh64 = lib_mh64;
load_commands = (struct load_command *)((char *)mh64 +
sizeof(struct mach_header_64));
ncmds = mh64->ncmds;
}
lc = load_commands;
for(i = 0; i < 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 < lib->ndependent_images; j++){
if(libs[deps[j]].umbrella_name != NULL &&
strncmp(sub_umbrella_name, libs[deps[j]].umbrella_name,
libs[deps[j]].name_size) == 0 &&
sub_umbrella_name[libs[deps[j]].name_size] == '\0'){
found = FALSE;
for(l = 0; l < n; l++){
if(lib->sub_images[l] == deps[j]){
found = TRUE;
break;
}
}
if(found == FALSE)
lib->sub_images[n++] = deps[j];
for(k = 0; k < libs[deps[j]].nsub_images; k++){
found = FALSE;
for(l = 0; l < n; l++){
if(lib->sub_images[l] ==
libs[deps[j]].sub_images[k]){
found = TRUE;
break;
}
}
if(found == FALSE)
lib->sub_images[n++] =
libs[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 < lib->ndependent_images; j++){
if(libs[deps[j]].library_name != NULL &&
strncmp(sub_library_name, libs[deps[j]].library_name,
libs[deps[j]].name_size) == 0 &&
sub_library_name[libs[deps[j]].name_size] == '\0'){
found = FALSE;
for(l = 0; l < n; l++){
if(lib->sub_images[l] == deps[j]){
found = TRUE;
break;
}
}
if(found == FALSE)
lib->sub_images[n++] = deps[j];
for(k = 0; k < libs[deps[j]].nsub_images; k++){
found = FALSE;
for(l = 0; l < n; l++){
if(lib->sub_images[l] ==
libs[deps[j]].sub_images[k]){
found = TRUE;
break;
}
}
if(found == FALSE)
lib->sub_images[n++] =
libs[deps[j]].sub_images[k];
}
}
}
break;
case LC_REEXPORT_DYLIB:
dl_load = (struct dylib_command *)lc;
dylib_name = (char *)dl_load + dl_load->dylib.name.offset;
for(j = 0; j < lib->ndependent_images; j++){
if(libs[deps[j]].dylib_name != NULL &&
strcmp(dylib_name, libs[deps[j]].dylib_name) == 0){
found = FALSE;
for(l = 0; l < n; l++){
if(lib->sub_images[l] == deps[j]){
found = TRUE;
break;
}
}
if(found == FALSE)
lib->sub_images[n++] = deps[j];
for(k = 0; k < libs[deps[j]].nsub_images; k++){
found = FALSE;
for(l = 0; l < n; l++){
if(lib->sub_images[l] ==
libs[deps[j]].sub_images[k]){
found = TRUE;
break;
}
}
if(found == FALSE)
lib->sub_images[n++] =
libs[deps[j]].sub_images[k];
}
}
}
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
lib->sub_images = reallocate(lib->sub_images, sizeof(uint32_t) *n);
lib->nsub_images = n;
lib->sub_images_setup = TRUE;
return(TRUE);
}
static
enum bool
load_library(
char *file_name,
struct dylib_command *dl_load,
enum bool time_stamps_must_match,
uint32_t *image_pointer)
{
uint32_t i;
char *dylib_name;
struct ofile *ofile;
struct fat_arch *best_fat_arch;
struct load_command *lc;
struct dylib_command *dl_id;
enum bool already_loaded, is_framework;
char *suffix;
struct stat stat_buf;
uint32_t ncmds;
dylib_name = (char *)dl_load + dl_load->dylib.name.offset;
already_loaded = FALSE;
ofile = NULL;
for(i = 0; i < nlibs; i++){
if(strcmp(libs[i].dylib_name, dylib_name) == 0){
if(time_stamps_must_match == FALSE)
return(TRUE);
already_loaded = TRUE;
ofile = libs[i].ofile;
dylib_name = libs[i].file_name;
if(image_pointer != NULL)
*image_pointer = i;
break;
}
}
if(already_loaded == FALSE){
if(debug == TRUE)
printf("%s: loading library: %s\n", progname, dylib_name);
if(executable_path != NULL &&
strncmp(dylib_name, "@executable_path",
sizeof("@executable_path") - 1) == 0)
dylib_name = makestr(executable_path,
dylib_name + sizeof("@executable_path") - 1, NULL);
if(root_dir != NULL && *dylib_name == '/')
dylib_name = makestr(root_dir, dylib_name, NULL);
if(debug == TRUE &&
dylib_name != (char *)dl_load + dl_load->dylib.name.offset)
printf("%s: library name now: %s\n", progname, dylib_name);
if(dl_load->cmd == LC_LOAD_WEAK_DYLIB){
if(stat(dylib_name, &stat_buf) == -1){
if(image_pointer != NULL)
*image_pointer = WEAK_LIB;
return(TRUE);
}
}
if(stat(dylib_name, &stat_buf) != -1){
for(i = 0; i < nlibs; i++){
if(stat_buf.st_dev == libs[i].dev &&
stat_buf.st_ino == libs[i].ino){
if(time_stamps_must_match == FALSE)
return(TRUE);
already_loaded = TRUE;
ofile = libs[i].ofile;
dylib_name = libs[i].file_name;
if(image_pointer != NULL)
*image_pointer = i;
break;
}
}
}
if(already_loaded == FALSE){
ofile = allocate(sizeof(struct ofile));
if(ofile_map(dylib_name, NULL, NULL, ofile, FALSE) == FALSE)
redo_exit(2);
}
}
if(ofile->file_type == OFILE_FAT){
best_fat_arch = cpusubtype_findbestarch(
arch_flag.cputype,
arch_flag.cpusubtype,
ofile->fat_archs,
ofile->fat_header->nfat_arch);
if(best_fat_arch == NULL){
if(arch_cant_be_missing != 0 &&
arch_cant_be_missing != arch_flag.cputype){
if(already_loaded == FALSE)
ofile_unmap(ofile);
return(FALSE);
}
error("dynamic shared library file: %s does not contain an "
"architecture that can be used with %s (architecture %s)",
dylib_name, file_name, arch_name);
redo_exit(2);
}
(void)ofile_first_arch(ofile);
do{
if(best_fat_arch != ofile->fat_archs + ofile->narch)
continue;
if(ofile->arch_type == OFILE_ARCHIVE){
error("file: %s (for architecture %s) is an archive (not "
"a Mach-O dynamic shared library)", dylib_name,
ofile->arch_flag.name);
redo_exit(2);
}
else if(ofile->arch_type == OFILE_Mach_O){
if(ofile->mh_filetype != MH_DYLIB){
error("file: %s (for architecture %s) is not a Mach-O "
"dynamic shared library", dylib_name,
arch_name);
redo_exit(2);
}
goto good;
}
else if(ofile->arch_type == OFILE_UNKNOWN){
error("file: %s (for architecture %s) is not a Mach-O "
"dynamic shared library", dylib_name, arch_name);
redo_exit(2);
}
}while(ofile_next_arch(ofile) == TRUE);
}
else if(ofile->file_type == OFILE_ARCHIVE){
error("file: %s is an archive (not a Mach-O dynamic shared "
"library)", dylib_name);
redo_exit(2);
}
else if(ofile->file_type == OFILE_Mach_O){
if(arch_flag.cputype != ofile->mh_cputype){
if(arch_cant_be_missing != 0 &&
arch_cant_be_missing != arch_flag.cputype){
if(already_loaded == FALSE)
ofile_unmap(ofile);
return(FALSE);
}
error("dynamic shared library: %s has the wrong CPU type for: "
"%s (architecture %s)", dylib_name, file_name,
arch_name);
redo_exit(2);
}
if(cpusubtype_combine(arch_flag.cputype,
arch_flag.cpusubtype, ofile->mh_cpusubtype) == -1){
if(arch_cant_be_missing != 0 &&
arch_cant_be_missing != arch_flag.cputype){
if(already_loaded == FALSE)
ofile_unmap(ofile);
return(FALSE);
}
error("dynamic shared library: %s has the wrong CPU subtype "
"for: %s (architecture %s)", dylib_name, file_name,
arch_name);
redo_exit(2);
}
}
else{
error("file: %s is not a Mach-O dynamic shared library",
dylib_name);
redo_exit(2);
}
good:
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
if(time_stamps_must_match == TRUE
#ifdef LIBRARY_API
|| check_if_needed == TRUE
#endif
){
lc = ofile->load_commands;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_ID_DYLIB){
dl_id = (struct dylib_command *)lc;
if(dl_load->dylib.timestamp != dl_id->dylib.timestamp){
#ifdef LIBRARY_API
if(arch_cant_be_missing != 0 &&
arch_cant_be_missing != arch_flag.cputype){
if(already_loaded == FALSE)
ofile_unmap(ofile);
return(FALSE);
}
redo_prebinding_needed = TRUE;
#endif
if(time_stamps_must_match == TRUE){
if(dl_load->cmd == LC_ID_DYLIB){
error("library: %s (architecture %s) prebinding"
" not up to date with installed dynamic "
" shared library: %s", file_name,
arch_name, dylib_name);
redo_exit(1);
}
else{
error("library: %s (architecture %s) prebinding"
" not up to date with dependent dynamic "
"shared library: %s", file_name,arch_name,
dylib_name);
redo_exit(3);
}
}
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
else if(check_only == TRUE){
lc = ofile->load_commands;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_ID_DYLIB){
dl_id = (struct dylib_command *)lc;
if(dl_load->dylib.timestamp != dl_id->dylib.timestamp){
redo_exit(1);
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
if(already_loaded == FALSE &&
(dl_load->cmd == LC_LOAD_DYLIB ||
dl_load->cmd == LC_LOAD_WEAK_DYLIB ||
dl_load->cmd == LC_REEXPORT_DYLIB)){
libs = reallocate(libs, (nlibs + 1) * sizeof(struct lib));
memset(libs + nlibs, '\0', sizeof(struct lib));
libs[nlibs].file_name = dylib_name;
lc = ofile->load_commands;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_ID_DYLIB){
dl_id = (struct dylib_command *)lc;
libs[nlibs].dylib_name = (char *)dl_id +
dl_id->dylib.name.offset;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
libs[nlibs].umbrella_name = guess_short_name(libs[nlibs].dylib_name,
&is_framework,
&suffix);
if(is_framework == TRUE){
libs[nlibs].name_size = strlen(libs[nlibs].umbrella_name);
}
else{
if(libs[nlibs].umbrella_name != NULL){
libs[nlibs].library_name = libs[nlibs].umbrella_name;
libs[nlibs].umbrella_name = NULL;
libs[nlibs].name_size = strlen(libs[nlibs].library_name);
}
}
if(suffix != NULL)
free(suffix);
libs[nlibs].ofile = ofile;
libs[nlibs].dev = stat_buf.st_dev;
libs[nlibs].ino = stat_buf.st_ino;
if(image_pointer != NULL)
*image_pointer = nlibs;
nlibs++;
}
return(TRUE);
}
static
void
check_for_overlapping_segments(
uint32_t vmslide)
{
uint32_t i, j;
struct segment *segments;
uint32_t nsegments;
struct load_command *lc;
struct segment_command *sg;
uint32_t ncmds;
segments = NULL;
nsegments = 0;
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
segments = reallocate(segments,
(nsegments + 1) * sizeof(struct segment));
segments[nsegments].file_name = arch->file_name;
segments[nsegments].sg = *sg;
segments[nsegments].sg.vmaddr += vmslide;
nsegments++;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
for(i = 0; i < nlibs; i++){
lc = libs[i].ofile->load_commands;
if(libs[i].ofile->mh != NULL)
ncmds = libs[i].ofile->mh->ncmds;
else
ncmds = libs[i].ofile->mh64->ncmds;
for(j = 0; j < ncmds; j++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
segments = reallocate(segments,
(nsegments + 1) * sizeof(struct segment));
segments[nsegments].file_name = libs[i].file_name;
segments[nsegments].sg = *sg;
nsegments++;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
for(i = 0; i < nsegments; i++){
for(j = i + 1; j < nsegments; j++){
check_overlap(segments + i, segments + j);
}
}
}
static
void
check_overlap(
struct segment *s1,
struct segment *s2)
{
if(s1->sg.vmsize == 0 || s2->sg.vmsize == 0)
return;
if(s1->sg.vmaddr > s2->sg.vmaddr){
if(s2->sg.vmaddr + s2->sg.vmsize <= s1->sg.vmaddr)
return;
}
else{
if(s1->sg.vmaddr + s1->sg.vmsize <= s2->sg.vmaddr)
return;
}
error("prebinding can't be redone because %.16s segment (address = 0x%x"
" size = 0x%x) of %s overlaps with %.16s segment (address = 0x%x "
"size = 0x%x) of %s (for architecture %s)",
s1->sg.segname, (unsigned int)(s1->sg.vmaddr),
(unsigned int)(s1->sg.vmsize), s1->file_name,
s2->sg.segname, (unsigned int)(s2->sg.vmaddr),
(unsigned int)(s2->sg.vmsize), s2->file_name,
arch_name);
redo_exit(2);
}
static
void
setup_symbolic_info(
enum bool missing_arch)
{
uint32_t i, j, nlibrefs;
enum byte_sex host_byte_sex;
struct load_command *lc;
uint32_t ncmds;
host_byte_sex = get_host_byte_sex();
arch_swapped = arch->object->object_byte_sex != host_byte_sex;
if(arch->object->st == NULL){
error("malformed file: %s (no LC_SYMTAB load command) (for"
" architecture %s)", arch->file_name, arch_name);
redo_exit(2);
}
if(arch->object->dyst == NULL){
error("malformed file: %s (no LC_DYSYMTAB load command) (for"
" architecture %s)", arch->file_name, arch_name);
redo_exit(2);
}
arch_nsyms = arch->object->st->nsyms;
if(arch->object->mh != NULL){
arch_symbols = (struct nlist *)(arch->object->object_addr +
arch->object->st->symoff);
arch_symbols64 = NULL;
if(arch_swapped == TRUE)
swap_nlist(arch_symbols, arch_nsyms, host_byte_sex);
}
else{
arch_symbols = NULL;
arch_symbols64 = (struct nlist_64 *)(arch->object->object_addr +
arch->object->st->symoff);
if(arch_swapped == TRUE)
swap_nlist_64(arch_symbols64, arch_nsyms, host_byte_sex);
}
arch_strings = arch->object->object_addr + arch->object->st->stroff;
arch_strsize = arch->object->st->strsize;
if(arch->object->hints_cmd != NULL &&
arch->object->hints_cmd->nhints != 0){
arch_hints = (struct twolevel_hint *)
(arch->object->object_addr +
arch->object->hints_cmd->offset);
arch_nhints = arch->object->hints_cmd->nhints;
if(arch_swapped == TRUE)
swap_twolevel_hint(arch_hints, arch_nhints, host_byte_sex);
}
arch_extrelocs = (struct relocation_info *)
(arch->object->object_addr +
arch->object->dyst->extreloff);
arch_nextrel = arch->object->dyst->nextrel;
if(arch_swapped == TRUE)
swap_relocation_info(arch_extrelocs, arch_nextrel, host_byte_sex);
arch_locrelocs = (struct relocation_info *)
(arch->object->object_addr +
arch->object->dyst->locreloff);
arch_nlocrel = arch->object->dyst->nlocrel;
if(arch_swapped == TRUE)
swap_relocation_info(arch_locrelocs, arch_nlocrel, host_byte_sex);
arch_indirect_symtab = (uint32_t *)
(arch->object->object_addr +
arch->object->dyst->indirectsymoff);
arch_nindirectsyms = arch->object->dyst->nindirectsyms;
if(arch_swapped == TRUE)
swap_indirect_symbols(arch_indirect_symtab, arch_nindirectsyms,
host_byte_sex);
if(arch->object->mh_filetype == MH_DYLIB){
arch_tocs = (struct dylib_table_of_contents *)
(arch->object->object_addr +
arch->object->dyst->tocoff);
arch_ntoc = arch->object->dyst->ntoc;
if(arch->object->mh != NULL){
arch_mods = (struct dylib_module *)
(arch->object->object_addr +
arch->object->dyst->modtaboff);
arch_mods64 = NULL;
}
else{
arch_mods = NULL;
arch_mods64 = (struct dylib_module_64 *)
(arch->object->object_addr +
arch->object->dyst->modtaboff);
}
arch_nmodtab = arch->object->dyst->nmodtab;
arch_refs = (struct dylib_reference *)
(arch->object->object_addr +
arch->object->dyst->extrefsymoff);
arch_nextrefsyms = arch->object->dyst->nextrefsyms;
if(arch_swapped == TRUE){
swap_dylib_table_of_contents(
arch_tocs, arch_ntoc, host_byte_sex);
if(arch->object->mh != NULL)
swap_dylib_module(
arch_mods, arch_nmodtab, host_byte_sex);
else
swap_dylib_module_64(
arch_mods64, arch_nmodtab, host_byte_sex);
swap_dylib_reference(
arch_refs, arch_nextrefsyms, host_byte_sex);
}
}
else{
arch_tocs = NULL;
arch_ntoc = 0;;
arch_mods = NULL;
arch_mods64 = NULL;
arch_nmodtab = 0;;
arch_refs = NULL;
arch_nextrefsyms = 0;;
}
nlibrefs = 0;
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_LOAD_DYLIB ||
lc->cmd == LC_LOAD_WEAK_DYLIB ||
lc->cmd == LC_REEXPORT_DYLIB){
nlibrefs++;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
check_symbolic_info_tables(
arch->file_name,
arch->object->mh,
arch->object->mh64,
nlibrefs,
arch->object->st,
arch->object->dyst,
arch_symbols,
arch_symbols64,
arch_nsyms,
arch_strings,
arch_strsize,
arch_tocs,
arch_ntoc,
arch_mods,
arch_mods64,
arch_nmodtab,
arch_refs,
arch_nextrefsyms);
if(missing_arch == TRUE)
return;
for(i = 0; i < nlibs; i++){
libs[i].st = NULL;
libs[i].dyst = NULL;
nlibrefs = 0;
lc = libs[i].ofile->load_commands;
if(libs[i].ofile->mh != NULL)
ncmds = libs[i].ofile->mh->ncmds;
else
ncmds = libs[i].ofile->mh64->ncmds;
for(j = 0; j < ncmds; j++){
if(lc->cmd == LC_SYMTAB){
if(libs[i].st != NULL){
error("malformed library: %s (more than one LC_SYMTAB "
"load command) (for architecture %s)",
libs[i].file_name, arch_name);
redo_exit(2);
}
libs[i].st = (struct symtab_command *)lc;
}
else if(lc->cmd == LC_DYSYMTAB){
if(libs[i].dyst != NULL){
error("malformed library: %s (more than one LC_DYSYMTAB"
" load command) (for architecture %s)",
libs[i].file_name, arch_name);
redo_exit(2);
}
libs[i].dyst = (struct dysymtab_command *)lc;
}
else if(lc->cmd == LC_ROUTINES){
if(libs[i].rc != NULL){
error("malformed library: %s (more than one LC_ROUTINES"
" load command) (for architecture %s)",
libs[i].file_name, arch_name);
redo_exit(2);
}
libs[i].rc = (struct routines_command *)lc;
}
else if(lc->cmd == LC_LOAD_DYLIB ||
lc->cmd == LC_LOAD_WEAK_DYLIB ||
lc->cmd == LC_REEXPORT_DYLIB){
nlibrefs++;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(libs[i].st == NULL){
error("malformed file: %s (no LC_SYMTAB load command) (for"
" architecture %s)", libs[i].file_name, arch_name);
redo_exit(2);
}
if(libs[i].dyst == NULL){
error("malformed file: %s (no LC_DYSYMTAB load command) (for"
" architecture %s)", libs[i].file_name, arch_name);
redo_exit(2);
}
if(libs[i].ofile->mh != NULL){
libs[i].symbols = (struct nlist *)
(libs[i].ofile->object_addr + libs[i].st->symoff);
libs[i].symbols64 = NULL;
libs[i].mods = (struct dylib_module *)
(libs[i].ofile->object_addr + libs[i].dyst->modtaboff);
libs[i].mods64 = NULL;
}
else{
libs[i].symbols = NULL;
libs[i].symbols64 = (struct nlist_64 *)
(libs[i].ofile->object_addr + libs[i].st->symoff);
libs[i].mods = NULL;
libs[i].mods64 = (struct dylib_module_64 *)
(libs[i].ofile->object_addr + libs[i].dyst->modtaboff);
}
libs[i].nsyms = libs[i].st->nsyms;
libs[i].strings = libs[i].ofile->object_addr + libs[i].st->stroff;
libs[i].strsize = libs[i].st->strsize;
libs[i].tocs = (struct dylib_table_of_contents *)
(libs[i].ofile->object_addr + libs[i].dyst->tocoff);
libs[i].ntoc = libs[i].dyst->ntoc;
libs[i].nmodtab = libs[i].dyst->nmodtab;
libs[i].refs = (struct dylib_reference *)
(libs[i].ofile->object_addr +
libs[i].dyst->extrefsymoff);
libs[i].nextrefsyms = libs[i].dyst->nextrefsyms;
if(arch_swapped == TRUE){
if(libs[i].ofile->mh != NULL){
swap_nlist(
libs[i].symbols, libs[i].nsyms, host_byte_sex);
swap_dylib_module(
libs[i].mods, libs[i].nmodtab, host_byte_sex);
}
else{
swap_nlist_64(
libs[i].symbols64, libs[i].nsyms, host_byte_sex);
swap_dylib_module_64(
libs[i].mods64, libs[i].nmodtab, host_byte_sex);
}
swap_dylib_table_of_contents(
libs[i].tocs, libs[i].ntoc, host_byte_sex);
swap_dylib_reference(
libs[i].refs, libs[i].nextrefsyms, host_byte_sex);
}
check_symbolic_info_tables(
libs[i].file_name,
libs[i].ofile->mh,
libs[i].ofile->mh64,
nlibrefs,
libs[i].st,
libs[i].dyst,
libs[i].symbols,
libs[i].symbols64,
libs[i].nsyms,
libs[i].strings,
libs[i].strsize,
libs[i].tocs,
libs[i].ntoc,
libs[i].mods,
libs[i].mods64,
libs[i].nmodtab,
libs[i].refs,
libs[i].nextrefsyms);
libs[i].module_states = allocate(libs[i].nmodtab *
sizeof(enum link_state));
memset(libs[i].module_states, '\0',
libs[i].nmodtab * sizeof(enum link_state));
}
}
static
void
swap_arch_for_output(
void)
{
if(arch_symbols != NULL)
swap_nlist(arch_symbols, arch_nsyms,
arch->object->object_byte_sex);
if(arch_symbols64 != NULL)
swap_nlist_64(arch_symbols64, arch_nsyms,
arch->object->object_byte_sex);
swap_relocation_info(arch_extrelocs, arch_nextrel,
arch->object->object_byte_sex);
swap_relocation_info(arch_locrelocs, arch_nlocrel,
arch->object->object_byte_sex);
swap_indirect_symbols(arch_indirect_symtab, arch_nindirectsyms,
arch->object->object_byte_sex);
swap_dylib_table_of_contents(arch_tocs, arch_ntoc,
arch->object->object_byte_sex);
if(arch_mods != NULL)
swap_dylib_module(arch_mods, arch_nmodtab,
arch->object->object_byte_sex);
if(arch_mods64 != NULL)
swap_dylib_module_64(arch_mods64, arch_nmodtab,
arch->object->object_byte_sex);
swap_dylib_reference(arch_refs, arch_nextrefsyms,
arch->object->object_byte_sex);
swap_twolevel_hint(arch_hints, arch_nhints,
arch->object->object_byte_sex);
}
static
void
check_symbolic_info_tables(
char *file_name,
struct mach_header *mh,
struct mach_header_64 *mh64,
uint32_t nlibrefs,
struct symtab_command *st,
struct dysymtab_command *dyst,
struct nlist *symbols,
struct nlist_64 *symbols64,
uint32_t nsyms,
char *strings,
uint32_t strsize,
struct dylib_table_of_contents *tocs,
uint32_t ntoc,
struct dylib_module *mods,
struct dylib_module_64 *mods64,
uint32_t nmodtab,
struct dylib_reference *refs,
uint32_t nextrefsyms)
{
uint32_t i;
uint32_t mh_flags, mh_filetype, n_strx, module_name, nextdefsym, iextdefsym;
uint8_t n_type;
uint64_t n_value;
uint16_t n_desc;
if(mh != NULL){
mh_filetype = mh->filetype;
mh_flags = mh->flags;
}
else{
mh_filetype = mh64->filetype;
mh_flags = mh64->flags;
}
for(i = 0; i < nsyms; i++){
if(mh != NULL){
n_strx = symbols[i].n_un.n_strx;
n_type = symbols[i].n_type;
n_value = symbols[i].n_value;
n_desc = symbols[i].n_desc;
}
else{
n_strx = symbols64[i].n_un.n_strx;
n_type = symbols64[i].n_type;
n_value = symbols64[i].n_value;
n_desc = symbols64[i].n_desc;
}
if(n_strx > strsize){
error("malformed file: %s (bad string table index (%d) for "
"symbol %u) (for architecture %s)", file_name,
n_strx, i, arch_name);
redo_exit(2);
}
if((n_type & N_TYPE) == N_INDR && n_value > strsize){
error("malformed file: %s (bad string table index (%llu) for "
"N_INDR symbol %u) (for architecture %s)", file_name,
n_value, i, arch_name);
redo_exit(2);
}
if((mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL &&
(n_type & N_STAB) == 0 &&
(n_type & N_TYPE) == N_PBUD){
if(mh_filetype == MH_DYLIB){
if(GET_LIBRARY_ORDINAL(n_desc) !=
SELF_LIBRARY_ORDINAL &&
(uint32_t)GET_LIBRARY_ORDINAL(n_desc)
- 1 > nlibrefs){
error("malformed file: %s (bad LIBRARY_ORDINAL (%d) "
"for symbol %u %s) (for architecture %s)",
file_name, GET_LIBRARY_ORDINAL(n_desc),
i, strings + n_strx, arch_name);
redo_exit(2);
}
}
else if(mh_filetype == MH_EXECUTE){
if(GET_LIBRARY_ORDINAL(n_desc) ==
SELF_LIBRARY_ORDINAL ||
(uint32_t)GET_LIBRARY_ORDINAL(n_desc)
- 1 > nlibrefs){
error("malformed file: %s (bad LIBRARY_ORDINAL (%d) "
"for symbol %u %s) (for architecture %s)",
file_name, GET_LIBRARY_ORDINAL(n_desc),
i, strings + n_strx, arch_name);
redo_exit(2);
}
}
}
}
for(i = 0; i < ntoc; i++){
if(tocs[i].symbol_index > nsyms){
error("malformed file: %s (bad symbol table index (%d) for "
"table of contents entry %u) (for architecture %s)",
file_name, tocs[i].symbol_index, i, arch_name);
redo_exit(2);
}
if(tocs[i].module_index > nmodtab){
error("malformed file: %s (bad module table index (%d) for "
"table of contents entry %u) (for architecture %s)",
file_name, tocs[i].module_index, i, arch_name);
redo_exit(2);
}
}
for(i = 0; i < nmodtab; i++){
if(mh != NULL){
module_name = mods[i].module_name;
nextdefsym = mods[i].nextdefsym;
iextdefsym = mods[i].iextdefsym;
nextdefsym = mods[i].nextdefsym;
iextdefsym = mods[i].iextdefsym;
}
else{
module_name = mods64[i].module_name;
nextdefsym = mods64[i].nextdefsym;
iextdefsym = mods64[i].iextdefsym;
nextdefsym = mods[i].nextdefsym;
iextdefsym = mods[i].iextdefsym;
}
if(module_name > strsize){
error("malformed file: %s (bad string table index (%d) for "
"module_name in module table entry %u ) (for "
"architecture %s)", file_name, module_name, i,
arch_name);
redo_exit(2);
}
if(nextdefsym != 0 &&
(iextdefsym < dyst->iextdefsym ||
iextdefsym >= dyst->iextdefsym + dyst->nextdefsym)){
error("malformed file: %s (bad external symbol table index for"
" for module table entry %u) (for architecture %s)",
file_name, i, arch_name);
redo_exit(2);
}
if(nextdefsym != 0 &&
iextdefsym + nextdefsym > dyst->iextdefsym + dyst->nextdefsym){
error("malformed file: %s (bad number of external symbol table"
" entries for module table entry %u) (for architecture "
"%s)", file_name, i, arch_name);
redo_exit(2);
}
}
for(i = 0; i < nextrefsyms; i++){
if(refs[i].isym > nsyms){
error("malformed file: %s (bad external symbol table index "
"reference table entry %u) (for architecture %s)",
file_name, i, arch_name);
redo_exit(2);
}
}
}
static
void
check_for_dylib_override_symbols(
void)
{
uint32_t i;
for(i = arch->object->dyst->iextdefsym;
i < arch->object->dyst->iextdefsym + arch->object->dyst->nextdefsym;
i++){
check_dylibs_for_definition(
arch->file_name, arch_strings + arch_symbols[i].n_un.n_strx);
}
}
static
void
check_dylibs_for_definition(
char *file_name,
char *symbol_name)
{
uint32_t i;
struct dylib_table_of_contents *toc;
uint32_t mh_flags;
for(i = 0; i < nlibs; i++){
if(libs[i].ofile->mh != NULL)
mh_flags = libs[i].ofile->mh->flags;
else
mh_flags = libs[i].ofile->mh64->flags;
if(arch_force_flat_namespace == FALSE &&
(mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL)
continue;
bsearch_strings = libs[i].strings;
bsearch_symbols = libs[i].symbols;
toc = bsearch(symbol_name, libs[i].tocs, libs[i].ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))dylib_bsearch);
if(toc != NULL){
if(check_dylibs_for_reference(symbol_name) == TRUE){
error("prebinding can't be redone because of symbols "
"overridden in dependent dynamic shared libraries (%s "
"defined in: %s and in %s(%s)) (for architecture %s)",
symbol_name, file_name, libs[i].file_name,
libs[i].strings +
libs[i].mods[toc->module_index].module_name,
arch_name);
redo_exit(2);
}
}
}
}
static
enum bool
check_dylibs_for_reference(
char *symbol_name)
{
uint32_t i, j, symbol_index;
struct dylib_table_of_contents *toc;
struct nlist *symbol;
uint32_t mh_flags;
for(i = 0; i < nlibs; i++){
if(libs[i].ofile->mh != NULL)
mh_flags = libs[i].ofile->mh->flags;
else
mh_flags = libs[i].ofile->mh64->flags;
if(arch_force_flat_namespace == FALSE &&
(mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL)
continue;
bsearch_strings = libs[i].strings;
bsearch_symbols = libs[i].symbols;
toc = bsearch(symbol_name, libs[i].tocs, libs[i].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(symbol_name,
libs[i].symbols + libs[i].dyst->iundefsym,
libs[i].dyst->nundefsym,
sizeof(struct nlist),
(int (*)(const void *,const void *))nlist_bsearch);
if(symbol == NULL)
continue;
symbol_index = symbol - libs[i].symbols;
}
for(j = 0; j < libs[i].nextrefsyms; j++){
if(libs[i].refs[j].isym == symbol_index &&
(libs[i].refs[j].flags ==
REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
libs[i].refs[j].flags ==
REFERENCE_FLAG_UNDEFINED_LAZY))
return(TRUE);
}
}
return(FALSE);
}
static
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));
}
static
void
setup_initial_undefined_list(
void)
{
uint32_t i;
uint32_t mh_flags;
for(i = arch->object->dyst->iundefsym;
i < arch->object->dyst->iundefsym + arch->object->dyst->nundefsym;
i++){
add_to_undefined_list(
arch_strings + arch_symbols[i].n_un.n_strx,
arch_symbols + i,
ARCH_LIB);
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE){
arch_symbols[i].n_type &= ~N_TYPE;
arch_symbols[i].n_type |= N_PBUD;
}
}
}
static
void
link_in_need_modules(
void)
{
struct symbol_list *undefined, *next_undefined;
struct nlist *symbol;
enum link_state *module_state;
struct lib *lib;
for(undefined = undefined_list.next;
undefined != &undefined_list;
){
lookup_symbol(undefined->name,
get_primary_lib(undefined->ilib, undefined->symbol),
get_weak(undefined->symbol),
&symbol, &module_state, &lib, NULL, NULL,
NO_INDR_LOOP);
if(symbol != NULL){
next_undefined = undefined->next;
undefined->prev->next = undefined->next;
undefined->next->prev = undefined->prev;
undefined = next_undefined;
if(*module_state == UNLINKED)
link_library_module(module_state, lib);
if(undefined == &undefined_list &&
undefined->next != &undefined_list)
undefined = undefined->next;
}
else{
undefined = undefined->next;
}
}
if(undefined_list.next != &undefined_list){
#ifndef LIBRARY_API
printf("%s: ", progname);
#endif
message("prebinding can't be redone for: %s (for architecture "
"%s) because of undefined symbols:\n",
arch->file_name, arch_name);
for(undefined = undefined_list.next;
undefined != &undefined_list;
undefined = undefined->next){
message("%s\n", undefined->name);
}
redo_exit(2);
}
}
static
void
link_library_module(
enum link_state *module_state,
struct lib *lib)
{
uint32_t i, j, module_index, ilib;
struct dylib_module *dylib_module;
char *name;
struct nlist *prev_symbol;
enum link_state *prev_module_state;
struct lib *prev_lib;
struct nlist *ref_symbol;
enum link_state *ref_module_state;
struct lib *ref_lib;
uint32_t mh_flags;
module_index = module_state - lib->module_states;
dylib_module = lib->mods + module_index;
ilib = lib - libs;
if(lib->ofile->mh != NULL)
mh_flags = lib->ofile->mh->flags;
else
mh_flags = lib->ofile->mh64->flags;
if(arch_force_flat_namespace == FALSE &&
(mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL){
goto add_undefineds;
}
for(i = dylib_module->iextdefsym;
i < dylib_module->iextdefsym + dylib_module->nextdefsym;
i++){
name = lib->strings + lib->symbols[i].n_un.n_strx;
lookup_symbol(name,
get_primary_lib(ilib, lib->symbols + i),
get_weak(lib->symbols + i),
&prev_symbol, &prev_module_state, &prev_lib,
NULL, NULL, NO_INDR_LOOP);
if(prev_symbol != NULL &&
module_state != prev_module_state &&
*prev_module_state != UNLINKED){
#ifndef LIBRARY_API
printf("%s: ", progname);
#endif
message("prebinding can't be redone for: %s (for "
"architecture %s) because of multiply defined "
"symbol: %s\n", arch->file_name, arch_name, name);
if(prev_module_state == &arch_state)
message("%s definition of %s\n", arch->file_name, name);
else
message("%s(%s) definition of %s\n", prev_lib->file_name,
prev_lib->strings +
prev_lib->mods[
prev_module_state - prev_lib->module_states].
module_name, name);
if(module_state == &arch_state)
message("%s definition of %s\n", arch->file_name, name);
else
message("%s(%s) definition of %s\n", lib->file_name,
lib->strings + dylib_module->module_name, name);
redo_exit(2);
}
}
add_undefineds:
for(i = dylib_module->irefsym;
i < dylib_module->irefsym + dylib_module->nrefsym;
i++){
if(lib->refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
lib->refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
name = lib->strings +
lib->symbols[lib->refs[i].isym].n_un.n_strx;
lookup_symbol(name,
get_primary_lib(ilib, lib->symbols +
lib->refs[i].isym),
get_weak(lib->symbols + lib->refs[i].isym),
&ref_symbol, &ref_module_state, &ref_lib,
NULL, NULL, NO_INDR_LOOP);
if(ref_symbol != NULL){
if(*ref_module_state == UNLINKED)
add_to_undefined_list(name,
lib->symbols + lib->refs[i].isym,
ilib);
}
else{
add_to_undefined_list(name,
lib->symbols + lib->refs[i].isym,
ilib);
}
}
else{
if(lib->refs[i].flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
lib->refs[i].flags ==
REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
for(j = 0; j < lib->nmodtab; j++){
if(lib->refs[i].isym >= lib->mods[j].ilocalsym &&
lib->refs[i].isym <
lib->mods[j].ilocalsym + lib->mods[j].nlocalsym)
break;
}
if(j < lib->nmodtab){
if(lib->module_states[j] == UNLINKED){
lib->module_states[j] = LINKED;
link_library_module(lib->module_states + j, lib);
}
}
}
}
}
*module_state = LINKED;
if(lib->rc != NULL &&
lib->module_states[lib->rc->init_module] == UNLINKED){
link_library_module(lib->module_states + lib->rc->init_module, lib);
}
}
static
void
add_to_undefined_list(
char *name,
struct nlist *symbol,
uint32_t ilib)
{
struct symbol_list *undefined, *new;
for(undefined = undefined_list.next;
undefined != &undefined_list;
undefined = undefined->next){
if(undefined->name == name)
return;
}
new = allocate(sizeof(struct symbol_list));
new->name = name;
new->symbol = symbol;
new->ilib = ilib;
new->prev = undefined_list.prev;
new->next = &undefined_list;
undefined_list.prev->next = new;
undefined_list.prev = new;
}
static
struct lib *
get_primary_lib(
uint32_t ilib,
struct nlist *symbol)
{
struct lib *lib;
uint32_t mh_flags;
if(arch_force_flat_namespace == TRUE)
return(NULL);
if(ilib == ARCH_LIB){
lib = &arch_lib;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
}
else if(ilib == WEAK_LIB){
return(&weak_lib);
}
else{
lib = libs + ilib;
if(lib->ofile->mh != NULL)
mh_flags = lib->ofile->mh->flags;
else
mh_flags = lib->ofile->mh64->flags;
}
if((mh_flags & MH_TWOLEVEL) != MH_TWOLEVEL)
return(NULL);
if(GET_LIBRARY_ORDINAL(symbol->n_desc) == EXECUTABLE_ORDINAL)
return(NULL);
if(lib->ndependent_images != DYNAMIC_LOOKUP_ORDINAL &&
GET_LIBRARY_ORDINAL(symbol->n_desc) == DYNAMIC_LOOKUP_ORDINAL)
return(NULL);
if(GET_LIBRARY_ORDINAL(symbol->n_desc) == SELF_LIBRARY_ORDINAL)
return(libs + ilib);
if(lib->dependent_images[GET_LIBRARY_ORDINAL(symbol->n_desc) - 1] ==
WEAK_LIB)
return(&weak_lib);
return(libs +
lib->dependent_images[GET_LIBRARY_ORDINAL(symbol->n_desc) - 1]);
}
static
struct lib *
get_indr_lib(
char *symbol_name,
struct lib *lib)
{
struct dysymtab_command *dyst;
struct nlist *symbols, *symbol;
struct dylib_table_of_contents *tocs, *toc;
uint32_t symbol_index;
struct lib *indr_lib;
char *file_name;
uint32_t mh_flags, mh_filetype;
if(lib == &arch_lib) {
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
mh_filetype = arch->object->mh_filetype;
} else {
if(lib->ofile->mh != NULL)
mh_flags = lib->ofile->mh->flags;
else
mh_flags = lib->ofile->mh64->flags;
mh_filetype = lib->ofile->mh_filetype;
}
if(arch_force_flat_namespace == TRUE ||
(mh_flags & MH_TWOLEVEL) != MH_TWOLEVEL)
return(NULL);
if(lib == &arch_lib && mh_filetype != MH_DYLIB){
bsearch_strings = arch_strings;
symbol = bsearch(symbol_name,
arch_symbols + arch->object->dyst->iundefsym,
arch->object->dyst->nundefsym,
sizeof(struct nlist),
(int (*)(const void *,const void *))nlist_bsearch);
if(symbol == NULL){
error("malformed file: %s (table of contents or " "undefined symbol list) N_INDR symbol %s not "
"found (for architecture %s)", arch->file_name,
symbol_name, arch_name);
redo_exit(2);
}
indr_lib = get_primary_lib(ARCH_LIB, symbol);
}
else{
if(lib == &arch_lib){
tocs = arch_tocs;
bsearch_strings = arch_strings;
bsearch_symbols = arch_symbols;
symbols = arch_symbols;
dyst = arch->object->dyst;
file_name = arch->file_name;
}
else{
tocs = lib->tocs;
bsearch_strings = lib->strings;
bsearch_symbols = lib->symbols;
symbols = lib->symbols;
dyst = lib->dyst;
file_name = lib->file_name;
}
toc = bsearch(symbol_name, tocs, dyst->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(symbol_name, symbols + dyst->iundefsym,
dyst->nundefsym, sizeof(struct nlist),
(int (*)(const void *,const void *))nlist_bsearch);
if(symbol == NULL){
error("malformed file: %s (table of contents or " "undefined symbol list) N_INDR symbol %s not "
"found (for architecture %s)", file_name,
symbol_name, arch_name);
redo_exit(2);
}
symbol_index = symbol - symbols;
}
indr_lib = get_primary_lib(libs - lib, symbols + symbol_index);
}
return(indr_lib);
}
static
enum bool
get_weak(
struct nlist *symbol)
{
if(symbol != NULL && (symbol->n_desc & N_WEAK_REF) == N_WEAK_REF)
return(TRUE);
return(FALSE);
}
static
void
lookup_symbol(
char *name,
struct lib *primary_lib,
enum bool weak,
struct nlist **symbol,
enum link_state **module_state,
struct lib **lib,
uint32_t *isub_image,
uint32_t *itoc,
struct indr_loop_list *indr_loop)
{
uint32_t i;
if(isub_image != NULL)
*isub_image = 0;
if(itoc != NULL)
*itoc = 0;
if(primary_lib != NULL){
if(primary_lib == &weak_lib){
weak = TRUE;
goto weak_library_symbol;
}
if(primary_lib == &arch_lib){
if(lookup_symbol_in_arch(name, symbol, module_state, lib,
isub_image, itoc, indr_loop) == TRUE)
return;
}
else{
if(lookup_symbol_in_lib(name, primary_lib, symbol, module_state,
lib, isub_image, itoc, indr_loop) == TRUE)
return;
}
for(i = 0; i < primary_lib->nsub_images; i++){
if(lookup_symbol_in_lib(name, libs + primary_lib->sub_images[i],
symbol, module_state, lib, isub_image,
itoc, indr_loop) == TRUE){
if(isub_image != NULL)
*isub_image = i + 1;
return;
}
}
weak_library_symbol:
if(weak == TRUE){
*symbol = &weak_symbol;
*module_state = &weak_module;
*lib = primary_lib;
return;
}
*symbol = NULL;
*module_state = NULL;
*lib = NULL;
return;
}
if(lookup_symbol_in_arch(name, symbol, module_state, lib, isub_image,
itoc, indr_loop) == TRUE)
return;
for(i = 0; i < nlibs; i++){
if(lookup_symbol_in_lib(name, libs + i, symbol, module_state, lib,
isub_image, itoc, indr_loop) == TRUE)
return;
}
if(weak == TRUE){
*symbol = &weak_symbol;
*module_state = &weak_module;
*lib = primary_lib;
return;
}
*symbol = NULL;
*module_state = NULL;
*lib = NULL;
return;
}
static
enum bool
lookup_symbol_in_arch(
char *name,
struct nlist **symbol,
enum link_state **module_state,
struct lib **lib,
uint32_t *isub_image,
uint32_t *itoc,
struct indr_loop_list *indr_loop)
{
struct dylib_table_of_contents *toc;
struct nlist *s;
struct indr_loop_list new_indr_loop, *loop;
if(arch->object->mh_filetype == MH_DYLIB){
bsearch_strings = arch_strings;
bsearch_symbols = arch_symbols;
toc = bsearch(name, arch_tocs, arch_ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))dylib_bsearch);
if(toc != NULL){
*symbol = arch_symbols + toc->symbol_index;
if(((*symbol)->n_type & N_TYPE) == N_INDR){
name = (*symbol)->n_value + arch_strings;
goto indr;
}
*module_state = &arch_state;
*lib = NULL;
if(itoc != NULL)
*itoc = toc - arch_tocs;
return(TRUE);
}
}
else{
bsearch_strings = arch_strings;
s = bsearch(name,
arch_symbols + arch->object->dyst->iextdefsym,
arch->object->dyst->nextdefsym,
sizeof(struct nlist),
(int (*)(const void *,const void *))nlist_bsearch);
if(s != NULL){
*symbol = s;
if(((*symbol)->n_type & N_TYPE) == N_INDR){
name = (*symbol)->n_value + arch_strings;
goto indr;
}
*module_state = &arch_state;
*lib = NULL;
return(TRUE);
}
}
*symbol = NULL;
*module_state = NULL;
*lib = NULL;
return(FALSE);
indr:
if(indr_loop != NO_INDR_LOOP){
for(loop = indr_loop; loop != NULL; loop = loop->next){
if(loop->symbol == *symbol){
*symbol = NULL;
*module_state = NULL;
*lib = NULL;
return(FALSE);
}
}
}
new_indr_loop.symbol = *symbol;
new_indr_loop.next = indr_loop;
lookup_symbol(name, get_indr_lib(name, &arch_lib), FALSE, symbol,
module_state, lib, isub_image, itoc, &new_indr_loop);
return(symbol != NULL);
}
static
enum bool
lookup_symbol_in_lib(
char *name,
struct lib *primary_lib,
struct nlist **symbol,
enum link_state **module_state,
struct lib **lib,
uint32_t *isub_image,
uint32_t *itoc,
struct indr_loop_list *indr_loop)
{
struct dylib_table_of_contents *toc;
struct indr_loop_list new_indr_loop, *loop;
bsearch_strings = primary_lib->strings;
bsearch_symbols = primary_lib->symbols;
toc = bsearch(name, primary_lib->tocs, primary_lib->ntoc,
sizeof(struct dylib_table_of_contents),
(int (*)(const void *, const void *))dylib_bsearch);
if(toc != NULL){
*symbol = primary_lib->symbols + toc->symbol_index;
if(((*symbol)->n_type & N_TYPE) == N_INDR){
name = (*symbol)->n_value + primary_lib->strings;
goto indr;
}
*module_state = primary_lib->module_states + toc->module_index;
*lib = primary_lib;
if(itoc != NULL)
*itoc = toc - primary_lib->tocs;
return(TRUE);
}
*symbol = NULL;
*module_state = NULL;
*lib = NULL;
return(FALSE);
indr:
if(indr_loop != NO_INDR_LOOP){
for(loop = indr_loop; loop != NULL; loop = loop->next){
if(loop->symbol == *symbol){
*symbol = NULL;
*module_state = NULL;
*lib = NULL;
return(FALSE);
}
}
}
new_indr_loop.symbol = *symbol;
new_indr_loop.next = indr_loop;
lookup_symbol(name, get_indr_lib(name, primary_lib), FALSE, symbol,
module_state, lib, isub_image, itoc, &new_indr_loop);
return(symbol != NULL);
}
static
void
build_new_symbol_table(
uint32_t vmslide,
enum bool missing_arch)
{
uint32_t i, j, sym_info_size, ihint, isub_image, itoc, objc_slide;
uint32_t lowest_objc_module_info_addr;
struct load_command *lc;
struct segment_command *sg;
struct section *s, *s_objc;
char *symbol_name, *dot;
struct nlist *new_symbols;
struct nlist_64 *new_symbols64;
struct nlist *symbol;
enum link_state *module_state;
struct lib *lib;
sym_info_size =
arch_nextrel * sizeof(struct relocation_info) +
arch_nlocrel * sizeof(struct relocation_info) +
arch_ntoc * sizeof(struct dylib_table_of_contents) +
arch_nextrefsyms * sizeof(struct dylib_reference) +
arch_strsize;
if(arch->object->mh != NULL){
sym_info_size +=
arch_nmodtab * sizeof(struct dylib_module) +
arch_nsyms * sizeof(struct nlist) +
arch_nindirectsyms * sizeof(uint32_t);
}
else{
sym_info_size +=
arch_nmodtab * sizeof(struct dylib_module_64) +
arch_nsyms * sizeof(struct nlist_64) +
rnd(arch_nindirectsyms * sizeof(uint32_t), 8);
}
if(arch->object->hints_cmd != NULL){
sym_info_size +=
arch->object->hints_cmd->nhints *
sizeof(struct twolevel_hint);
}
if(arch->object->split_info_cmd != NULL){
sym_info_size +=
arch->object->split_info_cmd->datasize;
}
if(arch->object->func_starts_info_cmd != NULL){
sym_info_size +=
arch->object->func_starts_info_cmd->datasize;
}
if(arch->object->code_sig_cmd != NULL){
sym_info_size =
rnd(sym_info_size, 16);
sym_info_size +=
arch->object->code_sig_cmd->datasize;
}
arch->object->input_sym_info_size = sym_info_size;
arch->object->output_sym_info_size = sym_info_size;
arch->object->output_nsymbols = arch_nsyms;
arch->object->output_strings_size = arch_strsize;
arch->object->output_ilocalsym = arch->object->dyst->ilocalsym;
arch->object->output_nlocalsym = arch->object->dyst->nlocalsym;
arch->object->output_iextdefsym = arch->object->dyst->iextdefsym;
arch->object->output_nextdefsym = arch->object->dyst->nextdefsym;
arch->object->output_iundefsym = arch->object->dyst->iundefsym;
arch->object->output_nundefsym = arch->object->dyst->nundefsym;
arch->object->output_loc_relocs = arch_locrelocs;
arch->object->output_ext_relocs = arch_extrelocs;
arch->object->output_indirect_symtab = arch_indirect_symtab;
arch->object->output_tocs = arch_tocs;
arch->object->output_ntoc = arch_ntoc;
arch->object->output_mods = arch_mods;
arch->object->output_mods64 = arch_mods64;
arch->object->output_nmodtab = arch_nmodtab;
arch->object->output_refs = arch_refs;
arch->object->output_nextrefsyms = arch_nextrefsyms;
if(arch->object->hints_cmd != NULL &&
arch->object->hints_cmd->nhints != 0){
arch->object->output_hints = (struct twolevel_hint *)
(arch->object->object_addr +
arch->object->hints_cmd->offset);
}
if(arch->object->split_info_cmd != NULL){
arch->object->output_split_info_data = arch->object->object_addr +
arch->object->split_info_cmd->dataoff;
arch->object->output_split_info_data_size =
arch->object->split_info_cmd->datasize;
}
if(arch->object->func_starts_info_cmd != NULL){
arch->object->output_func_start_info_data =
arch->object->object_addr +
arch->object->func_starts_info_cmd->dataoff;
arch->object->output_func_start_info_data_size =
arch->object->func_starts_info_cmd->datasize;
}
if(arch->object->code_sig_cmd != NULL){
arch->object->output_code_sig_data = arch->object->object_addr +
arch->object->code_sig_cmd->dataoff;
arch->object->output_code_sig_data_size =
arch->object->code_sig_cmd->datasize;
}
if(arch->object->mh != NULL){
new_symbols = allocate(arch_nsyms * sizeof(struct nlist));
memcpy(new_symbols, arch_symbols,
arch_nsyms * sizeof(struct nlist));
arch->object->output_symbols = new_symbols;
arch->object->output_symbols64 = NULL;
new_symbols64 = NULL;
}
else{
new_symbols = NULL;
arch->object->output_symbols = NULL;
new_symbols64 = allocate(arch_nsyms * sizeof(struct nlist_64));
memcpy(new_symbols64, arch_symbols64,
arch_nsyms * sizeof(struct nlist_64));
arch->object->output_symbols64 = new_symbols64;
}
arch->object->output_strings = arch_strings;
if(missing_arch == TRUE){
arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
return;
}
objc_slide = 0;
if(vmslide != 0){
if(arch->object->mh != NULL){
if(unprebinding && arch_nmodtab != 0){
lowest_objc_module_info_addr = UINT_MAX;
for(i = 0; i < arch_nmodtab; i++){
if(arch_mods[i].objc_module_info_size != 0){
if(arch_mods[i].objc_module_info_addr <
lowest_objc_module_info_addr){
lowest_objc_module_info_addr =
arch_mods[i].objc_module_info_addr;
}
}
}
s_objc = NULL;
lc = arch->object->load_commands;
for(i = 0;
i < arch->object->mh->ncmds && s_objc == NULL;
i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(strcmp(sg->segname, SEG_OBJC) == 0){
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects; j++){
if(strcmp(s[j].sectname,
SECT_OBJC_MODULES) == 0){
s_objc = s + j;
break;
}
}
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(lowest_objc_module_info_addr != UINT_MAX &&
s_objc != NULL){
objc_slide = s_objc->addr -
lowest_objc_module_info_addr;
}
else{
objc_slide = vmslide;
}
}
else{
objc_slide = vmslide;
}
for(i = 0; i < arch_nmodtab; i++){
if(arch_mods[i].objc_module_info_size != 0)
arch_mods[i].objc_module_info_addr += objc_slide;
}
}
else{
for(i = 0; i < arch_nmodtab; i++){
if(arch_mods64[i].objc_module_info_size != 0)
arch_mods64[i].objc_module_info_addr += vmslide;
}
}
}
ihint = 0;
for(i = arch->object->dyst->iundefsym;
i < arch->object->dyst->iundefsym + arch->object->dyst->nundefsym;
i++){
if(unprebinding == TRUE){
if(arch->object->mh != NULL){
new_symbols[i].n_value = 0;
new_symbols[i].n_type &= ~N_TYPE;
new_symbols[i].n_type |= N_UNDF;
}
else{
new_symbols64[i].n_value = 0;
new_symbols64[i].n_type &= ~N_TYPE;
new_symbols64[i].n_type |= N_UNDF;
}
}
else{
if(arch->object->mh != NULL){
symbol_name = arch_strings + arch_symbols[i].n_un.n_strx;
lookup_symbol(symbol_name,
get_primary_lib(ARCH_LIB, arch_symbols + i),
get_weak(arch_symbols + i),
&symbol, &module_state, &lib, &isub_image,
&itoc, NO_INDR_LOOP);
new_symbols[i].n_value = symbol->n_value;
if(symbol->n_desc & N_ARM_THUMB_DEF)
new_symbols[i].n_value |= 1;
}
else{
fatal_arch(arch, NULL, "code does not yet support 64-bit "
"Mach-O binaries");
}
}
if(arch_hints != NULL){
if(unprebinding == TRUE){
arch_hints[ihint].isub_image = 0;
arch_hints[ihint].itoc = 0;
}
else{
arch_hints[ihint].isub_image = isub_image;
arch_hints[ihint].itoc = itoc;
}
ihint++;
}
}
if(vmslide != 0){
for(i = arch->object->dyst->iextdefsym;
i < arch->object->dyst->iextdefsym +
arch->object->dyst->nextdefsym;
i++){
if(arch->object->mh != NULL){
if(arch_symbols[i].n_sect != NO_SECT)
new_symbols[i].n_value += vmslide;
}
else{
if(arch_symbols64[i].n_sect != NO_SECT)
new_symbols64[i].n_value += vmslide;
}
}
for(i = arch->object->dyst->ilocalsym;
i < arch->object->dyst->ilocalsym +
arch->object->dyst->nlocalsym;
i++){
if(arch->object->mh != NULL){
if(arch_symbols[i].n_sect != NO_SECT)
new_symbols[i].n_value += vmslide;
}
else{
if(arch_symbols64[i].n_sect != NO_SECT)
new_symbols64[i].n_value += vmslide;
}
}
}
if(unprebinding){
for(i = arch->object->dyst->iextdefsym;
i < arch->object->dyst->iextdefsym +
arch->object->dyst->nextdefsym;
i++){
if(arch->object->mh != NULL){
if((arch_symbols[i].n_type & N_TYPE) == N_ABS){
symbol_name = arch_strings +
arch_symbols[i].n_un.n_strx;
dot = rindex(symbol_name, '.');
if(strncmp(symbol_name, ".objc",
sizeof(".objc") - 1) == 0 ||
(dot != NULL && dot[1] == 'e' &&
dot[2] == 'h' && dot[3] == '\0') )
new_symbols[i].n_value = 0;
}
}
}
}
if(arch->object->mh != NULL && unprebinding == TRUE){
if(vmslide != 0 && objc_slide != vmslide){
for(i = arch->object->dyst->ilocalsym;
i < arch->object->dyst->ilocalsym +
arch->object->dyst->nlocalsym;
i++){
if((new_symbols[i].n_type & N_STAB) != 0){
if(new_symbols[i].n_type == N_STSYM ||
new_symbols[i].n_type == N_SO){
new_symbols[i].n_value += objc_slide - vmslide;
}
}
}
}
}
}
static
void
setup_r_address_base(
void)
{
uint32_t i;
struct load_command *lc;
struct segment_command *sg;
uint32_t ncmds, mh_flags;
if(arch->object->mh != NULL) {
ncmds = arch->object->mh->ncmds;
mh_flags = arch->object->mh->flags;
} else {
ncmds = arch->object->mh64->ncmds;
mh_flags = arch->object->mh64->flags;
}
if((mh_flags & MH_SPLIT_SEGS) == MH_SPLIT_SEGS)
arch_split_segs = TRUE;
else
arch_split_segs = FALSE;
sg = NULL;
lc = arch->object->load_commands;
for(i = 0; i < ncmds && sg == NULL; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(arch_split_segs == FALSE){
arch_seg1addr = sg->vmaddr;
}
else{
if((sg->initprot & VM_PROT_WRITE) == VM_PROT_WRITE)
arch_segs_read_write_addr = sg->vmaddr;
else
sg = NULL;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
update_local_relocs(
uint32_t vmslide)
{
switch(arch->object->mh_cputype){
case CPU_TYPE_MC680x0:
update_generic_local_relocs(vmslide);
break;
case CPU_TYPE_I386:
update_generic_local_relocs(vmslide);
break;
case CPU_TYPE_HPPA:
update_hppa_local_relocs(vmslide);
break;
case CPU_TYPE_SPARC:
update_sparc_local_relocs(vmslide);
break;
case CPU_TYPE_POWERPC:
update_ppc_local_relocs(vmslide);
break;
case CPU_TYPE_ARM:
update_arm_local_relocs(vmslide);
break;
default:
error("can't redo prebinding for: %s (for architecture %s) because "
"of unknown cputype", arch->file_name, arch_name);
}
}
static
void
update_generic_local_relocs(
uint32_t vmslide)
{
uint32_t i, r_address, r_pcrel, r_length, r_type, r_value, value;
char *p;
enum bool no_sect;
struct scattered_relocation_info *sreloc;
sreloc = NULL;
r_value = 0;
for(i = 0; i < arch_nlocrel; i++){
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)
(arch_locrelocs + i);
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_length = sreloc->r_length;
r_type = sreloc->r_type;
r_value = sreloc->r_value;
no_sect = FALSE;
}
else{
r_address = arch_locrelocs[i].r_address;
r_pcrel = arch_locrelocs[i].r_pcrel;
r_length = arch_locrelocs[i].r_length;
r_type = arch_locrelocs[i].r_type;
no_sect = arch_locrelocs[i].r_symbolnum == NO_SECT;
}
value = 0;
if(r_pcrel)
value -= vmslide;
if(no_sect == FALSE){
value += vmslide;
r_value += vmslide;
}
p = contents_pointer_for_vmaddr(r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for local relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(r_type == GENERIC_RELOC_PB_LA_PTR){
;
}
else{
switch(r_length){
case 0:
value += get_arch_byte(p);
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 1 "
"byte)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value += get_arch_short(p);
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 2 "
"bytes)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value += get_arch_long(p);
set_arch_long(p, value);
break;
}
}
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc->r_value = r_value;
}
}
}
static
void
update_hppa_local_relocs(
uint32_t vmslide)
{
uint32_t i, r_address, r_pcrel, r_length, r_value, value;
char *p;
uint32_t instruction, immediate;
enum bool no_sect;
struct scattered_relocation_info *sreloc;
struct relocation_info *pair_reloc;
struct scattered_relocation_info *spair_reloc;
enum reloc_type_hppa r_type, pair_r_type;
uint32_t other_half;
uint32_t hi21, lo14;
uint32_t w, w1, w2;
sreloc = NULL;
pair_reloc = NULL;
spair_reloc = NULL;
other_half = 0;
r_value = 0;
for(i = 0; i < arch_nlocrel; i++){
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)
(arch_locrelocs + i);
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_length = sreloc->r_length;
r_value = sreloc->r_value;
r_type = (enum reloc_type_hppa)sreloc->r_type;
no_sect = FALSE;
}
else{
r_address = arch_locrelocs[i].r_address;
r_pcrel = arch_locrelocs[i].r_pcrel;
r_length = arch_locrelocs[i].r_length;
r_type = (enum reloc_type_hppa)arch_locrelocs[i].r_type;
no_sect = arch_locrelocs[i].r_symbolnum == NO_SECT;
}
pair_r_type = 0;
if(r_type == HPPA_RELOC_HI21 ||
r_type == HPPA_RELOC_LO14 ||
r_type == HPPA_RELOC_BR17){
if(i + 1 == arch_nlocrel){
error("malformed file: %s (missing pair local "
"relocation entry for entry %u) (for architecture "
"%s)", arch->file_name, i, arch_name);
redo_exit(2);
}
pair_reloc = arch_locrelocs + i + 1;
if((pair_reloc->r_address & R_SCATTERED) != 0){
spair_reloc = (struct scattered_relocation_info *)
pair_reloc;
pair_r_type = spair_reloc->r_type;
other_half = spair_reloc->r_address;
}
else{
pair_r_type = pair_reloc->r_type;
other_half = pair_reloc->r_address;
}
i++;
if(pair_r_type != HPPA_RELOC_PAIR){
error("malformed file: %s (pair local relocation entry "
"for entry %u is not of r_type HPPA_RELOC_PAIR) "
"(for architecture %s)", arch->file_name, i,
arch_name);
redo_exit(2);
}
}
value = 0;
if(r_pcrel)
value -= vmslide;
if(no_sect == FALSE){
value += vmslide;
r_value += vmslide;
}
p = contents_pointer_for_vmaddr(r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for local relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(r_type == HPPA_RELOC_VANILLA){
switch(r_length){
case 0:
value += get_arch_byte(p);
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 1 "
"byte)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value += get_arch_short(p);
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 2 "
"bytes)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value += get_arch_long(p);
set_arch_long(p, value);
break;
}
}
else{
switch(r_type){
case HPPA_RELOC_PB_LA_PTR:
break;
case HPPA_RELOC_HI21:
instruction = get_arch_long(p);
immediate = sign_ext(other_half, 14) +
(assemble_21(instruction & 0x1fffff) << 11);
calc_hppa_HILO(value + immediate, 0, &hi21, &lo14);
instruction = (instruction & 0xffe00000) |
dis_assemble_21(hi21 >> 11);
set_arch_long(p, instruction);
other_half = lo14 & 0x3fff;
break;
case HPPA_RELOC_LO14:
instruction = get_arch_long(p);
immediate = low_sign_ext(instruction & 0x3fff, 14) +
(other_half << 11);
calc_hppa_HILO(value + immediate, 0, &hi21, &lo14);
lo14 = low_sign_unext(lo14, 14);
instruction = (instruction & 0xffffc000) |
(lo14 & 0x3fff);
set_arch_long(p, instruction);
other_half = hi21 >> 11;
break;
case HPPA_RELOC_BR17:
instruction = get_arch_long(p);
immediate = assemble_17((instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
immediate = (sign_ext(immediate, 17) << 2) +
(other_half << 11);
calc_hppa_HILO(value + immediate, 0, &hi21, &lo14);
lo14 >>= 2;
dis_assemble_17(lo14, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
set_arch_long(p, instruction);
other_half = hi21 >> 11;
break;
case HPPA_RELOC_BL17:
instruction = get_arch_long(p);
immediate = assemble_17((instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
if((immediate & 0x10000) != 0)
immediate |= 0xfffe0000;
immediate <<= 2;
immediate += value;
if(U_ABS(immediate) > 0x3ffff){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u displacement "
"too large to fit)", arch->file_name, arch_name, i);
}
immediate >>= 2;
dis_assemble_17(immediate, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
set_arch_long(p, instruction);
break;
default:
error("malformed file: %s (local relocation entry "
"%u has unknown r_type) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
break;
}
}
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc->r_value = r_value;
}
if(pair_r_type == HPPA_RELOC_PAIR){
if((pair_reloc->r_address & R_SCATTERED) != 0)
spair_reloc->r_address = other_half;
else
pair_reloc->r_address = other_half;
}
}
}
static
void
update_sparc_local_relocs(
uint32_t vmslide)
{
uint32_t i, r_address, r_pcrel, r_length, r_value, value;
char *p;
uint32_t instruction, immediate;
enum bool no_sect;
struct scattered_relocation_info *sreloc;
struct relocation_info *pair_reloc;
struct scattered_relocation_info *spair_reloc;
enum reloc_type_sparc r_type, pair_r_type;
uint32_t other_half;
sreloc = NULL;
pair_reloc = NULL;
spair_reloc = NULL;
other_half = 0;
r_value = 0;
for(i = 0; i < arch_nlocrel; i++){
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)
(arch_locrelocs + i);
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_length = sreloc->r_length;
r_value = sreloc->r_value;
r_type = (enum reloc_type_sparc)sreloc->r_type;
no_sect = FALSE;
}
else{
r_address = arch_locrelocs[i].r_address;
r_pcrel = arch_locrelocs[i].r_pcrel;
r_length = arch_locrelocs[i].r_length;
r_type = (enum reloc_type_sparc)arch_locrelocs[i].r_type;
no_sect = arch_locrelocs[i].r_symbolnum == NO_SECT;
}
pair_r_type = 0;
if(r_type == SPARC_RELOC_HI22 ||
r_type == SPARC_RELOC_LO10 ){
if(i + 1 == arch_nlocrel){
error("malformed file: %s (missing pair local "
"relocation entry for entry %u) (for architecture "
"%s)", arch->file_name, i, arch_name);
redo_exit(2);
}
pair_reloc = arch_locrelocs + i + 1;
if((pair_reloc->r_address & R_SCATTERED) != 0){
spair_reloc = (struct scattered_relocation_info *)
pair_reloc;
pair_r_type = spair_reloc->r_type;
other_half = spair_reloc->r_address;
}
else{
pair_r_type = pair_reloc->r_type;
other_half = pair_reloc->r_address;
}
i++;
if(pair_r_type != SPARC_RELOC_PAIR){
error("malformed file: %s (pair local relocation entry "
"for entry %u is not of r_type SPARC_RELOC_PAIR) "
"(for architecture %s)", arch->file_name, i,
arch_name);
redo_exit(2);
}
}
value = 0;
if(r_pcrel)
value -= vmslide;
if(no_sect == FALSE){
value += vmslide;
r_value += vmslide;
}
p = contents_pointer_for_vmaddr(r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for local relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(r_type == SPARC_RELOC_VANILLA){
switch(r_length){
case 0:
value += get_arch_byte(p);
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 1 "
"byte)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value += get_arch_short(p);
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 2 "
"bytes)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value += get_arch_long(p);
set_arch_long(p, value);
break;
}
}
else {
switch(r_type) {
case SPARC_RELOC_PB_LA_PTR:
break;
case SPARC_RELOC_HI22:
instruction = get_arch_long(p);
immediate = ((instruction & 0x3fffff) << 10) | other_half;
immediate += value;
instruction = (instruction & 0xffc00000) |
((immediate >> 10) & 0x3fffff);
set_arch_long(p, instruction);
other_half = immediate & 0x3ff;
break;
case SPARC_RELOC_LO10:
instruction = get_arch_long(p);
immediate = (instruction & 0x3ff) | (other_half << 10);
immediate += value;
instruction = (instruction & 0xfffffc00) |
(immediate & 0x3ff);
set_arch_long(p, instruction);
other_half = (immediate >> 10) & 0x3fffff;
break;
case SPARC_RELOC_WDISP22:
instruction = get_arch_long(p);
immediate = (instruction & 0x3fffff);
if((immediate & 0x200000) != 0)
immediate |= 0xffc00000;
immediate <<= 2;
immediate += value;
if((immediate & 0xff800000) != 0xff800000 &&
(immediate & 0xff800000) != 0x00) {
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u displacement too "
"large to fit)", arch->file_name, arch_name, i);
}
immediate >>= 2;
instruction = (instruction & 0xffc00000) |
(immediate & 0x3fffff);
set_arch_long(p, instruction);
break;
case SPARC_RELOC_WDISP30:
instruction = get_arch_long(p);
immediate = (instruction & 0x3fffffff);
immediate <<= 2;
immediate += value;
immediate >>= 2;
instruction = (instruction & 0xc0000000) |
(immediate & 0x3fffffff);
set_arch_long(p, instruction);
break;
default:
error("malformed file: %s (local relocation entry "
"%u has unknown r_type) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
break;
}
}
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc->r_value = r_value;
}
if(pair_r_type == SPARC_RELOC_PAIR){
if((pair_reloc->r_address & R_SCATTERED) != 0)
spair_reloc->r_address = other_half;
else
pair_reloc->r_address = other_half;
}
}
}
static
void
update_ppc_local_relocs(
uint32_t vmslide)
{
uint32_t i, r_address, r_pcrel, r_length, r_value, value;
char *p;
uint32_t instruction, immediate;
enum bool no_sect;
struct scattered_relocation_info *sreloc;
struct relocation_info *pair_reloc;
struct scattered_relocation_info *spair_reloc;
enum reloc_type_ppc r_type, pair_r_type;
uint32_t other_half;
sreloc = NULL;
pair_reloc = NULL;
spair_reloc = NULL;
other_half = 0;
r_value = 0;
for(i = 0; i < arch_nlocrel; i++){
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)
(arch_locrelocs + i);
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_length = sreloc->r_length;
r_value = sreloc->r_value;
r_type = (enum reloc_type_ppc)sreloc->r_type;
no_sect = FALSE;
}
else{
r_address = arch_locrelocs[i].r_address;
r_pcrel = arch_locrelocs[i].r_pcrel;
r_length = arch_locrelocs[i].r_length;
r_type = (enum reloc_type_ppc)arch_locrelocs[i].r_type;
no_sect = arch_locrelocs[i].r_symbolnum == NO_SECT;
}
pair_r_type = 0;
if(r_type == PPC_RELOC_HI16 || r_type == PPC_RELOC_LO16 ||
r_type == PPC_RELOC_HA16 || r_type == PPC_RELOC_LO14){
if(i + 1 == arch_nlocrel){
error("malformed file: %s (missing pair local "
"relocation entry for entry %u) (for architecture "
"%s)", arch->file_name, i, arch_name);
redo_exit(2);
}
pair_reloc = arch_locrelocs + i + 1;
if((pair_reloc->r_address & R_SCATTERED) != 0){
spair_reloc = (struct scattered_relocation_info *)
pair_reloc;
pair_r_type = spair_reloc->r_type;
other_half = spair_reloc->r_address;
}
else{
pair_r_type = pair_reloc->r_type;
other_half = pair_reloc->r_address;
}
i++;
if(pair_r_type != PPC_RELOC_PAIR){
error("malformed file: %s (pair local relocation entry "
"for entry %u is not of r_type PPC_RELOC_PAIR) "
"(for architecture %s)", arch->file_name, i,
arch_name);
redo_exit(2);
}
}
value = 0;
if(r_pcrel)
value -= vmslide;
if(no_sect == FALSE){
value += vmslide;
r_value += vmslide;
}
p = contents_pointer_for_vmaddr(r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for local relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(r_type == PPC_RELOC_VANILLA){
switch(r_length){
case 0:
value += get_arch_byte(p);
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 1 "
"byte)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value += get_arch_short(p);
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 2 "
"bytes)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value += get_arch_long(p);
set_arch_long(p, value);
break;
}
}
else{
switch(r_type){
case PPC_RELOC_PB_LA_PTR:
break;
case PPC_RELOC_HI16:
instruction = get_arch_long(p);
immediate = ((instruction & 0xffff) << 16) | other_half;
immediate += value;
instruction = (instruction & 0xffff0000) |
((immediate >> 16) & 0xffff);
set_arch_long(p, instruction);
other_half = immediate & 0xffff;
break;
case PPC_RELOC_LO16:
instruction = get_arch_long(p);
immediate = (other_half << 16) | (instruction & 0xffff);
immediate += value;
instruction = (instruction & 0xffff0000) |
(immediate & 0xffff);
set_arch_long(p, instruction);
other_half = (immediate >> 16) & 0xffff;
break;
case PPC_RELOC_HA16:
instruction = get_arch_long(p);
if((other_half & 0x00008000) != 0)
immediate = ((instruction & 0xffff) << 16) +
(0xffff0000 + other_half);
else
immediate = ((instruction & 0xffff) << 16) +
(other_half);
immediate += value;
if((immediate & 0x00008000) != 0)
instruction = (instruction & 0xffff0000) |
(((immediate + 0x00008000) >> 16) & 0xffff);
else
instruction = (instruction & 0xffff0000) |
((immediate >> 16) & 0xffff);
set_arch_long(p, instruction);
other_half = immediate & 0xffff;
break;
case PPC_RELOC_LO14:
instruction = get_arch_long(p);
immediate = (other_half << 16) | (instruction & 0xfffc);
immediate += value;
if((immediate & 0x3) != 0){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocated value "
"not a multiple of 4 bytes for local relocation "
"entry %u", arch->file_name, arch_name, i);
}
instruction = (instruction & 0xffff0003) |
(immediate & 0xfffc);
set_arch_long(p, instruction);
other_half = (immediate >> 16) & 0xffff;
break;
case PPC_RELOC_BR14:
instruction = get_arch_long(p);
immediate = instruction & 0xfffc;
if((immediate & 0x8000) != 0)
immediate |= 0xffff0000;
immediate += value;
if((immediate & 0x3) != 0){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocated value "
"not a multiple of 4 bytes for local relocation "
"entry %u", arch->file_name, arch_name, i);
}
if((immediate & 0xfffe0000) != 0xfffe0000 &&
(immediate & 0xfffe0000) != 0x00000000){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u displacement "
"too large to fit)", arch->file_name, arch_name, i);
}
instruction = (instruction & 0xffff0003) |
(immediate & 0xfffc);
set_arch_long(p, instruction);
break;
case PPC_RELOC_BR24:
instruction = get_arch_long(p);
immediate = instruction & 0x03fffffc;
if((immediate & 0x02000000) != 0)
immediate |= 0xfc000000;
immediate += value;
if((immediate & 0x3) != 0){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocated value "
"not a multiple of 4 bytes for local relocation "
"entry %u", arch->file_name, arch_name, i);
}
if((immediate & 0xfe000000) != 0xfe000000 &&
(immediate & 0xfe000000) != 0x00000000){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u displacement too "
"large to fit)", arch->file_name, arch_name, i);
}
instruction = (instruction & 0xfc000003) |
(immediate & 0x03fffffc);
set_arch_long(p, instruction);
break;
default:
error("malformed file: %s (local relocation entry "
"%u has unknown r_type) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
break;
}
}
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc->r_value = r_value;
}
if(pair_r_type == PPC_RELOC_PAIR){
if((pair_reloc->r_address & R_SCATTERED) != 0)
spair_reloc->r_address = other_half;
else
pair_reloc->r_address = other_half;
}
}
}
static
void
update_arm_local_relocs(
uint32_t vmslide)
{
uint32_t i, r_address, r_pcrel, r_length, r_value, value;
char *p;
enum bool no_sect;
struct scattered_relocation_info *sreloc;
struct relocation_info *pair_reloc;
struct scattered_relocation_info *spair_reloc;
enum reloc_type_arm r_type;
uint32_t other_half;
sreloc = NULL;
pair_reloc = NULL;
spair_reloc = NULL;
other_half = 0;
r_value = 0;
for(i = 0; i < arch_nlocrel; i++){
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)
(arch_locrelocs + i);
r_address = sreloc->r_address;
r_pcrel = sreloc->r_pcrel;
r_length = sreloc->r_length;
r_value = sreloc->r_value;
r_type = (enum reloc_type_arm)sreloc->r_type;
no_sect = FALSE;
}
else{
r_address = arch_locrelocs[i].r_address;
r_pcrel = arch_locrelocs[i].r_pcrel;
r_length = arch_locrelocs[i].r_length;
r_type = (enum reloc_type_arm)arch_locrelocs[i].r_type;
no_sect = arch_locrelocs[i].r_symbolnum == NO_SECT;
}
value = 0;
if(r_pcrel)
value -= vmslide;
if(no_sect == FALSE){
value += vmslide;
r_value += vmslide;
}
p = contents_pointer_for_vmaddr(r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for local relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(r_type == ARM_RELOC_VANILLA){
switch(r_length){
case 0:
value += get_arch_byte(p);
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 1 "
"byte)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value += get_arch_short(p);
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(local relocation entry %u does not fit in 2 "
"bytes)", arch->file_name, arch_name, i);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value += get_arch_long(p);
set_arch_long(p, value);
break;
}
}
else{
switch(r_type){
case ARM_RELOC_PB_LA_PTR:
break;
case ARM_THUMB_RELOC_BR22:
case ARM_RELOC_BR24:
if (!r_pcrel) {
error("prebinding can't be redone for: %s (for "
"architecture %s) because the relocation is not "
"pc-relative",
arch->file_name, arch_name);
redo_exit(2);
}
if (value != 0) {
error("prebinding can't be redone for: %s (for "
"architecture %s) because the slide of a pc-relative "
"relocation is not zero",
arch->file_name, arch_name);
redo_exit(2);
}
break;
default:
error("malformed file: %s (local relocation entry "
"%u has unknown r_type) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
break;
}
}
if((arch_locrelocs[i].r_address & R_SCATTERED) != 0){
sreloc->r_value = r_value;
}
}
}
static
void
update_external_relocs(
uint32_t vmslide)
{
switch(arch->object->mh_cputype){
case CPU_TYPE_MC680x0:
update_generic_external_relocs(vmslide);
break;
case CPU_TYPE_I386:
update_generic_external_relocs(vmslide);
break;
case CPU_TYPE_HPPA:
update_hppa_external_relocs(vmslide);
break;
case CPU_TYPE_SPARC:
update_sparc_external_relocs(vmslide);
break;
case CPU_TYPE_POWERPC:
update_ppc_external_relocs(vmslide);
break;
case CPU_TYPE_ARM:
update_arm_external_relocs(vmslide);
break;
default:
error("can't redo prebinding for: %s (for architecture %s) because "
"of unknown cputype", arch->file_name, arch_name);
}
}
static
void
update_generic_external_relocs(
uint32_t vmslide)
{
uint32_t i, value, symbol_slide;
char *name, *p;
struct nlist *defined_symbol, *arch_symbol;
enum link_state *module_state;
struct lib *lib;
uint32_t mh_flags;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
for(i = 0; i < arch_nextrel; i++){
if(arch_extrelocs[i].r_symbolnum > arch_nsyms){
error("malformed file: %s (bad symbol table index for "
"external relocation entry %u) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
arch_symbol = arch_symbols + arch_extrelocs[i].r_symbolnum;
if(arch_symbol->n_sect == NO_SECT)
symbol_slide = 0;
else
symbol_slide = vmslide;
name = arch_strings + arch_symbol->n_un.n_strx;
if((arch_symbol->n_type & N_TYPE) == N_PBUD){
if(unprebinding == TRUE){
defined_symbol = arch->object->output_symbols +
arch_extrelocs[i].r_symbolnum;
}
else{
lookup_symbol(name,
get_primary_lib(ARCH_LIB, arch_symbol),
get_weak(arch_symbol),
&defined_symbol, &module_state, &lib,
NULL, NULL, NO_INDR_LOOP);
}
}
else{
defined_symbol = arch_symbol;
}
p = contents_pointer_for_vmaddr(arch_extrelocs[i].r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << arch_extrelocs[i].r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for external relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
switch(arch_extrelocs[i].r_length){
case 0:
value = get_arch_byte(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value + symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for architecture"
" %s) because of relocation overflow (external "
"relocation for symbol %s does not fit in 1 byte)",
arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value = get_arch_short(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value + symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for architecture"
" %s) because of relocation overflow (external "
"relocation for symbol %s does not fit in 2 bytes)",
arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value = get_arch_long(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value + symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
set_arch_long(p, value);
break;
default:
error("malformed file: %s (external relocation entry "
"%u has bad r_length) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
}
}
static
void
update_hppa_external_relocs(
uint32_t vmslide)
{
uint32_t i, value, symbol_slide;
char *name, *p;
struct nlist *defined_symbol, *arch_symbol;
enum link_state *module_state;
struct lib *lib;
uint32_t instruction, immediate;
uint32_t other_half;
uint32_t hi21, lo14;
uint32_t w, w1, w2;
uint32_t mh_flags;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
for(i = 0; i < arch_nextrel; i++){
if(arch_extrelocs[i].r_symbolnum > arch_nsyms){
error("malformed file: %s (bad symbol table index for "
"external relocation entry %u) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
if(arch_extrelocs[i].r_type == HPPA_RELOC_HI21 ||
arch_extrelocs[i].r_type == HPPA_RELOC_LO14 ||
arch_extrelocs[i].r_type == HPPA_RELOC_BR17){
if(i + 1 == arch_nextrel){
error("malformed file: %s (missing pair external "
"relocation entry for entry %u) (for architecture "
"%s)", arch->file_name, i, arch_name);
redo_exit(2);
}
if(arch_extrelocs[i + 1].r_type != HPPA_RELOC_PAIR){
error("malformed file: %s (pair external relocation entry "
"for entry %u is not of r_type HPPA_RELOC_PAIR) (for"
" architecture %s)", arch->file_name, i, arch_name);
redo_exit(2);
}
}
arch_symbol = arch_symbols + arch_extrelocs[i].r_symbolnum;
if(arch_symbol->n_sect == NO_SECT)
symbol_slide = 0;
else
symbol_slide = vmslide;
name = arch_strings + arch_symbol->n_un.n_strx;
if((arch_symbol->n_type & N_TYPE) == N_PBUD){
if(unprebinding == TRUE){
defined_symbol = arch->object->output_symbols +
arch_extrelocs[i].r_symbolnum;
}
else{
lookup_symbol(name,
get_primary_lib(ARCH_LIB, arch_symbol),
get_weak(arch_symbol),
&defined_symbol, &module_state, &lib,
NULL, NULL, NO_INDR_LOOP);
}
}
else
defined_symbol = arch_symbol;
p = contents_pointer_for_vmaddr(arch_extrelocs[i].r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << arch_extrelocs[i].r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for external relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(arch_extrelocs[i].r_type == HPPA_RELOC_VANILLA){
switch(arch_extrelocs[i].r_length){
case 0:
value = get_arch_byte(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 1 byte)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value = get_arch_short(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 2 bytes)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value = get_arch_long(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
set_arch_long(p, value);
break;
default:
error("malformed file: %s (external relocation entry "
"%u has bad r_length) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
}
else{
instruction = get_arch_long(p);
switch(arch_extrelocs[i].r_type){
case HPPA_RELOC_HI21:
other_half = arch_extrelocs[i + 1].r_address;
immediate = sign_ext(other_half, 14) +
(assemble_21(instruction & 0x1fffff) << 11);
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
calc_hppa_HILO(immediate, 0, &hi21, &lo14);
instruction = (instruction & 0xffe00000) |
dis_assemble_21(hi21 >> 11);
arch_extrelocs[i + 1].r_address = lo14 & 0x3fff;
break;
case HPPA_RELOC_LO14:
other_half = arch_extrelocs[i + 1].r_address;
immediate = low_sign_ext(instruction & 0x3fff, 14) +
(other_half << 11);
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
calc_hppa_HILO(immediate, 0, &hi21, &lo14);
lo14 = low_sign_unext(lo14, 14);
instruction = (instruction & 0xffffc000) |
(lo14 & 0x3fff);
arch_extrelocs[i + 1].r_address = hi21 >> 11;
break;
case HPPA_RELOC_BR17:
other_half = arch_extrelocs[i + 1].r_address;
immediate = assemble_17((instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
immediate = (sign_ext(immediate, 17) << 2) +
(other_half << 11);
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
calc_hppa_HILO(immediate, 0, &hi21, &lo14);
lo14 >>= 2;
dis_assemble_17(lo14, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
arch_extrelocs[i + 1].r_address = hi21 >> 11;
break;
case HPPA_RELOC_BL17:
immediate = assemble_17((instruction & 0x1f0000) >> 16,
(instruction & 0x1ffc) >> 2,
instruction & 1);
if((immediate & 0x10000) != 0)
immediate |= 0xfffe0000;
immediate <<= 2;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
if(U_ABS(immediate) > 0x3ffff){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s displacement "
"too large to fit)", arch->file_name, arch_name,
name);
redo_exit(2);
}
immediate >>= 2;
dis_assemble_17(immediate, &w1, &w2, &w);
instruction = (instruction & 0xffe0e002) |
(w1 << 16) | (w2 << 2) | w;
break;
default:
error("malformed file: %s (external relocation entry "
"%u has unknown r_type) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
set_arch_long(p, instruction);
}
if(arch_extrelocs[i].r_type == HPPA_RELOC_HI21 ||
arch_extrelocs[i].r_type == HPPA_RELOC_LO14 ||
arch_extrelocs[i].r_type == HPPA_RELOC_BR17)
i++;
}
}
static
void
update_sparc_external_relocs(
uint32_t vmslide)
{
uint32_t i, value, symbol_slide;
char *name, *p;
struct nlist *defined_symbol, *arch_symbol;
enum link_state *module_state;
struct lib *lib;
uint32_t instruction, immediate;
uint32_t other_half;
uint32_t mh_flags;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
for(i = 0; i < arch_nextrel; i++){
if(arch_extrelocs[i].r_symbolnum > arch_nsyms){
error("malformed file: %s (bad symbol table index for "
"external relocation entry %u) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
if(arch_extrelocs[i].r_type == SPARC_RELOC_LO10 ||
arch_extrelocs[i].r_type == SPARC_RELOC_HI22){
if(i + 1 == arch_nextrel){
error("malformed file: %s (missing pair external "
"relocation entry for entry %u) (for architecture "
"%s)", arch->file_name, i, arch_name);
redo_exit(2);
}
if(arch_extrelocs[i + 1].r_type != SPARC_RELOC_PAIR){
error("malformed file: %s (pair external relocation entry "
"for entry %u is not of r_type SPARC_RELOC_PAIR) "
"(for architecture %s)", arch->file_name, i,
arch_name);
redo_exit(2);
}
}
arch_symbol = arch_symbols + arch_extrelocs[i].r_symbolnum;
if(arch_symbol->n_sect == NO_SECT)
symbol_slide = 0;
else
symbol_slide = vmslide;
name = arch_strings + arch_symbol->n_un.n_strx;
if((arch_symbol->n_type & N_TYPE) == N_PBUD){
if(unprebinding == TRUE){
defined_symbol = arch->object->output_symbols +
arch_extrelocs[i].r_symbolnum;
}
else{
lookup_symbol(name,
get_primary_lib(ARCH_LIB, arch_symbol),
get_weak(arch_symbol),
&defined_symbol, &module_state, &lib,
NULL, NULL, NO_INDR_LOOP);
}
}
else
defined_symbol = arch_symbol;
p = contents_pointer_for_vmaddr(arch_extrelocs[i].r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << arch_extrelocs[i].r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for external relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(arch_extrelocs[i].r_type == SPARC_RELOC_VANILLA){
switch(arch_extrelocs[i].r_length){
case 0:
value = get_arch_byte(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 1 byte)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value = get_arch_short(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 2 bytes)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value = get_arch_long(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
set_arch_long(p, value);
break;
default:
error("malformed file: %s (external relocation entry "
"%u has bad r_length) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
}
else{
instruction = get_arch_long(p);
switch(arch_extrelocs[i].r_type){
case SPARC_RELOC_HI22:
other_half = (arch_extrelocs[i + 1].r_address) & 0x3ff;
immediate = ((instruction & 0x3fffff) << 10) | other_half;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
instruction = (instruction & 0xffc00000) |
((immediate >> 10) & 0x3fffff);
arch_extrelocs[i + 1].r_address = immediate & 0x3ff;
break;
case SPARC_RELOC_LO10:
other_half = ((arch_extrelocs[i + 1].r_address) >> 10) &
0x3fffff;
immediate = (instruction & 0x3ff) | (other_half << 10);
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
instruction = (instruction & 0xfffffc00) |
(immediate & 0x3ff);
arch_extrelocs[i + 1].r_address =
(immediate >> 10) & 0x3fffff;
break;
case SPARC_RELOC_WDISP22:
immediate = (instruction & 0x3fffff);
if((immediate & 0x200000) != 0)
immediate |= 0xffc00000;
immediate <<= 2;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
if((immediate & 0xff800000) != 0xff800000 &&
(immediate & 0xff800000) != 0x00) {
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s displacement "
"too large to fit)", arch->file_name, arch_name,
name);
redo_exit(2);
}
immediate >>= 2;
instruction = (instruction & 0xffc00000) |
(immediate & 0x3fffff);
break;
case SPARC_RELOC_WDISP30:
immediate = (instruction & 0x3fffffff);
immediate <<= 2;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value + symbol_slide;
else
immediate += defined_symbol->n_value + symbol_slide
- arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
immediate >>= 2;
instruction = (instruction & 0xc0000000) |
(immediate & 0x3fffffff);
break;
default:
error("malformed file: %s (external relocation entry "
"%u has unknown r_type) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
set_arch_long(p, instruction);
}
if(arch_extrelocs[i].r_type == SPARC_RELOC_LO10 ||
arch_extrelocs[i].r_type == SPARC_RELOC_HI22)
i++;
}
}
static
void
update_ppc_external_relocs(
uint32_t vmslide)
{
uint32_t i, value, symbol_slide;
char *name, *p;
struct nlist *defined_symbol, *arch_symbol;
enum link_state *module_state;
struct lib *lib;
uint32_t instruction, immediate;
uint32_t other_half, br14_disp_sign;
uint32_t mh_flags;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
for(i = 0; i < arch_nextrel; i++){
if(arch_extrelocs[i].r_symbolnum > arch_nsyms){
error("malformed file: %s (bad symbol table index for "
"external relocation entry %u) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
if(arch_extrelocs[i].r_type == PPC_RELOC_HI16 ||
arch_extrelocs[i].r_type == PPC_RELOC_LO16 ||
arch_extrelocs[i].r_type == PPC_RELOC_HA16 ||
arch_extrelocs[i].r_type == PPC_RELOC_LO14){
if(i + 1 == arch_nextrel){
error("malformed file: %s (missing pair external "
"relocation entry for entry %u) (for architecture "
"%s)", arch->file_name, i, arch_name);
redo_exit(2);
}
if(arch_extrelocs[i + 1].r_type != PPC_RELOC_PAIR){
error("malformed file: %s (pair external relocation entry "
"for entry %u is not of r_type PPC_RELOC_PAIR) "
"(for architecture %s)", arch->file_name, i,
arch_name);
redo_exit(2);
}
}
arch_symbol = arch_symbols + arch_extrelocs[i].r_symbolnum;
if(arch_symbol->n_sect == NO_SECT)
symbol_slide = 0;
else
symbol_slide = vmslide;
name = arch_strings + arch_symbol->n_un.n_strx;
if((arch_symbol->n_type & N_TYPE) == N_PBUD)
if(unprebinding == TRUE){
defined_symbol = arch->object->output_symbols +
arch_extrelocs[i].r_symbolnum;
}
else{
lookup_symbol(name,
get_primary_lib(ARCH_LIB, arch_symbol),
get_weak(arch_symbol),
&defined_symbol, &module_state, &lib,
NULL, NULL, NO_INDR_LOOP);
}
else
defined_symbol = arch_symbol;
p = contents_pointer_for_vmaddr(arch_extrelocs[i].r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << arch_extrelocs[i].r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for external relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(arch_extrelocs[i].r_type == PPC_RELOC_VANILLA){
switch(arch_extrelocs[i].r_length){
case 0:
value = get_arch_byte(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 1 byte)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value = get_arch_short(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 2 bytes)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value = get_arch_long(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
set_arch_long(p, value);
break;
default:
error("malformed file: %s (external relocation entry "
"%u has bad r_length) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
}
else{
instruction = get_arch_long(p);
switch(arch_extrelocs[i].r_type){
case PPC_RELOC_HI16:
other_half = (arch_extrelocs[i + 1].r_address) & 0xffff;
immediate = ((instruction & 0xffff) << 16) | other_half;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value +
symbol_slide;
else
immediate += defined_symbol->n_value +
symbol_slide -
arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
instruction = (instruction & 0xffff0000) |
((immediate >> 16) & 0xffff);
arch_extrelocs[i + 1].r_address = immediate & 0xffff;
break;
case PPC_RELOC_LO16:
other_half = (arch_extrelocs[i + 1].r_address) & 0xffff;
immediate = (other_half << 16) | (instruction & 0xffff);
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value +
symbol_slide;
else
immediate += defined_symbol->n_value +
symbol_slide -
arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
instruction = (instruction & 0xffff0000) |
(immediate & 0xffff);
arch_extrelocs[i + 1].r_address =
(immediate >> 16) & 0xffff;
break;
case PPC_RELOC_HA16:
other_half = (arch_extrelocs[i + 1].r_address) & 0xffff;
immediate = ((instruction & 0xffff) << 16) | other_half;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value +
symbol_slide;
else
immediate += defined_symbol->n_value +
symbol_slide -
arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
if((immediate & 0x00008000) != 0)
instruction = (instruction & 0xffff0000) |
(((immediate + 0x00008000) >> 16) &
0xffff);
else
instruction = (instruction & 0xffff0000) |
((immediate >> 16) & 0xffff);
arch_extrelocs[i + 1].r_address = immediate & 0xffff;
break;
case PPC_RELOC_LO14:
other_half = (arch_extrelocs[i + 1].r_address) & 0xffff;
immediate = (other_half << 16) | (instruction & 0xfffc);
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value +
symbol_slide;
else
immediate += defined_symbol->n_value +
symbol_slide -
arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
if((immediate & 0x3) != 0){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocated value "
"not a multiple of 4 bytes", arch->file_name,
arch_name);
redo_exit(2);
}
instruction = (instruction & 0xffff0003) |
(immediate & 0xfffc);
arch_extrelocs[i + 1].r_address =
(immediate >> 16) & 0xffff;
break;
case PPC_RELOC_BR14:
br14_disp_sign = (instruction & 0x8000);
immediate = instruction & 0xfffc;
if((immediate & 0x8000) != 0)
immediate |= 0xffff0000;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value +
symbol_slide;
else
immediate += defined_symbol->n_value +
symbol_slide -
arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
if((immediate & 0x3) != 0){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocated value "
"not a multiple of 4 bytes", arch->file_name,
arch_name);
redo_exit(2);
}
if((immediate & 0xfffe0000) != 0xfffe0000 &&
(immediate & 0xfffe0000) != 0x00000000){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation "
"overflow (external relocation for symbol %s "
"displacement too large to fit)",
arch->file_name, arch_name, name);
redo_exit(2);
}
instruction = (instruction & 0xffff0003) |
(immediate & 0xfffc);
if((instruction & 0xfc000000) == 0x40000000 &&
(instruction & 0x03e00000) != 0x02800000 &&
(instruction & 0x00008000) != br14_disp_sign)
instruction ^= (1 << 21);
break;
case PPC_RELOC_BR24:
immediate = instruction & 0x03fffffc;
if((immediate & 0x02000000) != 0)
immediate |= 0xfc000000;
if(unprebinding == TRUE)
immediate -= arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
immediate += defined_symbol->n_value +
symbol_slide;
else
immediate += defined_symbol->n_value +
symbol_slide -
arch_symbol->n_value;
if(arch_extrelocs[i].r_pcrel)
immediate -= vmslide;
}
if((immediate & 0x3) != 0){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocated value "
"not a multiple of 4 bytes", arch->file_name,
arch_name);
redo_exit(2);
}
if((immediate & 0xfe000000) != 0xfe000000 &&
(immediate & 0xfe000000) != 0x00000000){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation "
"overflow (external relocation for symbol %s "
"displacement too large to fit)",
arch->file_name, arch_name, name);
redo_exit(2);
}
instruction = (instruction & 0xfc000003) |
(immediate & 0x03fffffc);
break;
default:
error("malformed file: %s (external relocation entry "
"%u has unknown r_type) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
set_arch_long(p, instruction);
}
if(arch_extrelocs[i].r_type == PPC_RELOC_HI16 ||
arch_extrelocs[i].r_type == PPC_RELOC_LO16 ||
arch_extrelocs[i].r_type == PPC_RELOC_HA16 ||
arch_extrelocs[i].r_type == PPC_RELOC_LO14)
i++;
}
}
static
void
update_arm_external_relocs(
uint32_t vmslide)
{
uint32_t i, value, symbol_slide;
char *name, *p;
struct nlist *defined_symbol, *arch_symbol;
enum link_state *module_state;
struct lib *lib;
uint32_t mh_flags;
if(arch->object->mh != NULL)
mh_flags = arch->object->mh->flags;
else
mh_flags = arch->object->mh64->flags;
for(i = 0; i < arch_nextrel; i++){
if(arch_extrelocs[i].r_symbolnum > arch_nsyms){
error("malformed file: %s (bad symbol table index for "
"external relocation entry %u) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
arch_symbol = arch_symbols + arch_extrelocs[i].r_symbolnum;
if(arch_symbol->n_sect == NO_SECT)
symbol_slide = 0;
else
symbol_slide = vmslide;
name = arch_strings + arch_symbol->n_un.n_strx;
if((arch_symbol->n_type & N_TYPE) == N_PBUD)
if(unprebinding == TRUE){
defined_symbol = arch->object->output_symbols +
arch_extrelocs[i].r_symbolnum;
}
else{
lookup_symbol(name,
get_primary_lib(ARCH_LIB, arch_symbol),
get_weak(arch_symbol),
&defined_symbol, &module_state, &lib,
NULL, NULL, NO_INDR_LOOP);
}
else
defined_symbol = arch_symbol;
p = contents_pointer_for_vmaddr(arch_extrelocs[i].r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr : arch_seg1addr),
1 << arch_extrelocs[i].r_length);
if(p == NULL){
error("malformed file: %s (for architecture %s) (bad r_address"
" field for external relocation entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if(arch_extrelocs[i].r_type == ARM_RELOC_VANILLA){
switch(arch_extrelocs[i].r_length){
case 0:
value = get_arch_byte(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffffff00) &&
((value & 0xffffff80) != 0xffffff80)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 1 byte)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_byte(p, value);
break;
case 1:
value = get_arch_short(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if( (value & 0xffff0000) &&
((value & 0xffff8000) != 0xffff8000)){
error("prebinding can't be redone for: %s (for "
"architecture %s) because of relocation overflow "
"(external relocation for symbol %s does not fit "
"in 2 bytes)", arch->file_name, arch_name, name);
redo_exit(2);
}
set_arch_short(p, value);
break;
case 2:
value = get_arch_long(p);
if(unprebinding == TRUE)
value = value - arch_symbol->n_value;
else{
if((mh_flags & MH_PREBINDABLE) == MH_PREBINDABLE)
value = value + defined_symbol->n_value +
symbol_slide;
else
value = (value - arch_symbol->n_value) +
defined_symbol->n_value + symbol_slide;
if(arch_extrelocs[i].r_pcrel)
value -= vmslide;
}
if (arch->object->mh_cputype == CPU_TYPE_ARM &&
(defined_symbol->n_desc & N_ARM_THUMB_DEF) != 0) {
set_arch_long(p, value | 1L);
} else {
set_arch_long(p, value);
}
break;
default:
error("malformed file: %s (external relocation entry "
"%u has bad r_length) (for architecture %s)",
arch->file_name, i, arch_name);
redo_exit(2);
}
}
else{
error("prebinding can't be redone for: %s (for "
"architecture %s) because of non-vanilla external relocation",
arch->file_name, arch_name);
redo_exit(2);
}
}
}
static
char *
contents_pointer_for_vmaddr(
uint32_t vmaddr,
uint32_t size)
{
uint32_t i, j, header_size, offset;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
uint32_t ncmds;
lc = arch->object->load_commands;
if(arch->object->mh != NULL){
ncmds = arch->object->mh->ncmds;
header_size = sizeof(struct mach_header) +
arch->object->mh->sizeofcmds;
}
else{
ncmds = arch->object->mh64->ncmds;
header_size = sizeof(struct mach_header_64) +
arch->object->mh64->sizeofcmds;
}
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(vmaddr >= sg->vmaddr &&
vmaddr + size <= sg->vmaddr + sg->vmsize){
offset = vmaddr - sg->vmaddr;
if(offset + size > sg->filesize)
return(NULL);
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects; j++){
if(vmaddr >= s->addr &&
vmaddr + size <= s->addr + s->size){
if(sg->fileoff + offset < header_size ||
sg->fileoff + offset >=
arch->object->object_size -
arch->object->input_sym_info_size)
return(NULL);
return(arch->object->object_addr +
sg->fileoff + offset);
}
s++;
}
return(NULL);
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
return(NULL);
}
static
void
update_symbol_pointers(
uint32_t vmslide)
{
uint32_t i, j, k, section_type, symbol_pointer;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
struct nlist *arch_symbol, *defined_symbol;
char *name, *p;
enum link_state *module_state;
struct lib *lib;
uint32_t ncmds;
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
section_type = s->flags & SECTION_TYPE;
if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_SYMBOL_POINTERS){
if(s->reserved1 + s->size / sizeof(uint32_t) >
arch_nindirectsyms){
error("malformed file: %s (for architecture %s) "
"(indirect symbol table entries for section "
"(%.16s,%.16s) extends past the end of the "
"indirect symbol table)", arch->file_name,
arch_name, s->segname, s->sectname);
redo_exit(2);
}
for(k = 0; k < s->size / sizeof(uint32_t); k++){
p = contents_pointer_for_vmaddr(
s->addr + (k * sizeof(uint32_t)),
sizeof(uint32_t));
if(p == NULL){
error("malformed file: %s (for architecture "
"%s) (bad indirect section (%.16s,%.16s))",
arch->file_name, arch_name, s->segname,
s->sectname);
redo_exit(2);
}
symbol_pointer = get_arch_long(p);
if(section_type == S_NON_LAZY_SYMBOL_POINTERS &&
(arch_indirect_symtab[s->reserved1 + k] &
INDIRECT_SYMBOL_ABS) == INDIRECT_SYMBOL_ABS){
continue;
}
if(section_type == S_NON_LAZY_SYMBOL_POINTERS &&
(arch_indirect_symtab[s->reserved1 + k] &
INDIRECT_SYMBOL_LOCAL) ==INDIRECT_SYMBOL_LOCAL){
set_arch_long(p, symbol_pointer + vmslide);
continue;
}
if(arch_indirect_symtab[s->reserved1 + k] >
arch_nsyms){
error("malformed file: %s (for architecture "
"%s) (bad indirect symbol table entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
arch_symbol = arch_symbols +
arch_indirect_symtab[s->reserved1 + k];
if((arch_symbol->n_type & N_TYPE) != N_PBUD){
if(arch_symbol->n_sect != NO_SECT)
set_arch_long(p, symbol_pointer + vmslide);
continue;
}
name = arch_strings + arch_symbol->n_un.n_strx;
lookup_symbol(name,
get_primary_lib(ARCH_LIB,arch_symbol),
get_weak(arch_symbol),
&defined_symbol, &module_state,
&lib, NULL, NULL, NO_INDR_LOOP);
if (arch->object->mh_cputype == CPU_TYPE_ARM &&
(defined_symbol->n_desc & N_ARM_THUMB_DEF) != 0)
set_arch_long(p, defined_symbol->n_value | 1L);
else
set_arch_long(p, defined_symbol->n_value);
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
update_self_modifying_stubs(
uint32_t vmslide)
{
uint32_t i, j, k, section_type, displacement, symbol_slide;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
struct nlist *arch_symbol, *defined_symbol;
char *name, *p;
enum link_state *module_state;
struct lib *lib;
uint32_t ncmds;
if(arch->object->mh->cputype != CPU_TYPE_I386 ||
arch->object->mh == NULL)
return;
lc = arch->object->load_commands;
ncmds = arch->object->mh->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
section_type = s->flags & SECTION_TYPE;
if(section_type == S_SYMBOL_STUBS &&
(s->flags & S_ATTR_SELF_MODIFYING_CODE) ==
S_ATTR_SELF_MODIFYING_CODE &&
s->reserved2 == 5){
if(s->reserved1 + s->size / 5 > arch_nindirectsyms){
error("malformed file: %s (for architecture %s) "
"(indirect symbol table entries for section "
"(%.16s,%.16s) extends past the end of the "
"indirect symbol table)", arch->file_name,
arch_name, s->segname, s->sectname);
redo_exit(2);
}
for(k = 0; k < s->size / 5; k++){
p = contents_pointer_for_vmaddr(
s->addr + (k * 5), 4);
if(p == NULL){
error("malformed file: %s (for architecture "
"%s) (bad indirect section (%.16s,%.16s))",
arch->file_name, arch_name, s->segname,
s->sectname);
redo_exit(2);
}
displacement = get_arch_long(p + 1);
if(arch_indirect_symtab[s->reserved1 + k] >
arch_nsyms){
error("malformed file: %s (for architecture "
"%s) (bad indirect symbol table entry "
"%u)", arch->file_name, arch_name, i);
redo_exit(2);
}
arch_symbol = arch_symbols +
arch_indirect_symtab[s->reserved1 + k];
if((arch_symbol->n_type & N_TYPE) != N_PBUD){
if(arch_symbol->n_sect == NO_SECT)
symbol_slide = 0;
else
symbol_slide = vmslide;
displacement = arch_symbol->n_value +
symbol_slide -
(vmslide + s->addr + (k * 5) + 5);
}
else{
name = arch_strings + arch_symbol->n_un.n_strx;
lookup_symbol(name,
get_primary_lib(ARCH_LIB,
arch_symbol),
get_weak(arch_symbol),
&defined_symbol, &module_state,
&lib, NULL, NULL, NO_INDR_LOOP);
displacement = defined_symbol->n_value -
(vmslide + s->addr + (k * 5) + 5);
}
*p = 0xE9;
set_arch_long(p + 1, displacement);
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
reset_symbol_pointers(
uint32_t vmslide)
{
uint32_t i, j, k, m, section_type;
uint32_t symbol_pointer;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
struct nlist *arch_symbol;
char *p;
struct scattered_relocation_info *sreloc;
uint32_t ncmds, mh_flags;
lc = arch->object->load_commands;
if(arch->object->mh != NULL){
ncmds = arch->object->mh->ncmds;
mh_flags = arch->object->mh->flags;
}
else{
ncmds = arch->object->mh64->ncmds;
mh_flags = arch->object->mh64->flags;
}
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
section_type = s->flags & SECTION_TYPE;
if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_SYMBOL_POINTERS){
if(s->reserved1 + s->size / sizeof(uint32_t) >
arch_nindirectsyms){
error("malformed file: %s (for architecture "
"%s) (indirect symbol table entries for "
"section (%.16s,%.16s) extends past the "
"end of the indirect symbol table)",
arch->file_name, arch_name, s->segname,
s->sectname);
redo_exit(2);
}
for(k = 0; k < s->size / sizeof(uint32_t); k++){
p = contents_pointer_for_vmaddr(
s->addr + (k * sizeof(uint32_t)),
sizeof(uint32_t));
if(p == NULL){
error("malformed file: %s (for architecture "
"%s) (bad indirect section (%.16s,%.16s))",
arch->file_name, arch_name, s->segname,
s->sectname);
redo_exit(2);
}
symbol_pointer = get_arch_long(p);
if(section_type == S_NON_LAZY_SYMBOL_POINTERS &&
(arch_indirect_symtab[s->reserved1 + k] &
INDIRECT_SYMBOL_ABS) == INDIRECT_SYMBOL_ABS){
continue;
}
if(section_type == S_NON_LAZY_SYMBOL_POINTERS &&
(arch_indirect_symtab[s->reserved1 + k] &
INDIRECT_SYMBOL_LOCAL) ==INDIRECT_SYMBOL_LOCAL){
set_arch_long(p, symbol_pointer + vmslide);
continue;
}
if(arch_indirect_symtab[s->reserved1 + k] >
arch_nsyms){
error("malformed file: %s (for architecture "
"%s) (bad indirect symbol table entry %u)",
arch->file_name, arch_name, i);
redo_exit(2);
}
if((mh_flags & MH_WEAK_DEFINES) == 0 &&
(mh_flags & MH_BINDS_TO_WEAK) == 0){
arch_symbol = arch_symbols +
arch_indirect_symtab[s->reserved1 + k];
if((arch_symbol->n_type & N_TYPE) != N_PBUD){
if(arch_symbol->n_sect != NO_SECT)
set_arch_long(p, symbol_pointer +
vmslide);
continue;
}
}
if(section_type == S_NON_LAZY_SYMBOL_POINTERS){
set_arch_long(p, 0);
}
else{
for(m = 0; m < arch_nlocrel; m++){
if(arch_locrelocs[m].r_address &
R_SCATTERED){
sreloc = (struct
scattered_relocation_info *)
(arch_locrelocs + m);
if(sreloc->r_address +
(arch_split_segs == TRUE ?
arch_segs_read_write_addr :
arch_seg1addr) ==
s->addr + (k * sizeof(uint32_t)) &&
check_pb_la_ptr_reloc_cputype(
sreloc->r_type)){
set_arch_long(p, sreloc->r_value);
break;
}
}
}
if(m > arch_nlocrel){
error("malformed file: %s (for "
"architecture %s) "
"(no local relocation entry for lazy "
"symbol pointer %u)",
arch->file_name, arch_name, k);
redo_exit(2);
}
}
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
reset_self_modifying_stubs(
void)
{
uint32_t i, j, section_type;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
char *p;
uint32_t ncmds;
if(arch->object->mh->cputype != CPU_TYPE_I386 ||
arch->object->mh == NULL)
return;
lc = arch->object->load_commands;
ncmds = arch->object->mh->ncmds;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0 ; j < sg->nsects ; j++){
section_type = s->flags & SECTION_TYPE;
if(section_type == S_SYMBOL_STUBS &&
(s->flags & S_ATTR_SELF_MODIFYING_CODE) ==
S_ATTR_SELF_MODIFYING_CODE &&
s->reserved2 == 5){
p = contents_pointer_for_vmaddr(s->addr, 1);
memset(p, 0xf4, s->size);
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
enum
bool
check_pb_la_ptr_reloc_cputype(
unsigned int reloc_type)
{
switch(arch->object->mh_cputype){
case CPU_TYPE_MC680x0:
return (reloc_type == GENERIC_RELOC_PB_LA_PTR);
case CPU_TYPE_I386:
return (reloc_type == GENERIC_RELOC_PB_LA_PTR);
case CPU_TYPE_HPPA:
return (reloc_type == HPPA_RELOC_PB_LA_PTR);
case CPU_TYPE_SPARC:
return (reloc_type == SPARC_RELOC_PB_LA_PTR);
case CPU_TYPE_POWERPC:
return (reloc_type == PPC_RELOC_PB_LA_PTR);
}
return FALSE;
}
static
void
update_load_commands(
uint32_t vmslide)
{
uint32_t i, j, k, nmodules, size, sizeofcmds, ncmds, low_fileoff;
struct load_command *lc1, *lc2, *new_load_commands;
struct dylib_command *dl_load, *dl_id;
struct prebound_dylib_command *pbdylib1, *pbdylib2;
struct segment_command *sg;
struct section *s;
char *dylib_name, *linked_modules;
struct routines_command *rc;
struct uuid_command *uuid;
struct linkedit_data_command *code_sig;
enum bool found, prebind_all_twolevel_modules;
uint32_t ncmds1, ncmds2, mh_flags, mh_sizeofcmds;
prebind_all_twolevel_modules = TRUE;
if(arch_force_flat_namespace == TRUE)
prebind_all_twolevel_modules = FALSE;
ncmds = 0;
sizeofcmds = 0;
lc1 = arch->object->load_commands;
if(arch->object->mh != NULL){
ncmds1 = arch->object->mh->ncmds;
mh_flags = arch->object->mh->flags;
}
else{
ncmds1 = arch->object->mh64->ncmds;
mh_flags = arch->object->mh64->flags;
}
for(i = 0; i < ncmds1; i++){
if(lc1->cmd == LC_LOAD_DYLIB ||
lc1->cmd == LC_LOAD_WEAK_DYLIB ||
lc1->cmd == LC_REEXPORT_DYLIB){
dl_load = (struct dylib_command *)lc1;
dylib_name = (char *)dl_load + dl_load->dylib.name.offset;
if(unprebinding == TRUE){
dl_load->dylib.timestamp = 0;
dl_load->dylib.current_version = 0;
dl_load->dylib.compatibility_version = 0;
}
else{
found = FALSE;
for(j = 0; j < nlibs; j++){
if(strcmp(libs[j].dylib_name, dylib_name) == 0){
lc2 = libs[j].ofile->load_commands;
if(arch->object->mh != NULL)
ncmds2 = libs[j].ofile->mh->ncmds;
else
ncmds2 = libs[j].ofile->mh64->ncmds;
for(k = 0; k < ncmds2; k++){
if(lc2->cmd == LC_ID_DYLIB){
dl_id = (struct dylib_command *)lc2;
dl_load->dylib.timestamp =
dl_id->dylib.timestamp;
found = TRUE;
break;
}
lc2 = (struct load_command *)
((char *)lc2 + lc2->cmdsize);
}
break;
}
}
if(found == FALSE){
dl_load->dylib.timestamp = 0;
dl_load->dylib.current_version = 0;
dl_load->dylib.compatibility_version = 0;
}
}
}
else if(lc1->cmd == LC_ID_DYLIB){
if(unprebinding == TRUE){
dl_load = (struct dylib_command *)lc1;
dl_load->dylib.timestamp = 0;
arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
}
}
else if(lc1->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc1;
sg->vmaddr += vmslide;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
s->addr += vmslide;
s++;
}
}
else if(lc1->cmd == LC_ROUTINES){
rc = (struct routines_command *)lc1;
rc->init_address += vmslide;
}
else if(lc1->cmd == LC_UUID && unprebinding == TRUE){
uuid = (struct uuid_command *)lc1;
memset(uuid->uuid, '\0', sizeof(uuid->uuid));
}
else if(lc1->cmd == LC_CODE_SIGNATURE && unprebinding == TRUE){
code_sig = (struct linkedit_data_command *)lc1;
memset(arch->object->object_addr + code_sig->dataoff, '\0',
code_sig->datasize);
}
if(lc1->cmd != LC_PREBOUND_DYLIB){
ncmds += 1;
sizeofcmds += lc1->cmdsize;
}
else{
if(prebind_all_twolevel_modules == TRUE){
pbdylib1 = (struct prebound_dylib_command *)lc1;
linked_modules = (char *)pbdylib1 +
pbdylib1->linked_modules.offset;
for(j = 0; j < pbdylib1->nmodules; j++){
if(((linked_modules[j/8] >> (j%8)) & 1) == 0){
prebind_all_twolevel_modules = FALSE;
break;
}
}
}
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
if(arch->object->cs != NULL){
if(zero_out_prebind_checksum == TRUE)
arch->object->cs->cksum = 0;
else{
if(arch->object->cs->cksum == 0)
arch->object->cs->cksum =
arch->object->calculated_input_prebind_cksum;
}
}
if(arch->object->mh_filetype != MH_EXECUTE)
return;
if(unprebinding == FALSE){
struct macosx_deployment_target deployment_version;
get_macosx_deployment_target(&deployment_version);
if(deployment_version.major >= 4)
return;
}
if(mh_flags & MH_ALLMODSBOUND){
if((mh_flags & MH_PREBINDABLE) != MH_PREBINDABLE){
error("malformed file: %s (MH_ALLMODSBOUND is set without "
"MH_PREBINDABLE)",
arch->file_name);
redo_exit(2);
}
if(arch->object->mh != NULL)
arch->object->mh->flags &= ~MH_ALLMODSBOUND;
else
arch->object->mh64->flags &= ~MH_ALLMODSBOUND;
prebind_all_twolevel_modules = TRUE;
}
else{
if(mh_flags & MH_PREBINDABLE){
prebind_all_twolevel_modules = FALSE;
}
}
if(unprebinding == FALSE){
for(i = 0; i < nlibs; i++){
lc1 = arch->object->load_commands;
for(j = 0; j < ncmds1; j++){
if(lc1->cmd == LC_PREBOUND_DYLIB){
pbdylib1 = (struct prebound_dylib_command *)lc1;
dylib_name = (char *)pbdylib1 + pbdylib1->name.offset;
if(strcmp(libs[i].dylib_name, dylib_name) == 0){
libs[i].LC_PREBOUND_DYLIB_found = TRUE;
if(libs[i].nmodtab <= pbdylib1->nmodules){
libs[i].LC_PREBOUND_DYLIB_size =
pbdylib1->cmdsize;
}
else{
size = pbdylib1->cmdsize -
(sizeof(struct prebound_dylib_command) +
rnd(strlen(dylib_name) + 1,
sizeof(uint32_t)));
if((libs[i].nmodtab + 7)/8 <= size){
libs[i].LC_PREBOUND_DYLIB_size =
pbdylib1->cmdsize;
}
else{
nmodules = libs[i].nmodtab +
(libs[i].nmodtab >> 2);
if(nmodules < 64)
nmodules = 64;
size = sizeof(struct
prebound_dylib_command) +
rnd(strlen(dylib_name)+1,
sizeof(uint32_t)) +
rnd(nmodules / 8, sizeof(uint32_t));
libs[i].LC_PREBOUND_DYLIB_size = size;
}
}
ncmds += 1;
sizeofcmds += libs[i].LC_PREBOUND_DYLIB_size;
break;
}
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
}
}
if(arch->object->mh != NULL)
mh_sizeofcmds = arch->object->mh->sizeofcmds;
else
mh_sizeofcmds = arch->object->mh64->sizeofcmds;
if(unprebinding == TRUE){
if(prebind_all_twolevel_modules &&
(mh_flags & MH_PREBOUND) == MH_PREBOUND){
if(arch->object->mh != NULL)
arch->object->mh->flags |= MH_ALLMODSBOUND;
else
arch->object->mh64->flags |= MH_ALLMODSBOUND;
}
}
else{
for(i = 0; i < nlibs; i++){
if(libs[i].LC_PREBOUND_DYLIB_found == FALSE){
nmodules = libs[i].nmodtab + (libs[i].nmodtab >> 2);
if(nmodules < 64)
nmodules = 64;
size = sizeof(struct prebound_dylib_command) +
rnd(strlen(libs[i].dylib_name) + 1, sizeof(uint32_t))+
rnd(nmodules / 8, sizeof(uint32_t));
libs[i].LC_PREBOUND_DYLIB_size = size;
sizeofcmds += libs[i].LC_PREBOUND_DYLIB_size;
ncmds++;
}
}
if(sizeofcmds > mh_sizeofcmds){
low_fileoff = UINT_MAX;
lc1 = arch->object->load_commands;
for(i = 0; i < ncmds1; i++){
if(lc1->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc1;
s = (struct section *)
((char *)sg + sizeof(struct segment_command));
if(sg->nsects != 0){
for(j = 0; j < sg->nsects; j++){
if(s->size != 0 &&
(s->flags & S_ZEROFILL) != S_ZEROFILL &&
(s->flags & S_THREAD_LOCAL_ZEROFILL) !=
S_THREAD_LOCAL_ZEROFILL &&
s->offset < low_fileoff)
low_fileoff = s->offset;
s++;
}
}
else{
if(sg->filesize != 0 && sg->fileoff < low_fileoff)
low_fileoff = sg->fileoff;
}
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
if(sizeofcmds + sizeof(struct mach_header) > low_fileoff){
error("prebinding can't be redone for: %s (for architecture"
" %s) because larger updated load commands do not fit "
"(the program must be relinked)", arch->file_name,
arch_name);
#ifdef LIBRARY_API
if(check_if_needed == TRUE){
only_if_needed_retval =
REDO_PREBINDING_NEEDS_REBUILDING;
return;
}
#endif
redo_exit(2);
}
}
}
new_load_commands = allocate(sizeofcmds);
memset(new_load_commands, '\0', sizeofcmds);
lc1 = arch->object->load_commands;
lc2 = new_load_commands;
for(i = 0; i < ncmds1; i++){
if(lc1->cmd == LC_PREBOUND_DYLIB){
if(unprebinding == FALSE){
pbdylib1 = (struct prebound_dylib_command *)lc1;
pbdylib2 = (struct prebound_dylib_command *)lc2;
dylib_name = (char *)pbdylib1 + pbdylib1->name.offset;
for(j = 0; j < nlibs; j++){
if(strcmp(libs[j].dylib_name, dylib_name) == 0){
pbdylib2->cmd = LC_PREBOUND_DYLIB;
pbdylib2->cmdsize = libs[j].LC_PREBOUND_DYLIB_size;
pbdylib2->name.offset =
sizeof(struct prebound_dylib_command);
strcpy(((char *)pbdylib2) +
sizeof(struct prebound_dylib_command),
dylib_name);
pbdylib2->nmodules = libs[j].nmodtab;
pbdylib2->linked_modules.offset =
sizeof(struct prebound_dylib_command) +
rnd(strlen(dylib_name) + 1,
sizeof(uint32_t));
linked_modules = ((char *)pbdylib2) +
sizeof(struct prebound_dylib_command) +
rnd(strlen(dylib_name) + 1,
sizeof(uint32_t));
if(libs[j].ofile->mh != NULL)
mh_flags = libs[j].ofile->mh->flags;
else
mh_flags = libs[j].ofile->mh64->flags;
for(k = 0; k < libs[j].nmodtab; k++){
if(libs[j].module_states[k] == LINKED ||
(prebind_all_twolevel_modules == TRUE &&
(mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL))
linked_modules[k / 8] |= 1 << k % 8;
}
lc2 = (struct load_command *)
((char *)lc2 + lc2->cmdsize);
break;
}
}
}
}
else{
memcpy(lc2, lc1, lc1->cmdsize);
lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
if(unprebinding == FALSE){
for(i = 0; i < nlibs; i++){
if(libs[i].LC_PREBOUND_DYLIB_found == FALSE){
pbdylib2 = (struct prebound_dylib_command *)lc2;
pbdylib2->cmd = LC_PREBOUND_DYLIB;
pbdylib2->cmdsize = libs[i].LC_PREBOUND_DYLIB_size;
pbdylib2->name.offset =
sizeof(struct prebound_dylib_command);
strcpy(((char *)pbdylib2) +
sizeof(struct prebound_dylib_command),
libs[i].dylib_name);
pbdylib2->nmodules = libs[i].nmodtab;
pbdylib2->linked_modules.offset =
sizeof(struct prebound_dylib_command) +
rnd(strlen(libs[i].dylib_name) + 1,
sizeof(uint32_t));
linked_modules = ((char *)pbdylib2) +
sizeof(struct prebound_dylib_command) +
rnd(strlen(libs[i].dylib_name) + 1,
sizeof(uint32_t));
if(libs[i].ofile->mh != NULL)
mh_flags = libs[i].ofile->mh->flags;
else
mh_flags = libs[i].ofile->mh64->flags;
for(j = 0; j < libs[i].nmodtab; j++){
if(libs[i].module_states[j] == LINKED ||
(prebind_all_twolevel_modules == TRUE &&
(mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL))
linked_modules[j / 8] |= 1 << j % 8;
}
lc2 = (struct load_command *)
((char *)lc2 + lc2->cmdsize);
}
}
}
memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
if(mh_sizeofcmds > sizeofcmds){
memset((char *)arch->object->load_commands + sizeofcmds, '\0',
(mh_sizeofcmds - sizeofcmds));
}
if(arch->object->mh != NULL) {
arch->object->mh->sizeofcmds = sizeofcmds;
arch->object->mh->ncmds = ncmds;
} else {
arch->object->mh64->sizeofcmds = sizeofcmds;
arch->object->mh64->ncmds = ncmds;
}
free(new_load_commands);
lc1 = arch->object->load_commands;
for(i = 0; i < ncmds; i++){
switch(lc1->cmd){
case LC_SYMTAB:
arch->object->st = (struct symtab_command *)lc1;
break;
case LC_DYSYMTAB:
arch->object->dyst = (struct dysymtab_command *)lc1;
break;
case LC_TWOLEVEL_HINTS:
arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
break;
case LC_PREBIND_CKSUM:
arch->object->cs = (struct prebind_cksum_command *)lc1;
break;
case LC_SEGMENT:
sg = (struct segment_command *)lc1;
if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
arch->object->seg_linkedit = sg;
break;
case LC_CODE_SIGNATURE:
arch->object->code_sig_cmd =
(struct linkedit_data_command *)lc1;
break;
case LC_SEGMENT_SPLIT_INFO:
arch->object->split_info_cmd =
(struct linkedit_data_command *)lc1;
break;
case LC_FUNCTION_STARTS:
arch->object->func_starts_info_cmd =
(struct linkedit_data_command *)lc1;
break;
}
lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
}
}
#ifndef LIBRARY_API
__private_extern__
void
warning_arch(
struct arch *arch,
struct member *member,
char *format,
...)
{
va_list ap;
va_start(ap, format);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, format, ap);
va_end(ap);
if(member != NULL){
fprintf(stderr, "%s(%.*s)", arch->file_name,
(int)member->member_name_size, member->member_name);
}
else
fprintf(stderr, "%s", arch->file_name);
if(arch->fat_arch_name != NULL)
fprintf(stderr, " (for architecture %s)\n", arch->fat_arch_name);
else
fprintf(stderr, "\n");
va_end(ap);
}
__private_extern__
void
error_arch(
struct arch *arch,
struct member *member,
char *format,
...)
{
va_list ap;
va_start(ap, format);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, format, ap);
va_end(ap);
if(member != NULL){
fprintf(stderr, "%s(%.*s)", arch->file_name,
(int)member->member_name_size, member->member_name);
}
else
fprintf(stderr, "%s", arch->file_name);
if(arch->fat_arch_name != NULL)
fprintf(stderr, " (for architecture %s)\n", arch->fat_arch_name);
else
fprintf(stderr, "\n");
va_end(ap);
errors++;
}
__private_extern__
void
fatal_arch(
struct arch *arch,
struct member *member,
char *format,
...)
{
va_list ap;
va_start(ap, format);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, format, ap);
va_end(ap);
if(member != NULL){
fprintf(stderr, "%s(%.*s)", arch->file_name,
(int)member->member_name_size, member->member_name);
}
else
fprintf(stderr, "%s", arch->file_name);
if(arch->fat_arch_name != NULL)
fprintf(stderr, " (for architecture %s)\n", arch->fat_arch_name);
else
fprintf(stderr, "\n");
va_end(ap);
if(check_for_non_prebound == TRUE)
exit(0);
exit(2);
}
#else
static
void
vmessage(
const char *format,
va_list ap)
{
uint32_t new;
setup_error_message_buffer();
#ifdef __OPENSTEP__
new = vsprintf(last, format, ap);
#else
new = vsnprintf(last, left, format, ap);
#endif
last += new;
left -= new;
}
static
void
message(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vmessage(format, ap);
va_end(ap);
}
static
void
message_with_arch(
struct arch *arch,
struct member *member,
const char *format,
va_list ap)
{
uint32_t new;
setup_error_message_buffer();
#ifdef __OPENSTEP__
new = vsprintf(last, format, ap);
#else
new = vsnprintf(last, left, format, ap);
#endif
last += new;
left -= new;
if(member != NULL){
#ifdef __OPENSTEP__
new = sprintf(last,
#else
new = snprintf(last, left,
#endif
"%s(%.*s)", arch->file_name,
(int)member->member_name_size, member->member_name);
last += new;
left -= new;
}
else{
#ifdef __OPENSTEP__
new = sprintf(last,
#else
new = snprintf(last, left,
#endif
"%s", arch->file_name);
last += new;
left -= new;
}
if(arch->fat_arch_name != NULL){
#ifdef __OPENSTEP__
new = sprintf(last,
#else
new = snprintf(last, left,
#endif
" (for architecture %s)", arch->fat_arch_name);
last += new;
left -= new;
}
}
__private_extern__
void
warning_arch(
struct arch *arch,
struct member *member,
char *format,
...)
{
va_list ap;
va_start(ap, format);
message_with_arch(arch, member, format, ap);
va_end(ap);
}
__private_extern__
void
error_arch(
struct arch *arch,
struct member *member,
char *format,
...)
{
va_list ap;
va_start(ap, format);
message_with_arch(arch, member, format, ap);
va_end(ap);
errors++;
}
__private_extern__
void
fatal_arch(
struct arch *arch,
struct member *member,
char *format,
...)
{
va_list ap;
va_start(ap, format);
message_with_arch(arch, member, format, ap);
va_end(ap);
if(check_only == TRUE)
retval = PREBINDING_UNKNOWN;
longjmp(library_env, 1);
}
__private_extern__ uint32_t errors = 0;
__private_extern__
void
warning(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vmessage(format, ap);
va_end(ap);
}
__private_extern__
void
error(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vmessage(format, ap);
va_end(ap);
errors++;
}
__private_extern__
void
error_with_arch(
const char *arch_name,
const char *format,
...)
{
va_list ap;
va_start(ap, format);
if(arch_name != NULL)
message("for architecture: %s ", arch_name);
vmessage(format, ap);
va_end(ap);
errors++;
}
__private_extern__
void
system_error(
const char *format,
...)
{
va_list ap;
va_start(ap, format);
vmessage(format, ap);
message(" (%s)", strerror(errno));
va_end(ap);
errors++;
}
__private_extern__
void
my_mach_error(
kern_return_t r,
char *format,
...)
{
va_list ap;
va_start(ap, format);
vmessage(format, ap);
message(" (%s)", mach_error_string(r));
va_end(ap);
errors++;
}
__private_extern__
void *
allocate(
size_t size)
{
void *p;
if(library_zone == NULL){
library_zone = malloc_create_zone(vm_page_size, 0);
if(library_zone == NULL)
fatal("malloc_create_zone() failed");
malloc_set_zone_name(library_zone, "redo_prebinding");
}
if(size == 0)
return(NULL);
if((p = malloc_zone_malloc(library_zone, size)) == NULL)
system_fatal("virtual memory exhausted (malloc_zone_malloc() "
" failed)");
return(p);
}
__private_extern__
void *
reallocate(
void *p,
size_t size)
{
if(library_zone == NULL){
library_zone = malloc_create_zone(vm_page_size, 1);
if(library_zone == NULL)
fatal("malloc_create_zone() failed");
malloc_set_zone_name(library_zone, "redo_prebinding");
}
if(p == NULL)
return(allocate(size));
if((p = malloc_zone_realloc(library_zone, p, size)) == NULL)
system_fatal("virtual memory exhausted (malloc_zone_realloc() "
" failed)");
return(p);
}
__private_extern__
char *
savestr(
const char *s)
{
uint32_t len;
char *r;
len = strlen(s) + 1;
r = (char *)allocate(len);
strcpy(r, s);
return(r);
}
__private_extern__
char *
makestr(
const char *args,
...)
{
va_list ap;
char *s, *p;
uint32_t 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);
}
__private_extern__
void
archive_error(
struct ofile *ofile,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
if(ofile->file_type == OFILE_FAT){
message("%s: for architecture %s archive: %s ",
progname, ofile->arch_flag.name, ofile->file_name);
}
else{
message("%s: archive: %s ", progname, ofile->file_name);
}
vmessage(format, ap);
message("\n");
va_end(ap);
errors++;
}
__private_extern__
void
archive_member_error(
struct ofile *ofile,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
if(ofile->file_type == OFILE_FAT){
message("%s: for architecture %s archive member: %s(%.*s) ",
progname, ofile->arch_flag.name, ofile->file_name,
(int)ofile->member_name_size, ofile->member_name);
}
else{
message("%s: archive member: %s(%.*s) ", progname, ofile->file_name,
(int)ofile->member_name_size, ofile->member_name);
}
vmessage(format, ap);
message("\n");
va_end(ap);
errors++;
}
__private_extern__
void
Mach_O_error(
struct ofile *ofile,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
if(ofile->file_type == OFILE_FAT){
if(ofile->arch_type == OFILE_ARCHIVE){
message("%s: for architecture %s object: %s(%.*s) ", progname,
ofile->arch_flag.name, ofile->file_name,
(int)ofile->member_name_size, ofile->member_name);
}
else{
message("%s: for architecture %s object: %s ", progname,
ofile->arch_flag.name, ofile->file_name);
}
}
else if(ofile->file_type == OFILE_ARCHIVE){
if(ofile->member_type == OFILE_FAT){
message("%s: for object: %s(%.*s) architecture %s ", progname,
ofile->file_name, (int)ofile->member_name_size,
ofile->arch_flag.name, ofile->member_name);
}
else{
message("%s: object: %s(%.*s) ", progname, ofile->file_name,
(int)ofile->member_name_size, ofile->member_name);
}
}
else{
message("%s: object: %s ", progname, ofile->file_name);
}
vmessage(format, ap);
message("\n");
va_end(ap);
errors++;
}
#endif
#include <sys/attr.h>
struct fileinfobuf {
uint32_t info_length;
uint32_t finderinfo[8];
char data_length[sizeof(uint64_t)];
char resource_length[sizeof(uint64_t)];
};
static
enum bool
has_resource_fork(
char *filename)
{
int err;
struct attrlist alist;
struct fileinfobuf finfo;
uint64_t data_length;
uint64_t resource_length;
alist.bitmapcount = 5;
alist.reserved = 0;
alist.commonattr = ATTR_CMN_FNDRINFO;
alist.volattr = 0;
alist.dirattr = 0;
alist.fileattr = ATTR_FILE_DATALENGTH | ATTR_FILE_RSRCLENGTH;
alist.forkattr = 0;
err = getattrlist(filename, &alist, &finfo, sizeof(finfo), 0);
if(debug == TRUE){
printf("getattrlist() returned = %d\n", err);
if(err == 0){
printf("finfo.info_length = %u\n", finfo.info_length);
printf("sizeof(finfo) = %lu\n", sizeof(finfo));
}
}
if(err != 0)
return(FALSE);
memcpy(&resource_length, finfo.resource_length, sizeof(uint64_t));
memcpy(&data_length, finfo.data_length, sizeof(uint64_t));
if(debug == TRUE){
printf("Resource fork len is %llu\n", resource_length);
printf("Data fork len is %llu\n", data_length);
}
if(resource_length != 0)
return(TRUE);
if((finfo.finderinfo[0] != 0) || (finfo.finderinfo[1] != 0))
return(TRUE);
return(FALSE);
}