#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include "stuff/ofile.h"
#include "stuff/allocate.h"
#include "stuff/rnd.h"
#include "stuff/errors.h"
#include "stuff/seg_addr_table.h"
#include "stuff/guess_short_name.h"
#include "stuff/dylib_table.h"
#include "stuff/dylib_roots.h"
#include "stuff/macosx_deployment_target.h"
#define DEFAULT_SEG1ADDR_X10_1 0x41300000
#define DEFAULT_READ_ONLY_ADDR_X10_1 0x70000000
#define DEFAULT_READ_WRITE_ADDR_X10_1 0x80000000
#define DEFAULT_SEG1ADDR_X10_2 0x8fe00000
#define DEFAULT_READ_ONLY_ADDR_X10_2 0x90000000
#define DEFAULT_READ_WRITE_ADDR_X10_2 0xa0000000
#define DEFAULT_DEBUG_ADDR_X10_3 0x40000000
#define SPLIT_OVERFLOW_MASK_X10_3 0xf8000000
#define SPLIT_OVERFLOW_MASK_X10_4 0xf0000000
#define MAX_ADDR 0xc0000000
#define READ_ONLY_SEGMENT_NAME "<< read-only segment for split libraries >>"
#define READ_WRITE_SEGMENT_NAME "<< read-write segment for split libraries >>"
#define DEFAULT_FACTOR 0x1
#define DEFAULT_ROUND_X10_3 0x10000
#define DEFAULT_ROUND_X10_4 0x1000
char *progname = NULL;
struct max_sizes {
uint32_t all;
uint32_t read_only;
uint32_t read_write;
};
struct layout_info {
char *install_name;
char *image_file_name;
struct max_sizes max_sizes;
enum bool split;
enum bool use_debug_region;
enum bool assigned;
char *short_name;
uint32_t seg1addr;
uint32_t segs_read_only_addr;
uint32_t segs_read_write_addr;
struct seg_addr_table *current_entry;
};
struct info {
char *seg_addr_table_name;
struct seg_addr_table *seg_addr_table;
uint32_t table_size;
struct layout_info **layout_info;
struct layout_info **sorted_flat_layout_info;
uint32_t nsorted_flat;
struct layout_info **sorted_split_read_only_layout_info;
struct layout_info **sorted_split_read_write_layout_info;
uint32_t nsorted_split;
uint32_t seg1addr;
uint32_t next_flat_line;
enum bool allocate_flat_increasing;
uint32_t debug_seg1addr;
uint32_t start_segs_read_only_addr;
uint32_t start_segs_read_write_addr;
uint32_t segs_read_only_addr;
uint32_t segs_read_write_addr;
uint32_t next_split_line;
uint32_t default_read_only_addr;
uint32_t default_read_write_addr;
struct arch_flag *arch_flags;
uint32_t narch_flags;
enum bool all_archs;
char *output_file_name;
uint32_t factor;
uint32_t round;
char *release_name;
enum bool disablewarnings;
uint32_t overflow_mask;
struct macosx_deployment_target macosx_deployment_target;
};
static void usage(
void);
static FILE * create_output_file(
char *output_file_name);
static int qsort_flat(
const struct layout_info **p1,
const struct layout_info **p2);
static int qsort_split_read_only(
const struct layout_info **p1,
const struct layout_info **p2);
static int qsort_split_read_write(
const struct layout_info **p1,
const struct layout_info **p2);
static void flat_overlap_error(
struct info *info,
uint32_t i1,
uint32_t i2,
enum bool next_address);
static void split_overlap_error(
struct info *info,
uint32_t i1,
uint32_t i2,
struct layout_info **sorted_layout_info,
char *segment,
enum bool next_address);
static struct seg_addr_table * search_seg_addr_table_for_fixed(
struct seg_addr_table *seg_addr_table,
uint32_t seg1addr,
uint32_t size);
static uint32_t next_flat_seg1addr(
struct info *info,
uint32_t size);
static uint32_t next_debug_seg1addr(
struct info *info,
uint32_t size);
static char * get_image_file_name(
struct info *info,
char *install_name,
enum bool try_symroot,
enum bool no_error_if_missing);
static void new_table_processor(
struct seg_addr_table *entry,
FILE *out_fp,
void *cookie);
static void sizes_and_addresses(
struct ofile *ofile,
char *arch_name,
void *cookie);
static void dylib_table_processor(
struct seg_addr_table *entry,
FILE *out_fp,
void *cookie);
static void get_seg1addr(
struct ofile *ofile,
char *arch_name,
void *cookie);
int
main(
int argc,
char **argv,
char **envp)
{
int a;
uint32_t i, j, used, max, size, seg1addr;
char *endp, *user, *dylib_table_name, *base_name, *short_name,
*image_file_name;
struct dylib_table *dylib_table;
FILE *out_fp;
time_t tloc;
struct info info;
struct seg_addr_table *entry;
struct layout_info *layout_info;
enum bool seg1addr_specified, segs_read_only_addr_specified,
segs_read_write_addr_specified, relayout, update, create,
checkonly, update_overlaps, allocate_flat_specified,
relayout_nonsplit;
enum bool found, is_framework, next_flat, next_split, next_debug;
enum bool operation_specified, from_dylib_table, create_dylib_table;
char *install_name, *has_suffix;
struct stat stat_buf;
struct macosx_deployment_target macosx_deployment_target;
progname = argv[0];
dylib_table_name = NULL;
dylib_table = NULL;
info.seg_addr_table = NULL;
info.seg_addr_table_name = NULL;
info.table_size = 0;
info.layout_info = NULL;
info.arch_flags = NULL;
info.narch_flags = 0;
info.all_archs = FALSE;
info.disablewarnings = FALSE;
operation_specified = FALSE;
relayout = FALSE;
update = FALSE;
checkonly = FALSE;
update_overlaps = FALSE;
create = FALSE;
from_dylib_table = FALSE;
create_dylib_table = FALSE;
relayout_nonsplit = FALSE;
info.output_file_name = NULL;
out_fp = NULL;
seg1addr_specified = FALSE;
allocate_flat_specified = FALSE;
segs_read_only_addr_specified = FALSE;
segs_read_write_addr_specified = FALSE;
info.factor = DEFAULT_FACTOR;
get_macosx_deployment_target(&macosx_deployment_target);
if(macosx_deployment_target.major >= 4) {
info.round = DEFAULT_ROUND_X10_4;
info.overflow_mask = SPLIT_OVERFLOW_MASK_X10_4;
} else {
info.round = DEFAULT_ROUND_X10_3;
info.overflow_mask = SPLIT_OVERFLOW_MASK_X10_3;
}
if(macosx_deployment_target.major >= 2){
info.allocate_flat_increasing = FALSE;
info.seg1addr = DEFAULT_SEG1ADDR_X10_2;
info.segs_read_only_addr = DEFAULT_READ_ONLY_ADDR_X10_2;
info.segs_read_write_addr = DEFAULT_READ_WRITE_ADDR_X10_2;
}
else{
info.allocate_flat_increasing = TRUE;
info.seg1addr = DEFAULT_SEG1ADDR_X10_1;
info.segs_read_only_addr = DEFAULT_READ_ONLY_ADDR_X10_1;
info.segs_read_write_addr = DEFAULT_READ_WRITE_ADDR_X10_1;
}
info.default_read_only_addr = info.segs_read_only_addr;
info.default_read_write_addr = info.segs_read_write_addr;
info.start_segs_read_only_addr = info.segs_read_only_addr;
info.start_segs_read_write_addr = info.segs_read_write_addr;
info.macosx_deployment_target = macosx_deployment_target;
info.debug_seg1addr = DEFAULT_DEBUG_ADDR_X10_3;
info.release_name = NULL;
for(a = 1; a < argc; a++){
if(argv[a][0] == '-'){
if(strcmp(argv[a], "-relayout") == 0){
if(operation_specified == TRUE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
relayout = TRUE;
}
else if(strcmp(argv[a], "-update") == 0){
if(operation_specified == TRUE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
update = TRUE;
}
else if(strcmp(argv[a], "-checkonly") == 0){
if(operation_specified == TRUE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
checkonly = TRUE;
}
else if(strcmp(argv[a], "-update_overlaps") == 0){
if(operation_specified == TRUE &&
relayout_nonsplit == FALSE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
update_overlaps = TRUE;
}
else if(strcmp(argv[a], "-create") == 0){
if(operation_specified == TRUE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
create = TRUE;
}
else if(strcmp(argv[a], "-relayout_nonsplit") == 0){
if(operation_specified == TRUE && update_overlaps == FALSE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
relayout_nonsplit = TRUE;
}
else if(strcmp(argv[a], "-from_dylib_table") == 0){
if(operation_specified == TRUE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
from_dylib_table = TRUE;
}
else if(strcmp(argv[a], "-create_dylib_table") == 0){
if(operation_specified == TRUE){
error("more than one operation specified");
usage();
}
operation_specified = TRUE;
create_dylib_table = TRUE;
}
else if(strcmp(argv[a], "-seg_addr_table") == 0){
if(a + 1 == argc){
error("missing argument(s) to %s option", argv[a]);
usage();
}
if(info.seg_addr_table != NULL){
error("more than one: %s option", argv[a]);
usage();
}
info.seg_addr_table_name = argv[a+1];
info.seg_addr_table = parse_seg_addr_table(argv[a+1],
argv[a], argv[a+1], &info.table_size);
a++;
}
else if(strcmp(argv[a], "-dylib_table") == 0){
if(a + 1 == argc){
error("missing argument(s) to %s option", argv[a]);
usage();
}
if(dylib_table_name != NULL){
error("more than one: %s option", argv[a]);
usage();
}
dylib_table_name = argv[a+1];
dylib_table = parse_dylib_table(argv[a+1], argv[a],
argv[a+1]);
a++;
}
else if(strcmp(argv[a], "-seg1addr") == 0){
if(a + 1 >= argc){
error("%s: argument missing", argv[a]);
usage();
}
if(seg1addr_specified == TRUE){
error("more than one: %s option", argv[a]);
usage();
}
info.seg1addr = strtoul(argv[a+1], &endp, 16);
if(*endp != '\0')
fatal("address for %s %s not a proper "
"hexadecimal number", argv[a], argv[a+1]);
seg1addr_specified = TRUE;
a++;
}
else if(strcmp(argv[a], "-allocate_flat") == 0){
if(a + 1 >= argc){
error("%s: argument missing", argv[a]);
usage();
}
if(allocate_flat_specified == TRUE){
error("more than one: %s option", argv[a]);
usage();
}
if(strcmp(argv[a+1], "increasing") == 0)
info.allocate_flat_increasing = TRUE;
else if(strcmp(argv[a+1], "decreasing") == 0)
info.allocate_flat_increasing = FALSE;
else
fatal("argument: %s for %s not valid (can be either "
"increasing or decreasing)", argv[a+1], argv[a]);
allocate_flat_specified = TRUE;
a++;
}
else if(strcmp(argv[a], "-segs_read_only_addr") == 0){
if(a + 1 >= argc){
error("%s: argument missing", argv[a]);
usage();
}
if(segs_read_only_addr_specified == TRUE){
error("more than one: %s option", argv[a]);
usage();
}
info.segs_read_only_addr =
strtoul(argv[a+1], &endp, 16);
info.start_segs_read_only_addr = info.segs_read_only_addr;
if(*endp != '\0')
fatal("address for %s %s not a proper "
"hexadecimal number", argv[a], argv[a+1]);
segs_read_only_addr_specified = TRUE;
a++;
}
else if(strcmp(argv[a], "-segs_read_write_addr") == 0){
if(a + 1 >= argc){
error("%s: argument missing", argv[a]);
usage();
}
if(segs_read_write_addr_specified == TRUE){
error("more than one: %s option", argv[a]);
usage();
}
info.segs_read_write_addr =
strtoul(argv[a+1], &endp, 16);
info.start_segs_read_write_addr = info.segs_read_write_addr;
if(*endp != '\0')
fatal("address for %s %s not a proper "
"hexadecimal number", argv[a], argv[a+1]);
segs_read_write_addr_specified = TRUE;
a++;
}
else if(strcmp(argv[a], "-arch") == 0){
if(a + 1 == argc){
error("missing argument(s) to %s option", argv[a]);
usage();
}
if(strcmp("all", argv[a+1]) == 0){
info.all_archs = TRUE;
}
else{
info.arch_flags = reallocate(info.arch_flags,
(info.narch_flags + 1) *
sizeof(struct arch_flag));
if(get_arch_from_flag(argv[a+1],
info.arch_flags + info.narch_flags) == 0){
error("unknown architecture specification flag: "
"%s %s", argv[a], argv[a+1]);
arch_usage();
usage();
}
info.narch_flags++;
}
a++;
}
else if(strcmp(argv[a], "-o") == 0){
if(a + 1 == argc){
error("missing argument(s) to %s option", argv[a]);
usage();
}
if(info.output_file_name != NULL){
error("more than one: %s %s option", argv[a],argv[a+1]);
usage();
}
info.output_file_name = argv[a+1];
a++;
}
else if(strcmp(argv[a], "-release") == 0){
if(a + 1 == argc){
error("missing argument(s) to %s option", argv[a]);
usage();
}
if(info.release_name != NULL){
error("more than one: %s option", argv[a]);
usage();
}
info.release_name = argv[a+1];
a++;
}
else if(strcmp(argv[a], "-disablewarnings") == 0){
info.disablewarnings = TRUE;
}
else{
error("unknown option: %s\n", argv[a]);
usage();
}
}
else{
error("unknown argument: %s\n", argv[a]);
usage();
}
}
if(info.narch_flags == 0)
info.all_archs = TRUE;
if(operation_specified == FALSE){
error("no operation specified");
usage();
}
if(checkonly == FALSE && info.output_file_name == NULL){
error("must specify an output with the -o option");
usage();
}
if((checkonly == TRUE || relayout == TRUE) &&
info.disablewarnings == TRUE){
warning("-disablewarnings has no effect with -checkonly or "
"-relayout");
info.disablewarnings = FALSE;
}
if(update == TRUE || update_overlaps == TRUE){
if(seg1addr_specified == TRUE)
fatal("can't specify -seg1addr option when -update or "
"-update_overlaps is used");
if(segs_read_only_addr_specified == TRUE)
fatal("can't specify -segs_read_only_addr option when -update "
"or -update_overlaps is used");
if(segs_read_write_addr_specified == TRUE)
fatal("can't specify -segs_read_write_addr option when -update "
"or -update_overlaps is used");
}
if(info.seg_addr_table == NULL && from_dylib_table == FALSE)
info.seg_addr_table = parse_default_seg_addr_table(
&info.seg_addr_table_name, &info.table_size);
#ifdef DEBUG
if(dylib_table == NULL)
dylib_table = parse_default_dylib_table(&dylib_table_name);
if(dylib_table != NULL){
printf("dylib_table %s\n", dylib_table_name);
for(i = 0; dylib_table[i].name != NULL; i++){
printf(" %d\n", i);
printf("\tname = %s\n", dylib_table[i].name);
printf("\tseg1addr = 0x%x\n",
(unsigned int)dylib_table[i].seg1addr);
install_name = guess_dylib_install_name(dylib_table[i].name);
if(install_name != NULL)
printf("\tinstall_name = %s\n", install_name);
}
}
if(info.seg_addr_table != NULL){
printf("seg_addr_table %s\n", info.seg_addr_table_name);
for(i = 0; info.seg_addr_table[i].install_name != NULL; i++){
printf(" %d\n", i);
printf("\tinstall_name = %s\n",
info.seg_addr_table[i].install_name);
printf("\tsplit = %s\n", info.seg_addr_table[i].split == TRUE ?
"TRUE" : "FALSE");
if(info.seg_addr_table[i].split == TRUE){
printf("\tsegs_read_only_addr = 0x%x\n",
(unsigned int)info.seg_addr_table[i].segs_read_only_addr);
printf("\tsegs_read_write_addr = 0x%x\n",
(unsigned int)info.seg_addr_table[i].segs_read_write_addr);
}
else{
printf("\tseg1addr = 0x%x\n",
(unsigned int)info.seg_addr_table[i].seg1addr);
}
short_name = guess_short_name(
info.seg_addr_table[i].install_name,
&is_framework, &has_suffix);
if(short_name != NULL){
printf("\tshort_name = %s\n", short_name);
printf("\tis_framework = %s\n", is_framework == TRUE ?
"TRUE" : "FALSE");
printf("\thas_suffix = %s\n", has_suffix == NULL ?
"NULL" : has_suffix);
if(search_dylib_table(dylib_table, short_name) == NULL)
printf("\tNOT in dylib_table\n");
else
printf("\thas entry in dylib_table\n");
}
}
}
#endif
if(from_dylib_table == TRUE){
if(dylib_table == NULL)
dylib_table = parse_default_dylib_table(&dylib_table_name);
for(i = 0; dylib_table[i].name != NULL; i++){
install_name = guess_dylib_install_name(dylib_table[i].name);
if(install_name == NULL)
error("can't guess install name for: %s",
dylib_table[i].name);
else{
if(out_fp == NULL)
out_fp = create_output_file(info.output_file_name);
fprintf(out_fp, "0x%x\t%s\n",
(unsigned int)dylib_table[i].seg1addr,
install_name);
}
}
}
if(create_dylib_table == TRUE){
out_fp = create_output_file(info.output_file_name);
process_seg_addr_table(info.seg_addr_table_name, out_fp, progname,
dylib_table_processor, &info);
}
if(update == TRUE || checkonly == TRUE || update_overlaps == TRUE){
next_flat = FALSE;
next_debug = FALSE;
next_split = FALSE;
for(i = 0 ; i < info.table_size; i++){
entry = info.seg_addr_table + i;
if(strcmp(entry->install_name,
NEXT_FLAT_ADDRESS_TO_ASSIGN) == 0){
if(next_flat == TRUE)
fatal("segment address table: %s has more than one "
"entry for %s", info.seg_addr_table_name,
NEXT_FLAT_ADDRESS_TO_ASSIGN);
if(entry->split == TRUE)
fatal("segment address table: %s entry for %s is not "
"a single address", info.seg_addr_table_name,
NEXT_FLAT_ADDRESS_TO_ASSIGN);
next_flat = TRUE;
if(relayout_nonsplit == FALSE)
info.seg1addr = entry->seg1addr;
info.next_flat_line = entry->line;
}
else if(strcmp(entry->install_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN) == 0){
if(next_split == TRUE)
fatal("segment address table: %s has more than one "
"entry for %s", info.seg_addr_table_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN);
if(entry->split == FALSE)
fatal("segment address table: %s entry for %s is "
"a single address", info.seg_addr_table_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN);
next_split = TRUE;
info.segs_read_only_addr = entry->segs_read_only_addr;
info.segs_read_write_addr = entry->segs_read_write_addr;
info.next_split_line = entry->line;
}
else if(strcmp(entry->install_name,
NEXT_DEBUG_ADDRESS_TO_ASSIGN) == 0){
if(next_debug == TRUE)
fatal("segment address table: %s has more than one "
"entry for %s", info.seg_addr_table_name,
NEXT_DEBUG_ADDRESS_TO_ASSIGN);
if(entry->split == TRUE)
fatal("segment address table: %s entry for %s is not "
"a single address", info.seg_addr_table_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN);
next_debug = TRUE;
if(relayout_nonsplit == FALSE)
info.debug_seg1addr = entry->seg1addr;
}
}
if(next_flat == FALSE && macosx_deployment_target.major < 4)
error("segment address table: %s does not have an entry for %s",
info.seg_addr_table_name, NEXT_FLAT_ADDRESS_TO_ASSIGN);
if(next_split == FALSE)
error("segment address table: %s does not have an entry for %s",
info.seg_addr_table_name, NEXT_SPLIT_ADDRESS_TO_ASSIGN);
if(next_debug == FALSE && macosx_deployment_target.major < 4)
error("segment address table: %s does not have an entry for %s",
info.seg_addr_table_name, NEXT_DEBUG_ADDRESS_TO_ASSIGN);
if(errors != 0)
exit(EXIT_FAILURE);
}
if(relayout == TRUE || update == TRUE || checkonly == TRUE ||
create == TRUE || update_overlaps == TRUE ||
relayout_nonsplit == TRUE){
layout_info = allocate(sizeof(struct layout_info) *
(info.table_size + 2));
memset(layout_info, '\0', sizeof(struct layout_info) *
(info.table_size + 2));
used = 0;
info.layout_info =
allocate(sizeof(struct layout_info *) *
(info.table_size + 2));
memset(info.layout_info, '\0', sizeof(struct layout_info *) *
(info.table_size + 2));
info.sorted_flat_layout_info =
allocate(sizeof(struct layout_info *) * (info.table_size + 2));
info.nsorted_flat = 0;
info.sorted_split_read_only_layout_info =
allocate(sizeof(struct layout_info *) * info.table_size);
info.sorted_split_read_write_layout_info =
allocate(sizeof(struct layout_info *) * info.table_size);
info.nsorted_split = 0;
layout_info[used].install_name = READ_ONLY_SEGMENT_NAME;
layout_info[used].image_file_name = READ_ONLY_SEGMENT_NAME;
layout_info[used].short_name = READ_ONLY_SEGMENT_NAME;
layout_info[used].split = FALSE;
layout_info[used].seg1addr = info.default_read_only_addr;
layout_info[used].max_sizes.all = 0x10000000;
info.sorted_flat_layout_info[info.nsorted_flat++] =
layout_info + used;
layout_info[used].current_entry =
allocate(sizeof(struct seg_addr_table));
layout_info[used].current_entry->install_name =
READ_ONLY_SEGMENT_NAME;
layout_info[used].current_entry->split = FALSE;
layout_info[used].current_entry->seg1addr =
info.default_read_only_addr;
used++;
layout_info[used].install_name = READ_WRITE_SEGMENT_NAME;
layout_info[used].image_file_name = READ_WRITE_SEGMENT_NAME;
layout_info[used].short_name = READ_WRITE_SEGMENT_NAME;
layout_info[used].split = FALSE;
layout_info[used].seg1addr = info.default_read_write_addr;
layout_info[used].max_sizes.all = 0x10000000;
info.sorted_flat_layout_info[info.nsorted_flat++] =
layout_info + used;
layout_info[used].current_entry =
allocate(sizeof(struct seg_addr_table));
layout_info[used].current_entry->install_name =
READ_WRITE_SEGMENT_NAME;
layout_info[used].current_entry->split = FALSE;
layout_info[used].current_entry->seg1addr =
info.default_read_write_addr;
used++;
for(i = 0 ; i < info.table_size; i++){
entry = info.seg_addr_table + i;
if(strcmp(entry->install_name,
NEXT_FLAT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name,
NEXT_DEBUG_ADDRESS_TO_ASSIGN) == 0)
continue;
if(strcmp(entry->install_name, FIXED_ADDRESS_AND_SIZE) == 0){
if(entry->split != TRUE)
error("entry in seg_addr_table: %s line: %u for fixed "
"address and size not to be allocated does not "
"have both address and size values",
info.seg_addr_table_name, entry->line);
else{
entry->split = FALSE;
entry->seg1addr = entry->segs_read_only_addr;
layout_info[used].install_name = entry->install_name;
layout_info[used].image_file_name = entry->install_name;
layout_info[used].short_name = entry->install_name;
layout_info[used].split = FALSE;
layout_info[used].seg1addr = entry->seg1addr;
layout_info[used].max_sizes.all =
entry->segs_read_write_addr;
layout_info[used].current_entry = entry;
info.layout_info[i] = layout_info + used;
info.sorted_flat_layout_info
[info.nsorted_flat++] = layout_info + used;
used++;
}
continue;
}
image_file_name = get_image_file_name(&info,
entry->install_name, FALSE,
update == TRUE || update_overlaps == TRUE);
if(image_file_name == NULL){
if(info.disablewarnings == FALSE &&
update == FALSE && update_overlaps == FALSE)
error("from seg_addr_table: %s line: %u can't find "
"file for install name: %s in -release %s",
info.seg_addr_table_name, entry->line,
entry->install_name, info.release_name);
continue;
}
if(stat(image_file_name, &stat_buf) == -1){
if(info.disablewarnings == FALSE &&
update == FALSE && update_overlaps == FALSE)
error("from seg_addr_table: %s line: %u can't open "
"file: %s", info.seg_addr_table_name, entry->line,
image_file_name);
continue;
}
if(entry->split == FALSE){
base_name = strrchr(entry->install_name, '/');
if(base_name == NULL || base_name[1] == '\0')
base_name = entry->install_name;
else
base_name = base_name + 1;
short_name = guess_short_name(entry->install_name,
&is_framework,
&has_suffix);
if(short_name == NULL)
short_name = base_name;
if((has_suffix != NULL) &&
(strcmp(has_suffix, "_debug") == 0 ||
strcmp(has_suffix, "_profile") == 0))
layout_info[used].use_debug_region = TRUE;
else
layout_info[used].use_debug_region = FALSE;
found = FALSE;
for(j = 0; j < used; j++){
if(layout_info[j].short_name != NULL &&
(layout_info[used].use_debug_region ==
layout_info[j].use_debug_region) &&
strncmp(layout_info[j].install_name,
entry->install_name,
base_name - entry->install_name) == 0 &&
strcmp(layout_info[j].short_name, short_name) == 0){
found = TRUE;
info.layout_info[i] = layout_info + j;
}
}
if(found == FALSE){
layout_info[used].install_name = entry->install_name;
layout_info[used].image_file_name = image_file_name;
layout_info[used].short_name = short_name;
info.layout_info[i] = layout_info + used;
if((update == TRUE || checkonly == TRUE ||
update_overlaps == TRUE) &&
relayout_nonsplit == FALSE &&
entry->seg1addr != 0)
info.sorted_flat_layout_info
[info.nsorted_flat++] = layout_info + used;
used++;
}
}
else{
layout_info[used].install_name = entry->install_name;
layout_info[used].image_file_name = image_file_name;
layout_info[used].short_name = NULL;
info.layout_info[i] = layout_info + used;
if((update == TRUE || checkonly == TRUE ||
update_overlaps == TRUE) &&
entry->segs_read_only_addr != 0){
info.sorted_split_read_only_layout_info
[info.nsorted_split] = layout_info + used;
info.sorted_split_read_write_layout_info
[info.nsorted_split] = layout_info + used;
info.nsorted_split++;
}
used++;
}
info.layout_info[i]->current_entry = entry;
ofile_process(image_file_name, info.arch_flags,
info.narch_flags, info.all_archs, FALSE,
TRUE, FALSE, sizes_and_addresses,
info.layout_info[i]);
}
qsort(info.sorted_flat_layout_info, info.nsorted_flat,
sizeof(struct layout_info *),
(int (*)(const void *, const void *))qsort_flat);
#ifdef DEBUG
for(i = 0 ; i < info.nsorted_flat; i++){
printf("0x%08x %s\n",
(unsigned int)info.sorted_flat_layout_info[i]->seg1addr,
info.sorted_flat_layout_info[i]->image_file_name);
}
#endif
qsort(info.sorted_split_read_only_layout_info, info.nsorted_split,
sizeof(struct layout_info *),
(int (*)(const void *, const void *))qsort_split_read_only);
qsort(info.sorted_split_read_write_layout_info, info.nsorted_split,
sizeof(struct layout_info *),
(int (*)(const void *, const void *))qsort_split_read_write);
for(i = 0 ;
i < info.nsorted_flat && relayout_nonsplit == FALSE;
i++){
for(j = i + 1; j < info.nsorted_flat; j++){
if(info.sorted_flat_layout_info[i]->current_entry->
seg1addr +
info.sorted_flat_layout_info[i]->max_sizes.all >
info.sorted_flat_layout_info[j]->current_entry->
seg1addr){
if(update_overlaps == TRUE)
info.sorted_flat_layout_info[i]->
current_entry->seg1addr = 0;
else
flat_overlap_error(&info, i, j, FALSE);
}
}
if(info.sorted_flat_layout_info[i]->use_debug_region == FALSE)
seg1addr = info.seg1addr;
else
seg1addr = info.debug_seg1addr;
if((info.allocate_flat_increasing == FALSE) &&
(update == TRUE || checkonly == TRUE ||
update_overlaps == TRUE) &&
strcmp(info.sorted_flat_layout_info[i]->install_name,
FIXED_ADDRESS_AND_SIZE) != 0 &&
info.sorted_flat_layout_info[i]->current_entry->seg1addr -
info.sorted_flat_layout_info[i]->max_sizes.all <
seg1addr &&
info.sorted_flat_layout_info[i]->seg1addr < seg1addr){
if(update_overlaps == TRUE)
info.sorted_flat_layout_info[i]->
current_entry->seg1addr = 0;
else
flat_overlap_error(&info, i, UINT_MAX, TRUE);
} else if((info.allocate_flat_increasing == TRUE) &&
(update == TRUE || checkonly == TRUE ||
update_overlaps == TRUE) &&
strcmp(info.sorted_flat_layout_info[i]->install_name,
FIXED_ADDRESS_AND_SIZE) != 0 &&
info.sorted_flat_layout_info[i]->current_entry->seg1addr +
info.sorted_flat_layout_info[i]->max_sizes.all >
info.seg1addr &&
info.sorted_flat_layout_info[i]->seg1addr < info.seg1addr){
if(update_overlaps == TRUE)
info.sorted_flat_layout_info[i]->
current_entry->seg1addr = 0;
else
flat_overlap_error(&info, i, UINT_MAX, TRUE);
}
}
for(i = 0 ; i < info.nsorted_split; i++){
for(j = i + 1 ; j < info.nsorted_split; j++){
if(info.sorted_split_read_only_layout_info[i]->
current_entry->segs_read_only_addr +
info.sorted_split_read_only_layout_info[i]->
max_sizes.read_only >
info.sorted_split_read_only_layout_info[j]->
current_entry->segs_read_only_addr){
if(update_overlaps == TRUE)
info.sorted_split_read_only_layout_info[i]->
current_entry->segs_read_only_addr = 0;
else
split_overlap_error(&info, i, j,
info.sorted_split_read_only_layout_info,
"read-only", FALSE);
}
}
if((update == TRUE || checkonly == TRUE ||
update_overlaps == TRUE) &&
info.sorted_split_read_only_layout_info[i]->
current_entry->segs_read_only_addr +
info.sorted_split_read_only_layout_info[i]->
max_sizes.read_only >
info.segs_read_only_addr){
if(update_overlaps == TRUE)
info.sorted_split_read_only_layout_info[i]->
current_entry->segs_read_only_addr = 0;
else
split_overlap_error(&info, i, UINT_MAX,
info.sorted_split_read_only_layout_info,
"read-only", TRUE);
}
}
for(i = 0 ; i < info.nsorted_split; i++){
for(j = i + 1 ; j < info.nsorted_split; j++){
if(info.sorted_split_read_write_layout_info[i]->
current_entry->segs_read_write_addr +
info.sorted_split_read_write_layout_info[i]->
max_sizes.read_write >
info.sorted_split_read_write_layout_info[j]->
current_entry->segs_read_write_addr){
if(update_overlaps == TRUE)
info.sorted_split_read_write_layout_info[i]->
current_entry->segs_read_write_addr = 0;
else
split_overlap_error(&info, i, j,
info.sorted_split_read_write_layout_info,
"read-write", FALSE);
}
}
if((update == TRUE || checkonly == TRUE ||
update_overlaps == TRUE) &&
info.sorted_split_read_write_layout_info[i]->
current_entry->segs_read_write_addr +
info.sorted_split_read_write_layout_info[i]->
max_sizes.read_write >
info.segs_read_write_addr){
if(update_overlaps == TRUE)
info.sorted_split_read_write_layout_info[i]->
current_entry->segs_read_write_addr = 0;
else
split_overlap_error(&info, i, UINT_MAX,
info.sorted_split_read_write_layout_info,
"read-write", TRUE);
}
}
}
if(create == TRUE){
out_fp = create_output_file(info.output_file_name);
fprintf(out_fp, "#%s -create", progname);
user = getenv("USER");
if(user != NULL)
fprintf(out_fp, " DEVELOPER:%s", user);
if(time(&tloc) != -1)
fprintf(out_fp, " BUILT:%s", ctime(&tloc));
else
fprintf(out_fp, "\n");
process_seg_addr_table(info.seg_addr_table_name, out_fp, progname,
new_table_processor, &info);
}
if(relayout == TRUE || relayout_nonsplit == TRUE){
for(i = 0 ; i < info.table_size; i++){
entry = info.seg_addr_table + i;
if(info.layout_info[i] == NULL)
continue;
if(entry->split == FALSE){
info.layout_info[i]->assigned = FALSE;
}
}
for(i = 0 ; i < info.table_size; i++){
entry = info.seg_addr_table + i;
if(info.layout_info[i] == NULL ||
strcmp(entry->install_name, FIXED_ADDRESS_AND_SIZE) == 0)
continue;
if(entry->split == FALSE){
if(info.layout_info[i]->assigned == FALSE){
size = rnd(info.layout_info[i]->max_sizes.all <<
info.factor, info.round);
if(info.layout_info[i]->use_debug_region == FALSE){
info.seg1addr = next_flat_seg1addr(&info, size);
info.layout_info[i]->seg1addr = info.seg1addr;
if(info.allocate_flat_increasing == TRUE){
info.seg1addr += size;
}
}
else{
info.debug_seg1addr =
next_debug_seg1addr(&info, size);
info.layout_info[i]->seg1addr = info.debug_seg1addr;
}
info.layout_info[i]->assigned = TRUE;
if(info.seg1addr > MAX_ADDR)
error("address assignment: 0x%x plus size 0x%x for "
"%s greater maximum address 0x%x",
(unsigned int)info.layout_info[i]->seg1addr,
(unsigned int)size,
entry->install_name, (unsigned int)MAX_ADDR);
}
}
else if (relayout_nonsplit == FALSE){
info.layout_info[i]->segs_read_only_addr =
info.segs_read_only_addr;
info.layout_info[i]->segs_read_write_addr =
info.segs_read_write_addr;
if(info.layout_info[i]->max_sizes.read_only >
info.layout_info[i]->max_sizes.read_write)
max = info.layout_info[i]->max_sizes.read_only;
else
max = info.layout_info[i]->max_sizes.read_write;
size = rnd(max + info.round, info.round);
info.segs_read_only_addr += size;
info.segs_read_write_addr += size;
if((info.layout_info[i]->segs_read_only_addr &
info.overflow_mask) !=
(info.start_segs_read_only_addr & info.overflow_mask))
error("read-only address assignment: 0x%x plus size "
"0x%x for %s overflows area to be allocated",
(unsigned int)
info.layout_info[i]->segs_read_only_addr,
(unsigned int)size,
entry->install_name);
if((info.layout_info[i]->segs_read_write_addr &
info.overflow_mask) !=
(info.start_segs_read_write_addr & info.overflow_mask))
error("read-write address assignment: 0x%x plus size "
"0x%x for %s overflows area to be allocated",
(unsigned int)
info.layout_info[i]->segs_read_write_addr,
(unsigned int)size,
entry->install_name);
}
}
if(update_overlaps == FALSE && relayout == FALSE){
next_split = FALSE;
for(i = 0 ; i < info.table_size; i++){
entry = info.seg_addr_table + i;
if(strcmp(entry->install_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN) == 0){
if(next_split == TRUE)
fatal("segment address table: %s has more than one "
"entry for %s", info.seg_addr_table_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN);
if(entry->split == FALSE)
fatal("segment address table: %s entry for %s is "
"a single address", info.seg_addr_table_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN);
next_split = TRUE;
info.segs_read_only_addr = entry->segs_read_only_addr;
info.segs_read_write_addr = entry->segs_read_write_addr;
info.next_split_line = entry->line;
}
}
}
if(update_overlaps == FALSE){
out_fp = create_output_file(info.output_file_name);
fprintf(out_fp, "#%s -relayout", progname);
user = getenv("USER");
if(user != NULL)
fprintf(out_fp, " DEVELOPER:%s", user);
if(time(&tloc) != -1)
fprintf(out_fp, " BUILT:%s", ctime(&tloc));
else
fprintf(out_fp, "\n");
process_seg_addr_table(info.seg_addr_table_name, out_fp,
progname, new_table_processor, &info);
fprintf(out_fp, "#%s: Do not remove the following line, "
"it is used by the %s tool\n", progname, progname);
fprintf(out_fp, "0x%08x\t0x%08x\t%s\n",
(unsigned int)info.segs_read_only_addr,
(unsigned int)info.segs_read_write_addr,
NEXT_SPLIT_ADDRESS_TO_ASSIGN);
if(macosx_deployment_target.major >= 4) {
if(info.segs_read_only_addr >
info.start_segs_read_only_addr + 0x10000000)
error("segs_read_only_addr over flow (more than 256meg's"
" of address space assigned, 0x%08x - 0x%08x)",
(unsigned int)info.start_segs_read_only_addr,
(unsigned int)info.segs_read_only_addr);
if (info.segs_read_write_addr >
info.start_segs_read_write_addr + 0x10000000)
error("segs_read_write_addr over flow (more than "
"256meg's of address space assigned, "
"0x%08x - 0x%08x)",
(unsigned int)info.start_segs_read_write_addr,
(unsigned int)info.segs_read_write_addr);
} else {
if(info.segs_read_only_addr >
info.start_segs_read_only_addr + 0x08000000)
error("segs_read_only_addr over flow (more than 128meg's"
" of address space assigned, 0x%08x - 0x%08x)",
(unsigned int)info.start_segs_read_only_addr,
(unsigned int)info.segs_read_only_addr);
if(info.segs_read_write_addr >
info.start_segs_read_write_addr + 0x08000000)
error("segs_read_write_addr over flow (more than"
"128meg's of address space assigned, "
" 0x%08x - 0x%08x)",
(unsigned int)info.start_segs_read_write_addr,
(unsigned int)info.segs_read_write_addr);
fprintf(out_fp, "#%s: Do not remove the following line, "
"it is used by the %s tool\n", progname, progname);
fprintf(out_fp, "0x%08x\t%s\n",
(unsigned int)info.seg1addr,
NEXT_FLAT_ADDRESS_TO_ASSIGN);
fprintf(out_fp, "#%s: Do not remove the following line, "
"it is used by the %s tool\n", progname, progname);
fprintf(out_fp, "0x%08x\t%s\n",
(unsigned int)info.debug_seg1addr,
NEXT_DEBUG_ADDRESS_TO_ASSIGN);
}
}
}
if(update == TRUE || update_overlaps == TRUE){
for(i = 0 ; i < info.table_size; i++){
entry = info.seg_addr_table + i;
if(strcmp(entry->install_name,
NEXT_FLAT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name,
NEXT_SPLIT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name,
NEXT_DEBUG_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name,
FIXED_ADDRESS_AND_SIZE) == 0)
continue;
if(info.layout_info[i] == NULL)
continue;
if(entry->split == FALSE && entry->seg1addr == 0 &&
relayout_nonsplit == FALSE){
if(info.layout_info[i]->assigned == FALSE){
size = rnd(info.layout_info[i]->max_sizes.all <<
info.factor, info.round);
if(info.layout_info[i]->use_debug_region == FALSE){
info.seg1addr = next_flat_seg1addr(&info, size);
info.layout_info[i]->seg1addr = info.seg1addr;
if(info.allocate_flat_increasing == TRUE){
info.seg1addr += size;
}
}
else{
info.debug_seg1addr =
next_debug_seg1addr(&info, size);
info.layout_info[i]->seg1addr = info.debug_seg1addr;
}
info.layout_info[i]->assigned = TRUE;
if(info.seg1addr > MAX_ADDR)
error("address assignment: 0x%x plus size 0x%x for "
"%s greater maximum address 0x%x",
(unsigned int)info.layout_info[i]->seg1addr,
(unsigned int)size,
entry->install_name, (unsigned int)MAX_ADDR);
}
}
if(entry->split == FALSE && entry->seg1addr != 0 &&
relayout_nonsplit == FALSE){
info.layout_info[i]->seg1addr = entry->seg1addr;
}
else if(entry->split == TRUE &&
(entry->segs_read_only_addr == 0 ||
entry->segs_read_write_addr == 0)){
info.layout_info[i]->segs_read_only_addr =
info.segs_read_only_addr;
info.layout_info[i]->segs_read_write_addr =
info.segs_read_write_addr;
if(info.layout_info[i]->max_sizes.read_only >
info.layout_info[i]->max_sizes.read_write)
max = info.layout_info[i]->max_sizes.read_only;
else
max = info.layout_info[i]->max_sizes.read_write;
size = rnd(max+info.round, info.round);
info.segs_read_only_addr += size;
info.segs_read_write_addr += size;
if((info.layout_info[i]->segs_read_only_addr &
info.overflow_mask) !=
(info.start_segs_read_only_addr & info.overflow_mask))
error("read-only address assignment: 0x%x plus size "
"0x%x for %s overflows area to be allocated",
(unsigned int)
info.layout_info[i]->segs_read_only_addr,
(unsigned int)size,
entry->install_name);
if((info.layout_info[i]->segs_read_write_addr &
info.overflow_mask) !=
(info.start_segs_read_write_addr & info.overflow_mask))
error("read-write address assignment: 0x%x plus size "
"0x%x for %s overflows area to be allocated",
(unsigned int)
info.layout_info[i]->segs_read_write_addr,
(unsigned int)size,
entry->install_name);
}
else if(entry->split == TRUE &&
entry->segs_read_only_addr != 0){
info.layout_info[i]->segs_read_only_addr =
entry->segs_read_only_addr;
info.layout_info[i]->segs_read_write_addr =
entry->segs_read_write_addr;
}
}
out_fp = create_output_file(info.output_file_name);
process_seg_addr_table(info.seg_addr_table_name, out_fp, progname,
new_table_processor, &info);
fprintf(out_fp, "#%s: Do not remove the following line, "
"it is used by the %s tool\n", progname, progname);
fprintf(out_fp, "0x%08x\t0x%08x\t%s\n",
(unsigned int)info.segs_read_only_addr,
(unsigned int)info.segs_read_write_addr,
NEXT_SPLIT_ADDRESS_TO_ASSIGN);
if(macosx_deployment_target.major < 4) {
fprintf(out_fp, "#%s: Do not remove the following line, "
"it is used by the %s tool\n", progname, progname);
fprintf(out_fp, "0x%08x\t%s\n",
(unsigned int)info.seg1addr,
NEXT_FLAT_ADDRESS_TO_ASSIGN);
fprintf(out_fp, "#%s: Do not remove the following line, "
"it is used by the %s tool\n", progname, progname);
fprintf(out_fp, "0x%08x\t%s\n",
(unsigned int)info.debug_seg1addr,
NEXT_DEBUG_ADDRESS_TO_ASSIGN);
}
}
if(out_fp != NULL){
if(fclose(out_fp) != 0)
system_fatal("can't close output file: %s\n",
info.output_file_name);
}
if(errors != 0)
return(EXIT_FAILURE);
else
return(EXIT_SUCCESS);
}
static
void
usage(
void)
{
fprintf(stderr, "Usage: %s [[[-relayout | -update "
"| [-update_overlaps [-relayout_nonsplit]] -o output_file] | "
"-checkonly ] [-seg_addr_table input_file] "
"[-disablewarnings] [-seg1addr hex_address] "
"[-allocate_flat increasing | decreasing]] "
"[-segs_read_only_addr hex_address] "
"[-segs_read_write_addr hex_address] "
"[-release <release_name> ] [[-arch <arch_flag>] ...]\n",
progname);
exit(EXIT_FAILURE);
}
static
FILE *
create_output_file(
char *output_file_name)
{
FILE *out_fp;
out_fp = fopen(output_file_name, "w");
if(out_fp == NULL)
system_fatal("can't create output file: %s\n", output_file_name);
return(out_fp);
}
static
int
qsort_flat(
const struct layout_info **p1,
const struct layout_info **p2)
{
if((*p1)->current_entry->seg1addr == (*p2)->current_entry->seg1addr)
return(0);
if((*p1)->current_entry->seg1addr < (*p2)->current_entry->seg1addr)
return(-1);
return(1);
}
static
int
qsort_split_read_only(
const struct layout_info **p1,
const struct layout_info **p2)
{
if((*p1)->current_entry->segs_read_only_addr ==
(*p2)->current_entry->segs_read_only_addr)
return(0);
if((*p1)->current_entry->segs_read_only_addr <
(*p2)->current_entry->segs_read_only_addr)
return(-1);
return(1);
}
static
int
qsort_split_read_write(
const struct layout_info **p1,
const struct layout_info **p2)
{
if((*p1)->current_entry->segs_read_write_addr ==
(*p2)->current_entry->segs_read_write_addr)
return(0);
if((*p1)->current_entry->segs_read_write_addr <
(*p2)->current_entry->segs_read_write_addr)
return(-1);
return(1);
}
static
void
flat_overlap_error(
struct info *info,
uint32_t i1,
uint32_t i2,
enum bool next_address)
{
struct layout_info *p1, *p2;
struct seg_addr_table *f1, *f2, fake;
fake.line = 0;
p1 = info->sorted_flat_layout_info[i1];
if(strcmp(p1->install_name, READ_ONLY_SEGMENT_NAME) == 0 ||
strcmp(p1->install_name, READ_WRITE_SEGMENT_NAME) == 0)
f1 = &fake;
else if(strcmp(p1->install_name, FIXED_ADDRESS_AND_SIZE) == 0)
f1 = search_seg_addr_table_for_fixed(info->seg_addr_table,
p1->seg1addr,
p1->max_sizes.all);
else
f1 = search_seg_addr_table(info->seg_addr_table, p1->install_name);
if(f1 == NULL)
fatal("internal error (can't find entry in info->seg_addr_table "
"for: %s\n", p1->install_name);
if(next_address == FALSE){
p2 = info->sorted_flat_layout_info[i2];
if(strcmp(p2->install_name, READ_ONLY_SEGMENT_NAME) == 0 ||
strcmp(p2->install_name, READ_WRITE_SEGMENT_NAME) == 0)
f2 = &fake;
else if(strcmp(p2->install_name, FIXED_ADDRESS_AND_SIZE) == 0)
f2 = search_seg_addr_table_for_fixed(info->seg_addr_table,
p2->seg1addr,
p2->max_sizes.all);
else
f2 = search_seg_addr_table(info->seg_addr_table,
p2->install_name);
if(f2 == NULL)
fatal("internal error (can't find entry in info->"
"seg_addr_table for: %s\n", p2->install_name);
if(info->disablewarnings == FALSE)
error("address space of: %s for seg_addr_table: %s entry on "
"line: %u overlaps with: %s for entry on line: %u",
p1->image_file_name, info->seg_addr_table_name, f1->line,
p2->image_file_name, f2->line);
}
else{
if(info->disablewarnings == FALSE)
error("address space of: %s for seg_addr_table: %s entry on "
"line: %u overlaps with: %s for entry on line: %u",
p1->image_file_name, info->seg_addr_table_name, f1->line,
NEXT_FLAT_ADDRESS_TO_ASSIGN, info->next_flat_line);
}
}
static
void
split_overlap_error(
struct info *info,
uint32_t i1,
uint32_t i2,
struct layout_info **sorted_layout_info,
char *segment,
enum bool next_address)
{
struct layout_info *p1, *p2;
struct seg_addr_table *f1, *f2;
p1 = sorted_layout_info[i1];
f1 = search_seg_addr_table(info->seg_addr_table, p1->install_name);
if(f1 == NULL)
fatal("internal error (can't find entry in info->seg_addr_table "
"for: %s\n", p1->install_name);
if(next_address == FALSE){
p2 = sorted_layout_info[i2];
f2 = search_seg_addr_table(info->seg_addr_table, p2->install_name);
if(f2 == NULL)
fatal("internal error (can't find entry in info->"
"seg_addr_table for: %s\n", p2->install_name);
if(info->disablewarnings == FALSE)
error("%s segments of: %s for seg_addr_table: %s entry on line:"
" %u overlaps with: %s for entry on line: %u", segment,
p1->image_file_name, info->seg_addr_table_name, f1->line,
p2->image_file_name, f2->line);
}
else{
if(info->disablewarnings == FALSE)
error("%s segments of: %s for seg_addr_table: %s entry on line:"
" %u overlaps with: %s for entry on line: %u", segment,
p1->image_file_name, info->seg_addr_table_name, f1->line,
NEXT_SPLIT_ADDRESS_TO_ASSIGN, info->next_split_line);
}
}
static
struct seg_addr_table *
search_seg_addr_table_for_fixed(
struct seg_addr_table *seg_addr_table,
uint32_t seg1addr,
uint32_t size)
{
struct seg_addr_table *p;
if(seg_addr_table == NULL)
return(NULL);
for(p = seg_addr_table; p->install_name != NULL; p++){
if(strcmp(p->install_name, FIXED_ADDRESS_AND_SIZE) == 0 &&
p->segs_read_only_addr == seg1addr &&
p->segs_read_write_addr == size)
return(p);
}
return(NULL);
}
static
uint32_t
next_flat_seg1addr(
struct info *info,
uint32_t size)
{
uint32_t seg1addr, start, end;
uint32_t i;
int32_t j;
if(info->allocate_flat_increasing == TRUE){
seg1addr = info->seg1addr;
for(i = 0 ; i < info->nsorted_flat; i++){
start = info->sorted_flat_layout_info[i]->seg1addr;
end = start + info->sorted_flat_layout_info[i]->max_sizes.all;
if((seg1addr <= start && seg1addr + size > start) ||
(seg1addr < end && seg1addr + size > end) ||
(seg1addr >= start && seg1addr + size <= end)){
#ifdef DEBUG
printf("next_flat_seg1addr() stepping over region start = 0x%x end = 0x%x\n",
(unsigned int)start, (unsigned int)end);
#endif
seg1addr = end;
}
}
}
else{
seg1addr = info->seg1addr - size;
for(j = info->nsorted_flat-1 ; j >= 0; j--){
start = info->sorted_flat_layout_info[j]->seg1addr;
end = start + info->sorted_flat_layout_info[j]->max_sizes.all;
if((seg1addr <= start && seg1addr + size > start) ||
(seg1addr < end && seg1addr + size > end) ||
(seg1addr >= start && seg1addr + size <= end)){
#ifdef DEBUG
printf("next_flat_seg1addr() stepping back over region start = 0x%x "
"end = 0x%x\n", (unsigned int)start, (unsigned int)end);
#endif
seg1addr = start;
}
}
}
#ifdef DEBUG
printf("next_flat_seg1addr() returning seg1addr = 0x%x\n",
(unsigned int)seg1addr);
#endif
return(seg1addr);
}
static
uint32_t
next_debug_seg1addr(
struct info *info,
uint32_t size)
{
uint32_t seg1addr, start, end;
int32_t j;
seg1addr = info->debug_seg1addr - size;
for(j = info->nsorted_flat-1 ; j >= 0; j--){
start = info->sorted_flat_layout_info[j]->seg1addr;
end = start + info->sorted_flat_layout_info[j]->max_sizes.all;
if((seg1addr <= start && seg1addr + size > start) ||
(seg1addr < end && seg1addr + size > end) ||
(seg1addr >= start && seg1addr + size <= end)){
#ifdef DEBUG
printf("next_debug_seg1addr() stepping back over region "
"start = 0x%x end = 0x%x\n",
(unsigned int)start, (unsigned int)end);
#endif
seg1addr = start;
}
}
#ifdef DEBUG
printf("next_debug_seg1addr() returning seg1addr = 0x%x\n",
(unsigned int)seg1addr);
#endif
return(seg1addr);
}
static
char *
get_image_file_name(
struct info *info,
char *install_name,
enum bool try_symroot,
enum bool no_error_if_missing)
{
char *image_file_name;
enum bool found_project;
image_file_name = NULL;
if(info->release_name != NULL){
if(try_symroot == TRUE)
image_file_name = get_symfile_for_dylib(
install_name,
info->release_name,
&found_project,
info->disablewarnings,
no_error_if_missing);
else
found_project = TRUE;
if(image_file_name == NULL && found_project == TRUE){
image_file_name = get_dstfile_for_dylib(
install_name,
info->release_name,
&found_project,
info->disablewarnings,
no_error_if_missing);
}
}
else{
image_file_name = install_name;
}
#ifdef DEBUG
printf("using %s for %s\n",
image_file_name == NULL ? "NULL" : image_file_name,
install_name);
#endif
return(image_file_name);
}
static
void
new_table_processor(
struct seg_addr_table *entry,
FILE *out_fp,
void *cookie)
{
struct info *info;
char *image_file_name;
struct stat stat_buf;
struct seg_addr_table *f;
if(strcmp(entry->install_name, NEXT_FLAT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name, NEXT_SPLIT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name, NEXT_DEBUG_ADDRESS_TO_ASSIGN) == 0)
return;
if(strcmp(entry->install_name, FIXED_ADDRESS_AND_SIZE) == 0){
fprintf(out_fp, "0x%08x\t0x%08x\t%s\n",
(unsigned int)entry->segs_read_only_addr,
(unsigned int)entry->segs_read_write_addr,
entry->install_name);
return;
}
info = (struct info *)cookie;
if(info->macosx_deployment_target.major >= 4 && entry->split != TRUE)
return;
image_file_name = get_image_file_name(info, entry->install_name,
FALSE,
TRUE);
if(image_file_name == NULL)
return;
if(stat(image_file_name, &stat_buf) != -1){
f = search_seg_addr_table(info->seg_addr_table,
entry->install_name);
if(f == NULL)
fatal("internal error (can't find entry in info->"
"seg_addr_table for: %s\n", entry->install_name);
if(entry->split == TRUE){
if(info->layout_info[f - info->seg_addr_table]->split != TRUE &&
info->macosx_deployment_target.major >= 4)
return;
fprintf(out_fp, "0x%08x\t0x%08x\t%s\n",
(unsigned int)info->layout_info[
f - info->seg_addr_table]->segs_read_only_addr,
(unsigned int)info->layout_info[
f - info->seg_addr_table]->segs_read_write_addr,
entry->install_name);
}
else{
fprintf(out_fp, "0x%08x\t%s\n",
(unsigned int)info->layout_info[
f - info->seg_addr_table]->seg1addr,
entry->install_name);
}
}
}
static
void
sizes_and_addresses(
struct ofile *ofile,
char *arch_name,
void *cookie)
{
uint32_t i, all, read_only, read_write,
segs_read_only_addr, segs_read_write_addr;
struct load_command *lc;
struct segment_command *sg, *first;
struct layout_info *layout_info;
enum bool split;
if(ofile->mh == NULL)
return;
#ifdef DEBUG
printf("In max_size() ofile->file_name = %s", ofile->file_name);
if(arch_name != NULL)
printf(" arch_name = %s\n", arch_name);
else
printf("\n");
#endif
layout_info = (struct layout_info *)cookie;
split = (ofile->mh->flags & MH_SPLIT_SEGS) == MH_SPLIT_SEGS;
layout_info->split = split;
lc = ofile->load_commands;
first = NULL;
all = 0;
read_only = 0;
read_write = 0;
segs_read_only_addr = UINT_MAX;
segs_read_write_addr = UINT_MAX;
for(i = 0; i < ofile->mh->ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(first == NULL){
first = sg;
if(split == FALSE && first->vmaddr != 0){
if(layout_info->seg1addr == 0 ||
layout_info->seg1addr == first->vmaddr){
layout_info->seg1addr = first->vmaddr;
}
}
}
if((sg->initprot & VM_PROT_WRITE) == 0){
read_only += sg->vmsize;
if(split == TRUE && sg->vmaddr < segs_read_only_addr)
segs_read_only_addr = sg->vmaddr;
}
else{
read_write += sg->vmsize;
if(split == TRUE && sg->vmaddr < segs_read_write_addr)
segs_read_write_addr = sg->vmaddr;
}
all += sg->vmsize;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(all > layout_info->max_sizes.all)
layout_info->max_sizes.all = all;
if(read_only > layout_info->max_sizes.read_only)
layout_info->max_sizes.read_only = read_only;
if(read_write > layout_info->max_sizes.read_write)
layout_info->max_sizes.read_write = read_write;
if(split == TRUE){
layout_info->segs_read_only_addr = segs_read_only_addr;
layout_info->segs_read_write_addr = segs_read_write_addr;
}
}
static
void
dylib_table_processor(
struct seg_addr_table *entry,
FILE *out_fp,
void *cookie)
{
struct info *info;
char *image_file_name, *short_name, *has_suffix;
struct stat stat_buf;
uint32_t seg1addr;
enum bool is_framework;
if(strcmp(entry->install_name, NEXT_FLAT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name, NEXT_SPLIT_ADDRESS_TO_ASSIGN) == 0 ||
strcmp(entry->install_name, NEXT_DEBUG_ADDRESS_TO_ASSIGN) == 0)
return;
info = (struct info *)cookie;
image_file_name = entry->install_name;
if(stat(image_file_name, &stat_buf) != -1){
seg1addr = 0;
ofile_process(image_file_name, info->arch_flags, info->narch_flags,
info->all_archs, FALSE, TRUE, FALSE,
get_seg1addr,&seg1addr);
short_name = guess_short_name(entry->install_name, &is_framework,
&has_suffix);
if(short_name == NULL){
short_name = strrchr(entry->install_name, '/');
if(short_name == NULL || short_name[1] == '\0')
short_name = entry->install_name;
}
fprintf(out_fp, "0x%08x\t%s\n", (unsigned int)seg1addr, short_name);
}
else{
error("from seg_addr_table: %s line: %u can't open file: "
"%s \n", info->seg_addr_table_name, entry->line,
image_file_name);
}
}
static
void
get_seg1addr(
struct ofile *ofile,
char *arch_name,
void *cookie)
{
uint32_t i;
struct load_command *lc;
struct segment_command *sg;
uint32_t *seg1addr, first_addr;
if(ofile->mh == NULL)
return;
#ifdef DEBUG
printf("In get_seg1addr() ofile->file_name = %s", ofile->file_name);
if(arch_name != NULL)
printf(" arch_name = %s\n", arch_name);
else
printf("\n");
#endif
first_addr = 0;
seg1addr = (uint32_t *)cookie;
lc = ofile->load_commands;
for(i = 0; i < ofile->mh->ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
first_addr = sg->vmaddr;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(*seg1addr != 0 && *seg1addr != first_addr)
error("seg1addr of: %s not the same in all architectures",
ofile->file_name);
*seg1addr = first_addr;
}