#define __srr0 srr0
#define __r1 r1
#define __eip eip
#define __esp esp
#define __es es
#define __ds ds
#define __ss ss
#define __cs cs
#ifdef SHLIB
#include "shlib.h"
#endif
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <mach/mach.h>
#else
#include <mach/mach.h>
#endif
#include <stdarg.h>
#include <string.h>
#include <sys/param.h>
#include "stuff/openstep_mach.h"
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#import <mach/m68k/thread_status.h>
#undef MACHINE_THREAD_STATE
#undef MACHINE_THREAD_STATE_COUNT
#undef THREAD_STATE_NONE
#undef VALID_THREAD_STATE_FLAVOR
#import <mach/ppc/thread_status.h>
#undef MACHINE_THREAD_STATE
#undef MACHINE_THREAD_STATE_COUNT
#undef THREAD_STATE_NONE
#undef VALID_THREAD_STATE_FLAVOR
#import <mach/m88k/thread_status.h>
#import <mach/i860/thread_status.h>
#import <mach/i386/thread_status.h>
#import <mach/hppa/thread_status.h>
#import <mach/sparc/thread_status.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#if defined(RLD) && !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
#include <mach-o/rld.h>
#include <streams/streams.h>
#endif
#include "stuff/arch.h"
#include "stuff/macosx_deployment_target.h"
#include "ld.h"
#include "specs.h"
#include "fvmlibs.h"
#include "dylibs.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "pass1.h"
#include "symbols.h"
#include "layout.h"
#include "pass2.h"
#include "sets.h"
#include "mach-o/sarld.h"
#include "indirect_sections.h"
#include "uuid.h"
#ifdef RLD
__private_extern__ long RLD_DEBUG_OUTPUT_FILENAME_flag;
#endif
__private_extern__ struct mach_header output_mach_header = { 0 };
__private_extern__ struct symtab_info output_symtab_info = { {0} };
__private_extern__ struct dysymtab_info output_dysymtab_info = { {0} };
__private_extern__ struct hints_info output_hints_info = { { 0 } };
__private_extern__ struct cksum_info output_cksum_info = { { 0 } };
__private_extern__ struct uuid_info output_uuid_info = { 0 };
__private_extern__ struct thread_info output_thread_info = { {0} };
__private_extern__ struct routines_info output_routines_info = { {0} };
static struct m68k_thread_state_regs mc680x0 = { {0} };
static ppc_thread_state_t powerpc = { 0 };
static m88k_thread_state_grf_t mc88000 = { 0 };
static struct i860_thread_state_regs i860 = { {0} };
static i386_thread_state_t intel386 = { 0 };
static struct hp_pa_frame_thread_state hppa_frame_state = { 0 };
static struct hp_pa_integer_thread_state hppa_integer_state = { 0 };
static struct sparc_thread_state_regs sparc_state = { {0} };
static struct arm_thread_state arm_state = { 0 };
static void layout_segments(void);
static unsigned long next_vmaddr(
unsigned long vmaddr,
unsigned long vmsize);
static int qsort_vmaddr(
const struct merged_segment **msg1,
const struct merged_segment **msg2);
#ifndef RLD
static enum bool check_reserved_segment(char *segname,
char *reserved_error_string);
static void check_overlap(struct merged_segment *msg1,
struct merged_segment *msg2,
enum bool prebind_check,
struct merged_segment *outputs_linkedit_segment);
static void check_for_overlapping_segments(
struct merged_segment *outputs_linkedit_segment);
static void check_for_lazy_pointer_relocs_too_far(void);
static void print_load_map(void);
static void print_load_map_for_objects(struct merged_section *ms);
#endif
__private_extern__
void
layout(void)
{
#ifdef RLD
memset(&output_mach_header, '\0', sizeof(struct mach_header));
memset(&output_symtab_info, '\0', sizeof(struct symtab_info));
memset(&output_dysymtab_info, '\0', sizeof(struct dysymtab_info));
memset(&output_hints_info, '\0', sizeof(struct hints_info));
memset(&output_cksum_info, '\0', sizeof(struct cksum_info));
#ifndef KLD
memset(&output_uuid_info, '\0', sizeof(struct uuid_info));
#endif
memset(&output_thread_info, '\0', sizeof(struct thread_info));
memset(&mc680x0, '\0', sizeof(struct m68k_thread_state_regs));
memset(&powerpc, '\0', sizeof(ppc_thread_state_t));
memset(&mc88000, '\0', sizeof(m88k_thread_state_grf_t));
memset(&intel386,'\0', sizeof(i386_thread_state_t));
intel386.es = USER_DATA_SELECTOR;
intel386.ds = USER_DATA_SELECTOR;
intel386.ss = USER_DATA_SELECTOR;
intel386.cs = USER_CODE_SELECTOR;
memset(&hppa_frame_state, '\0',
sizeof(struct hp_pa_frame_thread_state));
memset(&hppa_integer_state, '\0',
sizeof(struct hp_pa_integer_thread_state));
memset(&sparc_state, '\0', sizeof(struct sparc_thread_state_regs));
#endif
define_common_symbols();
#ifndef RLD
process_section_specs();
#endif
reduce_indr_symbols();
if(errors)
return;
#ifndef RLD
if(filetype == MH_EXECUTE ||
filetype == MH_BUNDLE ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER){
setup_link_editor_symbols();
if(undefined_flag == UNDEFINED_DEFINE_A_WAY)
define_undefined_symbols_a_way();
}
if(filetype == MH_PRELOAD)
define_link_editor_preload_symbols(TRUE);
#endif
save_lazy_symbol_pointer_relocs = prebinding;
merge_literal_sections(FALSE);
if(errors)
return;
#ifdef DEBUG
if(debug & (1 << 21))
print_merged_section_stats();
#endif
remove_debug_segments();
#ifndef RLD
layout_ordered_sections();
if(dead_strip == TRUE){
live_marking();
if(errors)
return;
count_live_symbols();
resize_live_sections();
merge_literal_sections(TRUE);
}
#endif
process_undefineds();
if(errors)
return;
#ifndef RLD
prebinding_check_for_dylib_override_symbols();
if(nowarnings == FALSE &&
twolevel_namespace == TRUE &&
multiply_defined_unused_flag != MULTIPLY_DEFINED_SUPPRESS)
twolevel_namespace_check_for_unused_dylib_symbols();
#endif
assign_output_symbol_indexes();
#ifndef RLD
if(filetype == MH_DYLIB)
layout_dylib_tables();
if(output_for_dyld == TRUE || dead_strip == TRUE)
relayout_relocs();
if(segalign_specified == FALSE)
#endif
segalign = get_segalign_from_flag(&arch_flag);
layout_segments();
#ifndef RLD
reset_prebound_undefines();
if(load_map)
print_load_map();
#endif
#ifdef DEBUG
if(debug & (1 << 7)){
print_mach_header();
print_merged_sections("after layout");
print_symtab_info();
print_thread_info();
}
if(debug & (1 << 8))
print_symbol_list("after layout", FALSE);
if(debug & (1 << 20))
print_object_list();
#endif
}
#if defined(RLD) && !defined(SA_RLD) && !(defined(KLD) && defined(__STATIC__))
__private_extern__
void
layout_rld_symfile(void)
{
unsigned long offset;
kern_return_t r;
memset(&output_mach_header, '\0', sizeof(struct mach_header));
memset(&output_symtab_info, '\0', sizeof(struct symtab_info));
output_symtab_info.symtab_command.cmd = LC_SYMTAB;
output_symtab_info.symtab_command.cmdsize =
sizeof(struct symtab_command);
output_symtab_info.symtab_command.nsyms = nmerged_symbols;
output_symtab_info.symtab_command.strsize =
rnd(merged_string_size + STRING_SIZE_OFFSET,
sizeof(unsigned long));
output_symtab_info.output_strpad =
output_symtab_info.symtab_command.strsize -
(merged_string_size + STRING_SIZE_OFFSET);
output_symtab_info.output_merged_strsize = STRING_SIZE_OFFSET;
output_symtab_info.output_local_strsize = STRING_SIZE_OFFSET +
merged_string_size;
output_mach_header.magic = MH_MAGIC;
output_mach_header.cputype = arch_flag.cputype;
output_mach_header.cpusubtype = arch_flag.cpusubtype;
output_mach_header.filetype = filetype;
output_mach_header.ncmds = 1;
output_mach_header.sizeofcmds =
output_symtab_info.symtab_command.cmdsize;
output_mach_header.flags = 0;
offset = sizeof(struct mach_header) + output_mach_header.sizeofcmds;
output_symtab_info.symtab_command.symoff = offset;
offset += output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist);
output_symtab_info.symtab_command.stroff = offset;
offset += output_symtab_info.symtab_command.strsize;
output_size = offset;
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr,
output_size, TRUE)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_allocate() memory for output of size "
"%lu", output_size);
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_allocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)output_addr, (unsigned int)output_size);
#endif
}
#endif
static
void
layout_segments(void)
{
unsigned long i, ncmds, sizeofcmds, headers_size, offset;
unsigned long addr, size, max_first_align, pad, max_align;
struct merged_segment **p, *msg, *first_msg;
struct merged_section **content, **zerofill, *ms;
#ifndef RLD
struct merged_fvmlib **q, *mfl;
unsigned long nfvmlibs;
struct segment_spec *seg_spec;
enum bool address_zero_specified;
struct merged_dylib *mdl;
struct dynamic_library *dp;
#endif
#ifdef RLD
#ifndef SA_RLD
kern_return_t r;
#endif
unsigned long allocate_size;
#endif
struct merged_symbol *merged_symbol;
static struct merged_segment linkedit_segment = { {0} };
static struct merged_segment pagezero_segment = { {0} };
static struct merged_segment stack_segment = { {0} };
static struct merged_segment object_segment = { {0} };
#ifdef RLD
memset(&object_segment, '\0', sizeof(struct merged_segment));
original_merged_segments = merged_segments;
#endif
if(filetype == MH_OBJECT){
object_segment.filename = outputfile;
content = &(object_segment.content_sections);
zerofill = &(object_segment.zerofill_sections);
p = &merged_segments;
while(*p){
msg = *p;
object_segment.sg.nsects += msg->sg.nsects;
*content = msg->content_sections;
while(*content){
ms = *content;
content = &(ms->next);
}
*zerofill = msg->zerofill_sections;
while(*zerofill){
ms = *zerofill;
zerofill = &(ms->next);
}
p = &(msg->next);
}
if(object_segment.sg.nsects != 0)
merged_segments = &object_segment;
}
#ifndef RLD
if(filetype != MH_FVMLIB &&
filetype != MH_DYLIB &&
filetype != MH_BUNDLE &&
arch_flag.cputype != 0 &&
((merged_segments != NULL &&
merged_segments->content_sections != NULL) ||
entry_point_name != NULL)){
output_thread_info.thread_in_output = TRUE;
if(filetype == MH_DYLINKER)
output_thread_info.thread_command.cmd = LC_THREAD;
else
output_thread_info.thread_command.cmd = LC_UNIXTHREAD;
if((stack_addr_specified == TRUE || stack_size_specified == TRUE) &&
output_thread_info.thread_command.cmd == LC_UNIXTHREAD){
if(check_reserved_segment(SEG_UNIXSTACK, "segment "
SEG_UNIXSTACK " reserved for the -stack_addr and "
"-stack_size options")){
seg_spec = lookup_segment_spec(SEG_UNIXSTACK);
if(seg_spec != NULL){
if(seg_spec->addr_specified)
error("specified address for segment " SEG_UNIXSTACK
" not allowed (segment " SEG_UNIXSTACK
" reserved for unix stack, use -stack_addr)");
if(seg_spec->prot_specified){
if((seg_spec->maxprot &
(VM_PROT_READ | VM_PROT_WRITE)) !=
(VM_PROT_READ | VM_PROT_WRITE)){
error("specified maximum protection for "
"segment " SEG_UNIXSTACK " must include read "
" and write");
seg_spec->maxprot |= (VM_PROT_READ |
VM_PROT_WRITE);
}
if((seg_spec->initprot &
(VM_PROT_READ | VM_PROT_WRITE)) !=
(VM_PROT_READ | VM_PROT_WRITE)){
error("specified initial protection for "
"segment " SEG_UNIXSTACK " must include read "
" and write");
seg_spec->initprot |= (VM_PROT_READ |
VM_PROT_WRITE);
}
stack_segment.sg.maxprot = seg_spec->maxprot;
stack_segment.sg.initprot = seg_spec->initprot;
if((stack_segment.sg.maxprot & VM_PROT_EXECUTE) ==
VM_PROT_EXECUTE)
allow_stack_execute = TRUE;
}
seg_spec->processed = TRUE;
stack_segment.prot_set = TRUE;
}
else{
stack_segment.sg.maxprot =
get_segprot_from_flag(&arch_flag);
stack_segment.sg.initprot = stack_segment.sg.maxprot;
stack_segment.prot_set = TRUE;
}
if(stack_addr_specified == TRUE){
if(stack_addr % segalign != 0)
fatal("-stack_addr: 0x%x not a multiple of the "
"segment alignment (0x%x)",
(unsigned int)stack_addr,
(unsigned int)segalign);
}
else{
stack_addr = get_stack_addr_from_flag(&arch_flag);
warning("no -stack_addr specified using the default "
"addr: 0x%x", (unsigned int)stack_addr);
stack_addr_specified = TRUE;
}
if(stack_size_specified == TRUE){
if(stack_size % segalign != 0)
fatal("-stack_size: 0x%x not a multiple of the "
"segment alignment (0x%x)",
(unsigned int)stack_size,
(unsigned int)segalign);
}
else{
stack_size = get_stack_size_from_flag(&arch_flag);
warning("no -stack_size specified using the default "
"size: 0x%x", (unsigned int)stack_size);
}
stack_segment.filename = outputfile;
strcpy(stack_segment.sg.segname, SEG_UNIXSTACK);
if(get_stack_direction_from_flag(&arch_flag) < 0)
stack_segment.sg.vmaddr = stack_addr - stack_size;
else
stack_segment.sg.vmaddr = stack_addr;
stack_segment.sg.vmsize = stack_size;
stack_segment.addr_set = TRUE;
p = &merged_segments;
while(*p){
msg = *p;
p = &(msg->next);
}
*p = &stack_segment;
}
}
}
else{
output_thread_info.thread_in_output = FALSE;
}
if(filetype == MH_DYLIB && init_name != NULL){
output_routines_info.routines_in_output = TRUE;
output_routines_info.routines_command.cmd = LC_ROUTINES;
output_routines_info.routines_command.cmdsize =
sizeof(struct routines_command);
}
else{
output_routines_info.routines_in_output = FALSE;
}
if(filetype == MH_EXECUTE ||
filetype == MH_BUNDLE ||
filetype == MH_FVMLIB ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER){
if(check_reserved_segment(SEG_LINKEDIT, "segment " SEG_LINKEDIT
" reserved for the -seglinkedit option")){
if(seglinkedit == TRUE){
linkedit_segment.filename = outputfile;
strcpy(linkedit_segment.sg.segname, SEG_LINKEDIT);
if(save_reloc)
linkedit_segment.sg.filesize += nreloc *
sizeof(struct relocation_info);
if(output_for_dyld)
linkedit_segment.sg.filesize +=
(output_dysymtab_info.dysymtab_command.nlocrel +
output_dysymtab_info.dysymtab_command.nextrel) *
sizeof(struct relocation_info);
if(filetype == MH_DYLIB)
linkedit_segment.sg.filesize +=
output_dysymtab_info.dysymtab_command.ntoc *
sizeof(struct dylib_table_of_contents) +
output_dysymtab_info.dysymtab_command.nmodtab *
sizeof(struct dylib_module) +
output_dysymtab_info.dysymtab_command.nextrefsyms *
sizeof(struct dylib_reference);
if(nindirectsyms != 0)
linkedit_segment.sg.filesize +=
nindirectsyms * sizeof(unsigned long);
if(strip_level != STRIP_ALL)
linkedit_segment.sg.filesize +=
(nmerged_symbols
- nstripped_merged_symbols
+ nlocal_symbols
- nmerged_symbols_referenced_only_from_dylibs) *
sizeof(struct nlist) +
rnd(merged_string_size +
local_string_size +
STRING_SIZE_OFFSET,
sizeof(unsigned long));
else
warning("segment created for -seglinkedit zero size "
"(output file stripped)");
if(output_for_dyld &&
twolevel_namespace == TRUE &&
twolevel_namespace_hints == TRUE)
linkedit_segment.sg.filesize +=
output_hints_info.twolevel_hints_command.nhints *
sizeof(struct twolevel_hint);
linkedit_segment.sg.vmsize =
rnd(linkedit_segment.sg.filesize, segalign);
p = &merged_segments;
while(*p){
msg = *p;
p = &(msg->next);
}
*p = &linkedit_segment;
}
}
}
if(filetype == MH_EXECUTE){
if(check_reserved_segment(SEG_PAGEZERO, "segment " SEG_PAGEZERO
" reserved for address zero through "
"segment alignment")){
seg_spec = lookup_segment_spec(SEG_PAGEZERO);
if(seg_spec != NULL){
if(seg_spec->addr_specified)
error("specified address for segment " SEG_PAGEZERO
" not allowed (segment " SEG_PAGEZERO " reserved "
"for address zero through segment alignment)");
if(seg_spec->prot_specified)
error("specified protection for segment " SEG_PAGEZERO
" not allowed (segment " SEG_PAGEZERO " reserved "
"for address zero through segment alignment and "
"has no assess protections)");
seg_spec->processed = TRUE;
}
address_zero_specified = FALSE;
for(i = 0; i < nsegment_specs; i++){
if(segment_specs[i].addr_specified &&
segment_specs[i].addr == 0 &&
&(segment_specs[i]) != seg_spec){
address_zero_specified = TRUE;
break;
}
}
if(address_zero_specified == FALSE &&
(seg1addr_specified == FALSE || seg1addr != 0)){
pagezero_segment.filename = outputfile;
pagezero_segment.addr_set = TRUE;
pagezero_segment.prot_set = TRUE;
strcpy(pagezero_segment.sg.segname, SEG_PAGEZERO);
if(pagezero_size != 0)
pagezero_segment.sg.vmsize = rnd(pagezero_size,
segalign);
else
pagezero_segment.sg.vmsize = segalign;
pagezero_segment.next = merged_segments;
merged_segments = &pagezero_segment;
}
}
}
process_segment_specs();
#endif
#ifndef RLD
msg = lookup_merged_segment(SEG_TEXT);
if(msg != NULL && msg->prot_set == FALSE){
msg->sg.initprot = VM_PROT_READ | VM_PROT_EXECUTE;
msg->sg.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
msg->prot_set = TRUE;
}
msg = lookup_merged_segment(SEG_IMPORT);
if(msg != NULL && msg->prot_set == FALSE){
msg->sg.initprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
msg->sg.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
msg->prot_set = TRUE;
}
if(seglinkedit){
msg = lookup_merged_segment(SEG_LINKEDIT);
if(msg != NULL && msg->prot_set == FALSE){
msg->sg.initprot = VM_PROT_READ;
msg->sg.maxprot = get_segprot_from_flag(&arch_flag);
msg->prot_set = TRUE;
}
}
#endif
p = &merged_segments;
while(*p){
msg = *p;
if(msg->prot_set == FALSE){
msg->sg.initprot = VM_PROT_READ | VM_PROT_WRITE;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((ms->s.flags & S_ATTR_SOME_INSTRUCTIONS) ==
S_ATTR_SOME_INSTRUCTIONS){
msg->sg.initprot |= VM_PROT_EXECUTE;
break;
}
content = &(ms->next);
}
msg->sg.maxprot = get_segprot_from_flag(&arch_flag);
if((msg->sg.initprot & VM_PROT_EXECUTE) == VM_PROT_EXECUTE)
msg->sg.maxprot |= VM_PROT_EXECUTE;
msg->prot_set = TRUE;
}
p = &(msg->next);
}
if(segs_read_only_addr_specified){
if(segs_read_only_addr % segalign != 0)
fatal("-segs_read_only_addr: 0x%x not a multiple of the segment"
" alignment (0x%x)", (unsigned int)segs_read_only_addr,
(unsigned int)segalign);
if(segs_read_write_addr_specified){
if(segs_read_write_addr % segalign != 0)
fatal("-segs_read_write_addr: 0x%x not a multiple of the "
"segment alignment (0x%x)",
(unsigned int)segs_read_write_addr,
(unsigned int)segalign);
}
else{
segs_read_write_addr = segs_read_only_addr +
get_shared_region_size_from_flag(&arch_flag);
}
}
first_msg = merged_segments;
if(first_msg == &pagezero_segment)
first_msg = first_msg->next;
if(first_msg != NULL){
if(seg1addr_specified == TRUE){
if(seg1addr % segalign != 0)
fatal("-seg1addr: 0x%x not a multiple of the segment "
"alignment (0x%x)", (unsigned int)seg1addr,
(unsigned int)segalign);
if(first_msg->addr_set == TRUE)
fatal("address of first segment: %.16s set both by name "
"and with the -seg1addr option",
first_msg->sg.segname);
first_msg->sg.vmaddr = seg1addr;
first_msg->addr_set = TRUE;
}
else{
if(first_msg->addr_set == FALSE){
if(filetype == MH_EXECUTE &&
pagezero_segment.addr_set == TRUE)
first_msg->sg.vmaddr = pagezero_segment.sg.vmsize;
else{
if(segs_read_only_addr_specified){
if((first_msg->sg.initprot & VM_PROT_WRITE) == 0)
first_msg->sg.vmaddr = segs_read_only_addr;
else
first_msg->sg.vmaddr = segs_read_write_addr;
}
else{
first_msg->sg.vmaddr = 0;
}
}
first_msg->addr_set = TRUE;
}
}
}
ncmds = 0;
sizeofcmds = 0;
p = &merged_segments;
while(*p){
msg = *p;
msg->sg.cmd = LC_SEGMENT;
msg->sg.cmdsize = sizeof(struct segment_command) +
msg->sg.nsects * sizeof(struct section);
ncmds++;
sizeofcmds += msg->sg.cmdsize;
p = &(msg->next);
}
#ifndef RLD
nfvmlibs = 0;
q = &merged_fvmlibs;
while(*q){
mfl = *q;
nfvmlibs++;
sizeofcmds += mfl->fl->cmdsize;
q = &(mfl->next);
}
if(filetype == MH_FVMLIB && nfvmlibs != 1){
if(nfvmlibs == 0)
error("no LC_IDFVMLIB command in the linked object files");
else
error("more than one LC_IDFVMLIB command in the linked object "
"files");
}
ncmds += nfvmlibs;
if(filetype == MH_DYLIB){
create_dylib_id_command();
if(sub_framework == TRUE){
create_sub_framework_command();
sizeofcmds += merged_sub_framework->sub->cmdsize;
ncmds++;
}
if(nsub_umbrellas != 0){
sizeofcmds += create_sub_umbrella_commands();
ncmds += nsub_umbrellas;
}
if(nsub_librarys != 0){
sizeofcmds += create_sub_library_commands();
ncmds += nsub_librarys;
}
if(nallowable_clients != 0){
sizeofcmds += create_sub_client_commands();
ncmds += nallowable_clients;
}
}
if(filetype == MH_DYLINKER)
create_dylinker_id_command();
if(merged_dylinker != NULL){
sizeofcmds += merged_dylinker->dyld->cmdsize;
ncmds++;
}
mdl = merged_dylibs;
while(mdl != NULL){
sizeofcmds += mdl->dl->cmdsize;
ncmds++;
if(headerpad_max_install_names == TRUE){
if(mdl->dl->cmdsize - sizeof(struct dylib_command) < MAXPATHLEN)
headerpad += MAXPATHLEN -
(mdl->dl->cmdsize -
sizeof(struct dylib_command));
}
mdl = mdl->next;
}
if(filetype == MH_EXECUTE){
for(dp = dynamic_libs; dp != NULL; dp = dp->next){
if(dp->type == DYLIB){
if(dp->pbdylib != NULL){
sizeofcmds += dp->pbdylib->cmdsize;
ncmds++;
if(headerpad_max_install_names == TRUE){
if(dp->pbdylib->cmdsize -
sizeof(struct prebound_dylib_command) <
MAXPATHLEN)
headerpad += MAXPATHLEN -
(dp->pbdylib->cmdsize -
sizeof(struct prebound_dylib_command));
}
headerpad += dp->pbdylib->cmdsize * 3 * indirect_library_ratio;
}
}
}
}
#endif
output_symtab_info.symtab_command.cmd = LC_SYMTAB;
output_symtab_info.symtab_command.cmdsize =
sizeof(struct symtab_command);
if(strip_level != STRIP_ALL){
output_symtab_info.symtab_command.nsyms =
nmerged_symbols
- nstripped_merged_symbols
+ nlocal_symbols
- nmerged_symbols_referenced_only_from_dylibs;
output_symtab_info.symtab_command.strsize =
rnd(merged_string_size +
local_string_size +
STRING_SIZE_OFFSET,
sizeof(unsigned long));
output_symtab_info.output_strpad =
output_symtab_info.symtab_command.strsize -
(merged_string_size + local_string_size + STRING_SIZE_OFFSET);
output_symtab_info.output_merged_strsize = STRING_SIZE_OFFSET;
output_symtab_info.output_local_strsize = STRING_SIZE_OFFSET +
merged_string_size;
}
ncmds++;
sizeofcmds += output_symtab_info.symtab_command.cmdsize;
if(nindirectsyms != 0 || output_for_dyld){
output_dysymtab_info.dysymtab_command.cmd = LC_DYSYMTAB;
output_dysymtab_info.dysymtab_command.cmdsize =
sizeof(struct dysymtab_command);
output_dysymtab_info.dysymtab_command.nindirectsyms = nindirectsyms;
ncmds++;
sizeofcmds += output_dysymtab_info.dysymtab_command.cmdsize;
}
if(output_for_dyld && twolevel_namespace == TRUE &&
twolevel_namespace_hints == TRUE){
output_hints_info.twolevel_hints_command.cmd = LC_TWOLEVEL_HINTS;
output_hints_info.twolevel_hints_command.cmdsize =
sizeof(struct twolevel_hints_command);
ncmds++;
sizeofcmds += output_hints_info.twolevel_hints_command.cmdsize;
}
if(prebinding == TRUE && macosx_deployment_target.major >= 2){
output_cksum_info.prebind_cksum_command.cmd = LC_PREBIND_CKSUM;
output_cksum_info.prebind_cksum_command.cmdsize =
sizeof(struct prebind_cksum_command);
output_cksum_info.prebind_cksum_command.cksum = 0;
ncmds++;
sizeofcmds += output_cksum_info.prebind_cksum_command.cmdsize;
}
#ifndef KLD
if(output_uuid_info.suppress != TRUE &&
(output_uuid_info.emit == TRUE ||
arch_flag.cputype == CPU_TYPE_ARM)){
output_uuid_info.uuid_command.cmd = LC_UUID;
output_uuid_info.uuid_command.cmdsize = sizeof(struct uuid_command);
uuid(&(output_uuid_info.uuid_command.uuid[0]));
ncmds++;
sizeofcmds += output_uuid_info.uuid_command.cmdsize;
}
#else
if(output_uuid_info.uuid_command.cmdsize != 0){
ncmds++;
sizeofcmds += output_uuid_info.uuid_command.cmdsize;
}
#endif
if(output_thread_info.thread_in_output == TRUE){
output_thread_info.thread_command.cmdsize =
sizeof(struct thread_command) +
2 * sizeof(long);
if(arch_flag.cputype == CPU_TYPE_MC680x0){
output_thread_info.flavor = M68K_THREAD_STATE_REGS;
output_thread_info.count = M68K_THREAD_STATE_REGS_COUNT;
output_thread_info.entry_point = &(mc680x0.pc);
output_thread_info.stack_pointer = &(mc680x0.areg[7]);
output_thread_info.state = &mc680x0;
output_thread_info.thread_command.cmdsize += sizeof(long) *
M68K_THREAD_STATE_REGS_COUNT;
}
else if(arch_flag.cputype == CPU_TYPE_POWERPC ||
arch_flag.cputype == CPU_TYPE_VEO){
output_thread_info.flavor = PPC_THREAD_STATE;
output_thread_info.count = PPC_THREAD_STATE_COUNT;
output_thread_info.entry_point = (int *)&(powerpc.srr0);
output_thread_info.stack_pointer = (int *)&(powerpc.r1);
output_thread_info.state = &powerpc;
output_thread_info.thread_command.cmdsize += sizeof(long) *
PPC_THREAD_STATE_COUNT;
}
else if(arch_flag.cputype == CPU_TYPE_MC88000){
output_thread_info.flavor = M88K_THREAD_STATE_GRF;
output_thread_info.count = M88K_THREAD_STATE_GRF_COUNT;
output_thread_info.entry_point = (int *)&(mc88000.xip);
output_thread_info.stack_pointer = (int *)&(mc88000.r31);
output_thread_info.state = &mc88000;
output_thread_info.thread_command.cmdsize += sizeof(long) *
M88K_THREAD_STATE_GRF_COUNT;
}
else if(arch_flag.cputype == CPU_TYPE_I860){
output_thread_info.flavor = I860_THREAD_STATE_REGS;
output_thread_info.count = I860_THREAD_STATE_REGS_COUNT;
output_thread_info.entry_point = &(i860.pc);
output_thread_info.stack_pointer = &(i860.ireg[0]);
output_thread_info.state = &i860;
output_thread_info.thread_command.cmdsize += sizeof(long) *
I860_THREAD_STATE_REGS_COUNT;
}
else if(arch_flag.cputype == CPU_TYPE_I386){
output_thread_info.flavor = i386_THREAD_STATE;
output_thread_info.count = i386_THREAD_STATE_COUNT;
output_thread_info.entry_point = (int *)&(intel386.eip);
output_thread_info.stack_pointer = (int *)&(intel386.esp);
intel386.es = USER_DATA_SELECTOR;
intel386.ds = USER_DATA_SELECTOR;
intel386.ss = USER_DATA_SELECTOR;
intel386.cs = USER_CODE_SELECTOR;
output_thread_info.state = &intel386;
output_thread_info.thread_command.cmdsize += sizeof(long) *
i386_THREAD_STATE_COUNT;
}
else if(arch_flag.cputype == CPU_TYPE_HPPA){
output_thread_info.flavor = HPPA_FRAME_THREAD_STATE;
output_thread_info.count = HPPA_FRAME_THREAD_STATE_COUNT;
output_thread_info.entry_point =
(int *)&(hppa_frame_state.ts_pcoq_front);
output_thread_info.state = &hppa_frame_state;
output_thread_info.thread_command.cmdsize += sizeof(long) *
HPPA_FRAME_THREAD_STATE_COUNT;
if(stack_addr_specified == TRUE){
output_thread_info.second_flavor =
HPPA_INTEGER_THREAD_STATE;
output_thread_info.second_count =
HPPA_INTEGER_THREAD_STATE_COUNT;
output_thread_info.stack_pointer =
(int *)&(hppa_integer_state.ts_gr30);
output_thread_info.second_state = &hppa_integer_state;
output_thread_info.thread_command.cmdsize +=
sizeof(long) * HPPA_INTEGER_THREAD_STATE_COUNT +
2 * sizeof(long);
}
}
else if (arch_flag.cputype == CPU_TYPE_SPARC) {
output_thread_info.flavor = SPARC_THREAD_STATE_REGS;
output_thread_info.count = SPARC_THREAD_STATE_REGS_COUNT;
output_thread_info.entry_point = &(sparc_state.regs.r_pc);
output_thread_info.stack_pointer = &(sparc_state.regs.r_sp);
output_thread_info.state = &sparc_state;
output_thread_info.thread_command.cmdsize += sizeof(long) *
SPARC_THREAD_STATE_REGS_COUNT;
}
else if (arch_flag.cputype == CPU_TYPE_ARM) {
output_thread_info.flavor = ARM_THREAD_STATE;
output_thread_info.count = ARM_THREAD_STATE_COUNT;
output_thread_info.entry_point = (int *)&(arm_state.r15);
output_thread_info.stack_pointer = (int *)&(arm_state.r13);
output_thread_info.state = &arm_state;
output_thread_info.thread_command.cmdsize += sizeof(long) *
ARM_THREAD_STATE_COUNT;
}
else{
fatal("internal error: layout_segments() called with unknown "
"cputype (%d) set", arch_flag.cputype);
}
sizeofcmds += output_thread_info.thread_command.cmdsize;
ncmds++;
}
if(output_routines_info.routines_in_output == TRUE){
sizeofcmds += output_routines_info.routines_command.cmdsize;
ncmds++;
}
output_mach_header.magic = MH_MAGIC;
output_mach_header.cputype = arch_flag.cputype;
output_mach_header.cpusubtype = arch_flag.cpusubtype;
output_mach_header.filetype = filetype;
output_mach_header.ncmds = ncmds;
output_mach_header.sizeofcmds = sizeofcmds;
output_mach_header.flags = 0;
if(base_obj != NULL)
output_mach_header.flags |= MH_INCRLINK;
if(output_for_dyld){
output_mach_header.flags |= MH_DYLDLINK;
if(bind_at_load)
output_mach_header.flags |= MH_BINDATLOAD;
if(segs_read_only_addr_specified)
output_mach_header.flags |= MH_SPLIT_SEGS;
if(twolevel_namespace)
output_mach_header.flags |= MH_TWOLEVEL;
if(force_flat_namespace)
output_mach_header.flags |= MH_FORCE_FLAT;
if(nomultidefs)
output_mach_header.flags |= MH_NOMULTIDEFS;
if(no_fix_prebinding)
output_mach_header.flags |= MH_NOFIXPREBINDING;
}
if(some_non_subsection_via_symbols_objects == FALSE)
output_mach_header.flags |= MH_SUBSECTIONS_VIA_SYMBOLS;
if(allow_stack_execute == TRUE)
output_mach_header.flags |= MH_ALLOW_STACK_EXECUTION;
headers_size = sizeof(struct mach_header) + sizeofcmds;
if(filetype == MH_FVMLIB){
if(headers_size > segalign)
fatal("size of headers (0x%x) exceeds the segment alignment "
"(0x%x) (would cause the addresses not to be fixed)",
(unsigned int)headers_size, (unsigned int)segalign);
headers_size = segalign;
}
else if(filetype == MH_DYLINKER){
headers_size = rnd(headers_size, segalign);
}
if(filetype == MH_EXECUTE ||
filetype == MH_BUNDLE ||
filetype == MH_DYLIB){
if(first_msg != NULL){
size = 0;
content = &(first_msg->content_sections);
if(*content){
max_first_align = 1 << (*content)->s.align;
while(*content){
ms = *content;
if((unsigned long)(1 << ms->s.align) > segalign)
error("alignment (0x%x) of section (%.16s,%.16s) "
"greater than the segment alignment (0x%x)",
(unsigned int)(1 << ms->s.align),
ms->s.segname, ms->s.sectname,
(unsigned int)segalign);
size = rnd(size, 1 << ms->s.align);
if((unsigned long)(1 << ms->s.align) > max_first_align)
max_first_align = 1 << ms->s.align;
size += ms->s.size;
content = &(ms->next);
}
if(errors == 0){
pad = ((rnd(size + rnd(headers_size,
max_first_align), segalign) -
(size + rnd(headers_size, max_first_align))) /
max_first_align) * max_first_align;
if(pad > headerpad)
headerpad = pad;
headers_size += headerpad;
}
}
}
}
max_align = 1;
p = &merged_segments;
while(*p){
msg = *p;
if(msg != &pagezero_segment &&
msg != &linkedit_segment &&
msg != &stack_segment){
if(msg == first_msg &&
(filetype == MH_EXECUTE ||
filetype == MH_BUNDLE ||
filetype == MH_FVMLIB ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER))
addr = headers_size;
else
addr = 0;
content = &(msg->content_sections);
while(*content){
ms = *content;
if((unsigned long)(1 << ms->s.align) > segalign)
error("alignment (0x%x) of section (%.16s,%.16s) "
"greater than the segment alignment (0x%x)",
(unsigned int)(1 << ms->s.align), ms->s.segname,
ms->s.sectname, (unsigned int)segalign);
if((unsigned long)(1 << ms->s.align) > max_align)
max_align = 1 << ms->s.align;
addr = rnd(addr, 1 << ms->s.align);
ms->s.addr = addr;
addr += ms->s.size;
content = &(ms->next);
}
if(msg == &object_segment)
msg->sg.filesize = addr;
else
msg->sg.filesize = rnd(addr, segalign);
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
if((unsigned long)(1 << ms->s.align) > segalign)
error("alignment (0x%x) of section (%.16s,%.16s) "
"greater than the segment alignment (0x%x)",
(unsigned int)(1 << ms->s.align), ms->s.segname,
ms->s.sectname, (unsigned int)segalign);
if((unsigned long)(1 << ms->s.align) > max_align)
max_align = 1 << ms->s.align;
addr = rnd(addr, 1 << ms->s.align);
ms->s.addr = addr;
addr += ms->s.size;
zerofill = &(ms->next);
}
if(msg == &object_segment)
msg->sg.vmsize = addr;
else
msg->sg.vmsize = rnd(addr, segalign);
}
p = &(msg->next);
}
#ifdef RLD
output_size = 0;
headers_size = rnd(headers_size, max_align);
output_size = headers_size;
if(first_msg != NULL)
output_size += first_msg->sg.vmsize;
allocate_size = output_size;
if(strip_level != STRIP_ALL)
allocate_size += output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist) +
output_symtab_info.symtab_command.strsize;
#ifdef SA_RLD
if(allocate_size > sa_rld_output_size)
fatal("not enough memory for output of size %lu (memory "
"available %lu)", allocate_size, sa_rld_output_size);
output_addr = sa_rld_output_addr;
#else
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr,
allocate_size, TRUE)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_allocate() memory for output of size "
"%lu", allocate_size);
if((r = vm_protect(mach_task_self(), (vm_address_t)output_addr,
allocate_size, FALSE, VM_PROT_ALL)) != KERN_SUCCESS)
mach_fatal(r, "can't set vm_protection on memory for output");
#endif
#ifdef RLD_VM_ALLOC_DEBUG
print("rld() vm_allocate: addr = 0x%0x size = 0x%x\n",
(unsigned int)output_addr, (unsigned int)allocate_size);
#endif
sets[cur_set].output_addr = output_addr;
sets[cur_set].output_size = output_size;
if(first_msg != NULL){
if(address_func != NULL){
if(RLD_DEBUG_OUTPUT_FILENAME_flag)
first_msg->sg.vmaddr =
(*address_func)(allocate_size, headers_size)+headers_size;
else
first_msg->sg.vmaddr =
(*address_func)(output_size, headers_size) + headers_size;
}
else
first_msg->sg.vmaddr = (long)output_addr + headers_size;
}
#endif
p = &merged_segments;
while(*p){
msg = *p;
if(msg->addr_set == FALSE){
if(segs_read_only_addr_specified){
if((msg->sg.initprot & VM_PROT_WRITE) == 0)
msg->sg.vmaddr = next_vmaddr(segs_read_only_addr,
msg->sg.vmsize);
else
msg->sg.vmaddr = next_vmaddr(segs_read_write_addr,
msg->sg.vmsize);
}
else{
msg->sg.vmaddr = next_vmaddr(first_msg->sg.vmaddr,
msg->sg.vmsize);
}
msg->addr_set = TRUE;
}
if(msg != &pagezero_segment &&
msg != &linkedit_segment &&
msg != &stack_segment){
content = &(msg->content_sections);
while(*content){
ms = *content;
ms->s.addr += msg->sg.vmaddr;
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
ms->s.addr += msg->sg.vmaddr;
zerofill = &(ms->next);
}
}
p = &(msg->next);
}
#ifndef RLD
check_for_overlapping_segments(&linkedit_segment);
if(prebinding)
check_for_lazy_pointer_relocs_too_far();
if(prebinding)
output_mach_header.flags |= MH_PREBOUND;
#endif
offset = headers_size;
p = &merged_segments;
while(*p){
msg = *p;
if(msg != &pagezero_segment &&
msg != &linkedit_segment &&
msg != &stack_segment){
if(msg == first_msg &&
(filetype == MH_EXECUTE ||
filetype == MH_BUNDLE ||
filetype == MH_FVMLIB ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER)){
msg->sg.fileoff = 0;
content = &(msg->content_sections);
if(*content){
ms = *content;
offset = ms->s.addr - msg->sg.vmaddr;
}
}
else
msg->sg.fileoff = offset;
content = &(msg->content_sections);
while(*content){
ms = *content;
ms->s.offset = offset;
if(ms->next != NULL)
offset += (ms->next->s.addr - ms->s.addr);
content = &(ms->next);
}
if(msg->sg.filesize == 0)
msg->sg.fileoff = 0;
if(msg == first_msg &&
(filetype == MH_EXECUTE ||
filetype == MH_BUNDLE ||
filetype == MH_FVMLIB ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER))
offset = msg->sg.filesize;
else
if(msg->sg.filesize != 0)
offset = msg->sg.fileoff + msg->sg.filesize;
}
p = &(msg->next);
}
offset = rnd(offset, sizeof(long));
#ifdef RLD
offset = output_size;
#endif
linkedit_segment.sg.fileoff = offset;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(save_reloc && ms->s.nreloc != 0){
ms->s.reloff = offset;
offset += ms->s.nreloc * sizeof(struct relocation_info);
}
else{
ms->s.reloff = 0;
ms->s.nreloc = 0;
}
content = &(ms->next);
}
p = &(msg->next);
}
if(output_for_dyld){
if(output_dysymtab_info.dysymtab_command.nlocrel != 0){
output_dysymtab_info.dysymtab_command.locreloff = offset;
offset += output_dysymtab_info.dysymtab_command.nlocrel *
sizeof(struct relocation_info);
}
}
if(output_for_dyld){
if(strip_level != STRIP_ALL){
output_symtab_info.symtab_command.symoff = offset;
offset += output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist);
}
}
if(output_for_dyld && twolevel_namespace == TRUE &&
twolevel_namespace_hints == TRUE){
output_hints_info.twolevel_hints_command.offset = offset;
offset += output_hints_info.twolevel_hints_command.nhints *
sizeof(struct twolevel_hint);
}
if(output_for_dyld){
if(output_dysymtab_info.dysymtab_command.nextrel != 0){
output_dysymtab_info.dysymtab_command.extreloff = offset;
offset += output_dysymtab_info.dysymtab_command.nextrel *
sizeof(struct relocation_info);
}
}
if(nindirectsyms != 0){
output_dysymtab_info.dysymtab_command.indirectsymoff = offset;
offset += nindirectsyms * sizeof(unsigned long);
}
#ifndef RLD
if(filetype == MH_DYLIB){
output_dysymtab_info.dysymtab_command.tocoff = offset;
offset += output_dysymtab_info.dysymtab_command.ntoc *
sizeof(struct dylib_table_of_contents);
output_dysymtab_info.dysymtab_command.modtaboff = offset;
offset += output_dysymtab_info.dysymtab_command.nmodtab *
sizeof(struct dylib_module);
output_dysymtab_info.dysymtab_command.extrefsymoff = offset;
offset += output_dysymtab_info.dysymtab_command.nextrefsyms *
sizeof(struct dylib_reference);
}
#endif
if(output_for_dyld == FALSE){
if(strip_level != STRIP_ALL){
output_symtab_info.symtab_command.symoff = offset;
offset += output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist);
}
}
if(strip_level != STRIP_ALL){
output_symtab_info.symtab_command.stroff = offset;
offset += output_symtab_info.symtab_command.strsize;
}
#ifndef RLD
output_size = offset;
#endif
i = 1;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
ms->output_sectnum = i++;
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
ms->output_sectnum = i++;
zerofill = &(ms->next);
}
p = &(msg->next);
}
if(i > MAX_SECT)
fatal("too many sections used, maximum is: %d", MAX_SECT);
#ifndef RLD
if(filetype == MH_EXECUTE &&
first_msg != NULL && first_msg != &linkedit_segment)
define_link_editor_execute_symbols(first_msg->sg.vmaddr);
if((filetype == MH_BUNDLE ||
filetype == MH_DYLIB || filetype == MH_DYLINKER) &&
first_msg != NULL && first_msg != &linkedit_segment)
define_link_editor_dylib_symbols(first_msg->sg.vmaddr);
if(filetype == MH_PRELOAD)
define_link_editor_preload_symbols(FALSE);
#endif
layout_merged_symbols();
if(output_thread_info.thread_in_output == TRUE){
if(entry_point_name != NULL){
merged_symbol = lookup_symbol(entry_point_name);
if(merged_symbol->name_len == 0 ||
merged_symbol->nlist.n_type == (N_EXT | N_UNDF))
fatal("entry point symbol name: %s not defined",
entry_point_name);
*output_thread_info.entry_point = merged_symbol->nlist.n_value;
}
else{
*output_thread_info.entry_point =
first_msg->content_sections->s.addr;
}
if(arch_flag.cputype == CPU_TYPE_HPPA)
hppa_frame_state.ts_pcoq_back =
hppa_frame_state.ts_pcoq_front + 4;
if(stack_addr_specified == TRUE &&
output_thread_info.thread_command.cmd == LC_UNIXTHREAD)
*output_thread_info.stack_pointer = stack_addr;
}
else{
if(entry_point_name != NULL)
warning("specified entry point symbol name ignored, output "
"file type has no entry point or no non-zerofill "
"sections");
}
if(output_routines_info.routines_in_output == TRUE){
if(init_name != NULL){
merged_symbol = lookup_symbol(init_name);
if(merged_symbol->name_len == 0 ||
merged_symbol->nlist.n_type == (N_EXT | N_UNDF))
fatal("initialization routine symbol name: %s not defined",
init_name);
if(arch_flag.cputype == CPU_TYPE_ARM &&
(merged_symbol->nlist.n_desc & N_ARM_THUMB_DEF))
output_routines_info.routines_command.init_address =
merged_symbol->nlist.n_value | 1;
else
output_routines_info.routines_command.init_address =
merged_symbol->nlist.n_value;
output_routines_info.routines_command.init_module =
merged_symbol->definition_object->imodtab;
}
}
else{
if(init_name != NULL)
warning("specified initialization routine symbol name ignored, "
"output file type has no initialization routine");
}
}
static
unsigned long
next_vmaddr(
unsigned long vmaddr,
unsigned long vmsize)
{
unsigned long i, n;
struct merged_segment *msg, **sorted_merged_segments;
n = 0;
for(msg = merged_segments; msg != NULL ; msg = msg->next){
if(msg->addr_set == TRUE && msg->sg.vmsize != 0)
n++;
}
if(n == 0)
return(vmaddr);
sorted_merged_segments = (struct merged_segment **)
allocate(n * sizeof(struct merged_segment *));
i = 0;
for(msg = merged_segments; msg != NULL ; msg = msg->next){
if(msg->addr_set == TRUE && msg->sg.vmsize != 0){
sorted_merged_segments[i] = msg;
i++;
}
}
qsort(sorted_merged_segments, n, sizeof(struct merged_segment *),
(int (*)(const void *, const void *))qsort_vmaddr);
for(i = 0; i < n; i++){
if(vmaddr < sorted_merged_segments[i]->sg.vmaddr){
if(vmaddr + vmsize <= sorted_merged_segments[i]->sg.vmaddr)
goto done;
vmaddr = sorted_merged_segments[i]->sg.vmaddr +
sorted_merged_segments[i]->sg.vmsize;
}
if(vmaddr < sorted_merged_segments[i]->sg.vmaddr +
sorted_merged_segments[i]->sg.vmsize){
vmaddr = sorted_merged_segments[i]->sg.vmaddr +
sorted_merged_segments[i]->sg.vmsize;
}
}
done:
free(sorted_merged_segments);
return(vmaddr);
}
static
int
qsort_vmaddr(
const struct merged_segment **msg1,
const struct merged_segment **msg2)
{
if((*msg1)->sg.vmaddr < (*msg2)->sg.vmaddr)
return(-1);
if((*msg1)->sg.vmaddr == (*msg2)->sg.vmaddr)
return(0);
return(1);
}
#ifndef RLD
static
enum bool
check_reserved_segment(
char *segname,
char *reserved_error_string)
{
struct merged_segment *msg;
struct merged_section **content, *ms;
unsigned long i, j;
struct object_list *object_list, **q;
struct object_file *object_file;
struct section *s;
msg = lookup_merged_segment(segname);
if(msg != NULL){
error("segment %s exist in the output file (%s)", segname,
reserved_error_string);
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->contents_filename != NULL)
print("section (%.16s,%.16s) created from file "
"%s\n", ms->s.segname, ms->s.sectname,
ms->contents_filename);
content = &(ms->next);
}
for(q = &objects; *q; q = &(object_list->next)){
object_list = *q;
for(i = 0; i < object_list->used; i++){
object_file = &(object_list->object_files[i]);
if(object_file == base_obj)
continue;
if(object_file->dylib)
continue;
if(object_file->bundle_loader)
continue;
if(object_file->dylinker)
continue;
for(j = 0; j < object_file->nsection_maps; j++){
s = object_file->section_maps[j].s;
if(strcmp(s->segname, segname) == 0){
print_obj_name(object_file);
print("contains section (%.16s,%.16s)\n",
s->segname, s->sectname);
}
}
}
}
return(FALSE);
}
return(TRUE);
}
static
void
check_for_overlapping_segments(
struct merged_segment *outputs_linkedit_segment)
{
struct merged_segment **p1, **p2, **last_merged, **last_fvmseg, **last_base,
*msg1, *msg2;
last_merged = &merged_segments;
while(*last_merged){
msg1 = *last_merged;
last_merged = &(msg1->next);
}
if(fvmlib_segments != NULL){
*last_merged = fvmlib_segments;
last_fvmseg = &fvmlib_segments;
while(*last_fvmseg){
msg1 = *last_fvmseg;
last_fvmseg = &(msg1->next);
}
}
else
last_fvmseg = last_merged;
*last_fvmseg = base_obj_segments;
p1 = &merged_segments;
while(*p1){
msg1 = *p1;
p2 = &(msg1->next);
while(*p2){
msg2 = *p2;
check_overlap(msg1, msg2, FALSE, outputs_linkedit_segment);
p2 = &(msg2->next);
}
p1 = &(msg1->next);
}
if(prebinding && dylib_segments != NULL){
last_base = last_fvmseg;
while(*last_base){
msg1 = *last_base;
last_base = &(msg1->next);
}
*last_base = dylib_segments;
p1 = &merged_segments;
while(*p1){
msg1 = *p1;
p2 = &(msg1->next);
while(*p2){
msg2 = *p2;
check_overlap(msg1, msg2, TRUE, outputs_linkedit_segment);
p2 = &(msg2->next);
}
p1 = &(msg1->next);
}
*last_base = NULL;
}
*last_merged = NULL;
*last_fvmseg = NULL;
}
static
void
check_overlap(
struct merged_segment *msg1,
struct merged_segment *msg2,
enum bool prebind_check,
struct merged_segment *outputs_linkedit_segment)
{
char *not;
if(msg1->sg.vmsize == 0 || msg2->sg.vmsize == 0)
return;
if(msg1->sg.vmaddr > msg2->sg.vmaddr){
if(msg2->sg.vmaddr + msg2->sg.vmsize <= msg1->sg.vmaddr)
return;
}
else{
if(msg1->sg.vmaddr + msg1->sg.vmsize <= msg2->sg.vmaddr)
return;
}
if(prebind_check == FALSE)
error("%.16s segment (address = 0x%x size = 0x%x) of %s overlaps "
"with %.16s segment (address = 0x%x size = 0x%x) of %s",
msg1->sg.segname, (unsigned int)(msg1->sg.vmaddr),
(unsigned int)(msg1->sg.vmsize), msg1->filename,
msg2->sg.segname, (unsigned int)(msg2->sg.vmaddr),
(unsigned int)(msg2->sg.vmsize), msg2->filename);
else{
if((segs_read_only_addr_specified &&
((msg1 == outputs_linkedit_segment &&
msg2->split_dylib == TRUE)||
(msg2 == outputs_linkedit_segment &&
msg1->split_dylib == TRUE))) ||
(msg1->split_dylib == TRUE &&
strcmp(msg1->sg.segname, SEG_LINKEDIT) == 0) ||
(msg2->split_dylib == TRUE &&
strcmp(msg2->sg.segname, SEG_LINKEDIT) == 0)){
warning("prebinding not disabled even though (%.16s segment "
"(address = 0x%x size = 0x%x) of %s overlaps with "
"%.16s segment (address = 0x%x size = 0x%x) of %s on "
"the assumption that the stripped output will not "
"overlap",
msg1->sg.segname, (unsigned int)(msg1->sg.vmaddr),
(unsigned int)(msg1->sg.vmsize), msg1->filename,
msg2->sg.segname, (unsigned int)(msg2->sg.vmaddr),
(unsigned int)(msg2->sg.vmsize), msg2->filename);
return;
}
if(prebind_allow_overlap == TRUE)
not = " not";
else
not = "";
warning("prebinding%s disabled because (%.16s segment (address = "
"0x%x size = 0x%x) of %s overlaps with %.16s segment "
"(address = 0x%x size = 0x%x) of %s", not,
msg1->sg.segname, (unsigned int)(msg1->sg.vmaddr),
(unsigned int)(msg1->sg.vmsize), msg1->filename,
msg2->sg.segname, (unsigned int)(msg2->sg.vmaddr),
(unsigned int)(msg2->sg.vmsize), msg2->filename);
if(prebind_allow_overlap == TRUE)
return;
if(ld_trace_prebinding_disabled == TRUE)
ld_trace("[Logging for XBS] prebinding disabled "
"for %s because (%.16s segment (address = 0x%x size = "
"0x%x) of %s overlaps with %.16s segment (address = 0x%x "
"size = 0x%x) of %s\n", final_output != NULL ?
final_output : outputfile,
msg1->sg.segname, (unsigned int)(msg1->sg.vmaddr),
(unsigned int)(msg1->sg.vmsize), msg1->filename,
msg2->sg.segname, (unsigned int)(msg2->sg.vmaddr),
(unsigned int)(msg2->sg.vmsize), msg2->filename);
}
prebinding = FALSE;
}
static
void
check_for_lazy_pointer_relocs_too_far(
void)
{
struct merged_segment **p, *msg;
struct merged_section **content, *ms;
unsigned long base_addr;
if(segs_read_only_addr_specified == TRUE)
base_addr = segs_read_write_addr;
else
base_addr = merged_segments->sg.vmaddr;
p = &merged_segments;
while(*p && prebinding){
msg = *p;
content = &(msg->content_sections);
while(*content && prebinding){
ms = *content;
if((ms->s.flags & SECTION_TYPE) ==
S_LAZY_SYMBOL_POINTERS){
if(((ms->s.addr + ms->s.size) - base_addr) & 0xff000000){
warning("prebinding disabled because output is too "
"large (limitation of the 24-bit r_address "
"field of scattered relocation entries)");
prebinding = FALSE;
}
}
content = &(ms->next);
}
p = &(msg->next);
}
}
static
void
print_load_map(void)
{
unsigned long i;
struct merged_segment *msg;
struct merged_section *ms;
struct common_symbol *common_symbol;
print("Load map for: %s\n", outputfile);
print("Segment name Section name Address Size\n");
for(msg = merged_segments; msg ; msg = msg->next){
print("%-16.16s %-16.16s 0x%08x 0x%08x\n",
msg->sg.segname, "", (unsigned int)(msg->sg.vmaddr),
(unsigned int)(msg->sg.vmsize));
for(ms = msg->content_sections; ms ; ms = ms->next){
print("%-16.16s %-16.16s 0x%08x 0x%08x",
ms->s.segname, ms->s.sectname,
(unsigned int)(ms->s.addr), (unsigned int)(ms->s.size));
if(ms->contents_filename)
print(" from the file: %s\n", ms->contents_filename);
else{
if(ms->order_load_maps){
print("\n");
for(i = 0; i < ms->norder_load_maps; i++){
if(dead_strip == FALSE ||
ms->order_load_maps[i].load_order->
fine_reloc->live == TRUE){
print("\t\t\t\t 0x%08x 0x%08x ",
(unsigned int)(fine_reloc_output_offset(
ms->order_load_maps[i].section_map,
ms->order_load_maps[i].value -
ms->order_load_maps[i].section_map->
s->addr) +
ms->order_load_maps[i].section_map->
output_section->s.addr),
(unsigned int)
(ms->order_load_maps[i].size));
}
else{
print("\t\t\t\t (dead stripped) ");
}
if(ms->order_load_maps[i].archive_name != NULL)
print("%s:",
ms->order_load_maps[i].archive_name);
if(ms->order_load_maps[i].symbol_name != NULL)
print("%s:%s\n",
ms->order_load_maps[i].object_name,
ms->order_load_maps[i].symbol_name);
else
print("%s\n",
ms->order_load_maps[i].object_name);
}
}
else{
print("\n");
print_load_map_for_objects(ms);
}
}
}
for(ms = msg->zerofill_sections; ms ; ms = ms->next){
print("%-16.16s %-16.16s 0x%08x 0x%08x\n",
ms->s.segname, ms->s.sectname,
(unsigned int)(ms->s.addr), (unsigned int)(ms->s.size));
if(ms->order_load_maps){
for(i = 0; i < ms->norder_load_maps; i++){
if(dead_strip == FALSE ||
ms->order_load_maps[i].load_order->
fine_reloc->live == TRUE){
print("\t\t\t\t 0x%08x 0x%08x ",
(unsigned int)(fine_reloc_output_offset(
ms->order_load_maps[i].section_map,
ms->order_load_maps[i].value -
ms->order_load_maps[i].section_map->
s->addr) +
ms->order_load_maps[i].section_map->
output_section->s.addr),
(unsigned int)
(ms->order_load_maps[i].size));
}
else{
print("\t\t\t\t (dead stripped) ");
}
if(ms->order_load_maps[i].archive_name != NULL)
print("%s:", ms->order_load_maps[i].archive_name);
print("%s:%s\n",
ms->order_load_maps[i].object_name,
ms->order_load_maps[i].symbol_name);
}
}
else{
print_load_map_for_objects(ms);
if(common_load_map.common_ms == ms){
common_symbol = common_load_map.common_symbols;
for(i = 0; i < common_load_map.ncommon_symbols; i++){
print("\t\t\t\t 0x%08x 0x%08x symbol: %s\n",
(unsigned int)
(common_symbol->merged_symbol->nlist.n_value),
(unsigned int)(common_symbol->common_size),
common_symbol->merged_symbol->nlist.n_un.n_name);
common_symbol++;
}
common_load_map.common_ms = NULL;
common_load_map.ncommon_symbols = 0;
free(common_load_map.common_symbols);
}
}
}
if(msg->next != NULL)
print("\n");
}
if(base_obj){
print("\nLoad map for base file: %s\n", base_obj->file_name);
print("Segment name Section name Address Size\n");
for(msg = base_obj_segments; msg ; msg = msg->next){
print("%-16.16s %-16.16s 0x%08x 0x%08x\n",
msg->sg.segname, "", (unsigned int)(msg->sg.vmaddr),
(unsigned int)(msg->sg.vmsize));
}
}
if(fvmlib_segments != NULL){
print("\nLoad map for fixed VM shared libraries\n");
print("Segment name Section name Address Size\n");
for(msg = fvmlib_segments; msg ; msg = msg->next){
print("%-16.16s %-16.16s 0x%08x 0x%08x %s\n",
msg->sg.segname, "", (unsigned int)(msg->sg.vmaddr),
(unsigned int)(msg->sg.vmsize), msg->filename);
}
}
}
static
void
print_load_map_for_objects(
struct merged_section *ms)
{
unsigned long i, j, k;
struct object_list *object_list, **p;
struct object_file *object_file;
struct fine_reloc *fine_relocs;
for(p = &objects; *p; p = &(object_list->next)){
object_list = *p;
for(i = 0; i < object_list->used; i++){
object_file = &(object_list->object_files[i]);
if(object_file == base_obj)
continue;
if(object_file->dylib)
continue;
if(object_file->bundle_loader)
continue;
if(object_file->dylinker)
continue;
for(j = 0; j < object_file->nsection_maps; j++){
if(object_file->section_maps[j].output_section == ms &&
object_file->section_maps[j].s->size != 0){
if(object_file->section_maps[j].nfine_relocs != 0){
fine_relocs =
object_file->section_maps[j].fine_relocs;
for(k = 0;
k < object_file->section_maps[j].nfine_relocs;
k++){
print(" (input address 0x%08x) ",
(unsigned int)
(object_file->section_maps[j].s->addr +
fine_relocs[k].input_offset));
if((object_file->section_maps[j].s->flags &
SECTION_TYPE) == S_SYMBOL_STUBS ||
(object_file->section_maps[j].s->flags &
SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
(object_file->section_maps[j].s->flags &
SECTION_TYPE) ==
S_NON_LAZY_SYMBOL_POINTERS ||
(object_file->section_maps[j].s->flags &
SECTION_TYPE) == S_COALESCED){
if(fine_relocs[k].use_contents == FALSE)
print("(eliminated) ");
else if(dead_strip == TRUE &&
fine_relocs[k].live == FALSE)
print("(dead stripped) ");
else
print(" 0x%08x ",
(unsigned int)(ms->s.addr +
fine_relocs[k].output_offset));
}
else if(dead_strip == TRUE &&
fine_relocs[k].live == FALSE)
print("(dead stripped) ");
else
print(" 0x%08x ",
(unsigned int)(ms->s.addr +
fine_relocs[k].output_offset));
print("0x%08x ",
(unsigned int)
(k == (unsigned int)
((object_file->section_maps[j].
nfine_relocs) -
(unsigned int)1) ?
(unsigned int)
(object_file->section_maps[j].s->size) -
(unsigned int)(fine_relocs[k].
input_offset) :
(unsigned int)(fine_relocs[k + 1].
input_offset) -
(unsigned int)(fine_relocs[k].
input_offset)));
print_obj_name(object_file);
print("\n");
}
}
else{
print("\t\t\t\t 0x%08x 0x%08x ",
(unsigned int)(ms->s.addr +
object_file->section_maps[j].offset),
(unsigned int)
(object_file->section_maps[j].s->size));
print_obj_name(object_file);
print("\n");
}
}
}
}
}
}
#endif
#ifdef DEBUG
__private_extern__
void
print_mach_header(void)
{
print("Mach header for output file\n");
print(" magic = 0x%x\n", (unsigned int)(output_mach_header.magic));
print(" cputype = %d\n", output_mach_header.cputype);
print(" cpusubtype = %d\n", output_mach_header.cpusubtype);
print(" filetype = %u\n", output_mach_header.filetype);
print(" ncmds = %u\n", output_mach_header.ncmds);
print(" sizeofcmds = %u\n", output_mach_header.sizeofcmds);
print(" flags = %u\n", output_mach_header.flags);
}
__private_extern__
void
print_symtab_info(void)
{
print("Symtab info for output file\n");
print(" cmd = %u\n", output_symtab_info.symtab_command.cmd);
print(" cmdsize = %u\n", output_symtab_info.symtab_command.cmdsize);
print(" nsyms = %u\n", output_symtab_info.symtab_command.nsyms);
print(" symoff = %u\n", output_symtab_info.symtab_command.symoff);
print(" strsize = %u\n", output_symtab_info.symtab_command.strsize);
print(" stroff = %u\n", output_symtab_info.symtab_command.stroff);
}
__private_extern__
void
print_thread_info(void)
{
print("Thread info for output file\n");
print(" flavor = %lu\n", output_thread_info.flavor);
print(" count = %lu\n", output_thread_info.count);
print(" entry_point = 0x%x",
(unsigned int)(output_thread_info.entry_point));
if(output_thread_info.entry_point != NULL)
print(" (0x%x)\n", (unsigned int)(*output_thread_info.entry_point));
else
print("\n");
}
#endif