#ifdef SHLIB
#include "shlib.h"
#endif SHLIB
#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 "stuff/openstep_mach.h"
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#import <mach/m68k/thread_status.h>
#import <mach/ppc/thread_status.h>
#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 "ld.h"
#include "specs.h"
#include "fvmlibs.h"
#include "dylibs.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"
#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 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 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 print_load_map(void);
static void print_load_map_for_objects(struct merged_section *ms);
#endif !defined(RLD)
__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_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 RLD
define_common_symbols();
#ifndef RLD
process_section_specs();
#endif !defined(RLD)
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(filetype == MH_PRELOAD)
define_link_editor_preload_symbols(TRUE);
#endif !defined(RLD)
save_lazy_symbol_pointer_relocs = prebinding;
merge_literal_sections();
if(errors)
return;
#ifdef DEBUG
if(debug & (1 << 21))
print_merged_section_stats();
#endif DEBUG
#ifndef RLD
layout_ordered_sections();
#endif RLD
process_undefineds();
#ifndef RLD
prebinding_check_for_dylib_override_symbols();
#endif RLD
assign_output_symbol_indexes();
#ifndef RLD
if(filetype == MH_DYLIB)
layout_dylib_tables();
if(output_for_dyld)
layout_relocs_for_dyld();
if(segalign_specified == FALSE)
#endif
segalign = get_segalign_from_flag(&arch_flag);
layout_segments();
reset_prebound_undefines();
#ifndef RLD
if(load_map)
print_load_map();
#endif !defined(RLD)
#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 DEBUG
}
#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 =
round(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 !defined(RLD)
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));
#endif RLD
if(filetype == MH_OBJECT){
object_segment.filename = outputfile;
content = &(object_segment.content_sections);
zerofill = &(object_segment.zerofill_sections);
#ifdef RLD
original_merged_segments = merged_segments;
#endif RLD
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 &&
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;
}
seg_spec->processed = TRUE;
stack_segment.prot_set = TRUE;
}
else{
stack_segment.sg.maxprot =
(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
stack_segment.sg.initprot =
(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
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);
}
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
+ nlocal_symbols
- nmerged_symbols_referenced_only_from_dylibs) *
sizeof(struct nlist) +
round(merged_string_size +
local_string_size +
STRING_SIZE_OFFSET,
sizeof(unsigned long));
else
warning("segment created for -seglinkedit zero size "
"(output file stripped)");
linkedit_segment.sg.vmsize =
round(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 = round(pagezero_size,
segalign);
else
pagezero_segment.sg.vmsize = segalign;
pagezero_segment.next = merged_segments;
merged_segments = &pagezero_segment;
}
}
}
process_segment_specs();
#endif !defined(RLD)
#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;
}
if(seglinkedit){
msg = lookup_merged_segment(SEG_LINKEDIT);
if(msg != NULL && msg->prot_set == FALSE){
msg->sg.initprot = VM_PROT_READ;
msg->sg.maxprot =VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
msg->prot_set = TRUE;
}
}
#endif !defined(RLD)
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 = VM_PROT_READ | VM_PROT_WRITE |
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 + 0x10000000;
}
}
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(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++;
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++;
}
}
}
}
#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
+ nlocal_symbols
- nmerged_symbols_referenced_only_from_dylibs;
output_symtab_info.symtab_command.strsize =
round(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_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){
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{
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(lazy_init)
output_mach_header.flags |= MH_LAZY_INIT;
if(twolevel_namespace)
output_mach_header.flags |= MH_TWOLEVEL;
if(force_flat_namespace)
output_mach_header.flags |= MH_FORCE_FLAT;
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;
}
if(filetype == MH_EXECUTE ||
filetype == MH_BUNDLE ||
filetype == MH_DYLIB ||
filetype == MH_DYLINKER){
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 = round(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 = ((round(size + round(headers_size,
max_first_align), segalign) -
(size + round(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 = round(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 = round(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 = round(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 = round(addr, segalign);
}
p = &(msg->next);
}
#ifdef RLD
output_size = 0;
if(first_msg != NULL){
#ifndef SA_RLD
kern_return_t r;
#endif
unsigned long allocate_size;
headers_size = round(headers_size, max_align);
output_size = headers_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(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 RLD
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)
output_mach_header.flags |= MH_PREBOUND;
#endif RLD
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 = round(offset, sizeof(long));
#ifdef RLD
offset = output_size;
#endif RLD
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){
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 !defined(RLD)
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 !defined(RLD)
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);
}
#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 !defined(RLD)
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 == NULL ||
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 == NULL ||
merged_symbol->nlist.n_type == (N_EXT | N_UNDF))
fatal("initialization routine symbol name: %s not defined",
init_name);
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->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)
{
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;
}
warning("prebinding disabled because (%.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);
if(rc_trace_prebinding_disabled == TRUE)
print("[Logging for Build & Integration] 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
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("%-16s %-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("%-16s %-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++){
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));
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("\n");
print_load_map_for_objects(ms);
}
}
}
for(ms = msg->zerofill_sections; ms ; ms = ms->next){
print("%-16s %-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++){
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));
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("%-16s %-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("%-16s %-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->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) 0x%08x "
"0x%08x ",
(unsigned int)
(object_file->section_maps[j].s->addr +
fine_relocs[k].input_offset),
(unsigned int)(ms->s.addr +
fine_relocs[k].output_offset),
(unsigned int)
(k == object_file->section_maps[j].
nfine_relocs - 1 ?
object_file->section_maps[j].s->size -
fine_relocs[k].input_offset :
fine_relocs[k + 1].input_offset -
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 !defined(RLD)
#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 = %lu\n", output_mach_header.filetype);
print(" ncmds = %lu\n", output_mach_header.ncmds);
print(" sizeofcmds = %lu\n", output_mach_header.sizeofcmds);
print(" flags = %lu\n", output_mach_header.flags);
}
__private_extern__
void
print_symtab_info(void)
{
print("Symtab info for output file\n");
print(" cmd = %lu\n", output_symtab_info.symtab_command.cmd);
print(" cmdsize = %lu\n", output_symtab_info.symtab_command.cmdsize);
print(" nsyms = %lu\n", output_symtab_info.symtab_command.nsyms);
print(" symoff = %lu\n", output_symtab_info.symtab_command.symoff);
print(" strsize = %lu\n", output_symtab_info.symtab_command.strsize);
print(" stroff = %lu\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 DEBUG