#ifdef SHLIB
#include "shlib.h"
#endif
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <libc.h>
#include <stdio.h>
#include <mach/mach.h>
#else
#include <mach/kern_return.h>
#endif
#include <stdarg.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "stuff/openstep_mach.h"
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "stuff/macosx_deployment_target.h"
#include "stuff/unix_standard_mode.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "fvmlibs.h"
#include "dylibs.h"
#include "sections.h"
#include "pass1.h"
#include "symbols.h"
#include "layout.h"
#include "pass2.h"
#include "sets.h"
#include "indirect_sections.h"
__private_extern__ unsigned long output_size = 0;
__private_extern__ char *output_addr = NULL;
__private_extern__ struct merged_section **output_sections = NULL;
#ifndef RLD
static int fd = 0;
static struct block {
unsigned long offset;
unsigned long size;
unsigned long written_offset;
unsigned long written_size;
struct block *next;
} *output_blocks;
static void setup_output_flush(void);
static void final_output_flush(void);
#ifdef DEBUG
static void print_block_list(void);
#endif
static struct block *get_block(void);
static void remove_block(struct block *block);
static unsigned long trnc(unsigned long v, unsigned long r);
#endif
static void create_output_sections_array(void);
static void set_SG_NORELOC_flags(void);
static void output_headers(void);
__private_extern__
void
pass2(void)
{
unsigned long i, j, section_type;
struct object_list *object_list, **p;
#ifndef RLD
int mode;
struct stat stat_buf;
kern_return_t r;
if(get_unix_standard_mode() == TRUE &&
access(outputfile, F_OK) == 0 &&
access(outputfile, W_OK) == -1)
system_fatal("can't write output file: %s", outputfile);
(void)unlink(outputfile);
if((fd = open(outputfile, O_WRONLY | O_CREAT | O_TRUNC, 0777)) == -1)
system_fatal("can't create output file: %s", outputfile);
#ifdef F_NOCACHE
(void)fcntl(fd, F_NOCACHE, 1);
#endif
if(fstat(fd, &stat_buf) == -1)
system_fatal("can't stat file: %s", outputfile);
if(output_mach_header.flags & MH_NOUNDEFS ||
(has_dynamic_linker_command && output_for_dyld))
mode = (stat_buf.st_mode & 0777) | (0111 & ~umask(0));
else
mode = (stat_buf.st_mode & 0777) & ~0111;
if(fchmod(fd, mode) == -1)
system_fatal("can't set execution permissions output file: %s",
outputfile);
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr,
output_size, TRUE)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_allocate() buffer for output file of size "
"%lu", output_size);
if(flush)
setup_output_flush();
nop_pure_instruction_scattered_sections();
#endif
set_merged_string_block_indexes();
#ifndef RLD
if(filetype == MH_DYLIB)
output_dylib_tables();
#endif
create_output_sections_array();
output_literal_sections();
#ifndef RLD
output_sections_from_files();
#endif
for(p = &objects; *p; p = &(object_list->next)){
object_list = *p;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
if(trace){
print_obj_name(cur_obj);
print("\n");
}
if(cur_obj->dylib)
continue;
if(cur_obj->bundle_loader)
continue;
if(cur_obj->dylinker)
continue;
if(cur_obj != base_obj){
for(j = 0; j < cur_obj->nsection_maps; j++){
if(cur_obj->section_maps[j].s->flags & S_ATTR_DEBUG)
continue;
#ifdef RLD
if(cur_obj->set_num == cur_set)
#endif
{
section_type = (cur_obj->section_maps[j].s->flags &
SECTION_TYPE);
if(section_type == S_REGULAR ||
section_type == S_SYMBOL_STUBS ||
section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_COALESCED ||
section_type == S_MOD_INIT_FUNC_POINTERS ||
section_type == S_MOD_TERM_FUNC_POINTERS){
output_section(&(cur_obj->section_maps[j]));
}
}
}
}
output_local_symbols();
#ifdef VM_SYNC_DEACTIVATE
vm_msync(mach_task_self(), (vm_address_t)cur_obj->obj_addr,
(vm_size_t)cur_obj->obj_size, VM_SYNC_DEACTIVATE);
#endif
}
}
if(errors != 0)
return;
#ifdef RLD
for(p = &objects; *p; p = &(object_list->next)){
object_list = *p;
for(i = 0; i < object_list->used; i++){
cur_obj = &(object_list->object_files[i]);
for(j = 0; j < cur_obj->nsection_maps; j++){
if(cur_obj->section_maps[j].nfine_relocs != 0){
free(cur_obj->section_maps[j].fine_relocs);
cur_obj->section_maps[j].fine_relocs = NULL;
cur_obj->section_maps[j].nfine_relocs = 0;
}
}
if(cur_obj->nundefineds != 0){
free(cur_obj->undefined_maps);
cur_obj->undefined_maps = NULL;
cur_obj->nundefineds = 0;
}
}
}
#endif
set_SG_NORELOC_flags();
#ifndef SA_RLD
output_indirect_symbols();
#endif
output_merged_symbols();
output_headers();
#ifndef RLD
if(flush){
flush_scatter_copied_sections();
final_output_flush();
}
else{
if(write(fd, output_addr, output_size) != (int)output_size)
system_fatal("can't write output file");
if((r = vm_deallocate(mach_task_self(), (vm_address_t)output_addr,
output_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() buffer for output file");
}
#ifdef F_NOCACHE
(void)fcntl(fd, F_NOCACHE, 0);
#endif
if(close(fd) == -1)
system_fatal("can't close output file");
#endif
}
#if defined(RLD) && !defined(SA_RLD)
__private_extern__
void
pass2_rld_symfile(void)
{
output_rld_symfile_merged_symbols();
memcpy(output_addr, &output_mach_header, sizeof(struct mach_header));
memcpy(output_addr + sizeof(struct mach_header),
&(output_symtab_info.symtab_command),
output_symtab_info.symtab_command.cmdsize);
}
#endif
__private_extern__
void
create_output_sections_array(void)
{
unsigned long i, nsects;
struct merged_segment **p, *msg;
struct merged_section **content, **zerofill, *ms;
nsects = 1;
p = &merged_segments;
while(*p){
msg = *p;
nsects += msg->sg.nsects;
p = &(msg->next);
}
output_sections = (struct merged_section **)
allocate(nsects * sizeof(struct merged_section *));
i = 1;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
output_sections[i++] = ms;
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
output_sections[i++] = ms;
zerofill = &(ms->next);
}
p = &(msg->next);
}
}
static
void
set_SG_NORELOC_flags(void)
{
struct merged_segment **p, *msg;
struct merged_section **content, **zerofill, *ms;
enum bool relocated, referenced;
free(output_sections);
output_sections = NULL;
p = &merged_segments;
while(*p){
relocated = FALSE;
referenced = FALSE;
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->relocated == TRUE)
relocated = TRUE;
if(ms->referenced == TRUE)
referenced = TRUE;
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
if(ms->referenced == TRUE)
referenced = TRUE;
zerofill = &(ms->next);
}
if(relocated == FALSE && referenced == FALSE)
msg->sg.flags |= SG_NORELOC;
p = &(msg->next);
}
}
#ifndef RLD
static
void
setup_output_flush(void)
{
unsigned long offset;
struct merged_segment **p, *msg;
struct merged_section **content, *ms;
offset = sizeof(struct mach_header) + output_mach_header.sizeofcmds;
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->s.size != 0){
if(ms->s.offset != offset)
output_flush(offset, ms->s.offset - offset);
offset = ms->s.offset + ms->s.size;
}
content = &(ms->next);
}
p = &(msg->next);
}
p = &merged_segments;
while(*p){
msg = *p;
content = &(msg->content_sections);
while(*content){
ms = *content;
if(ms->s.nreloc != 0){
if(ms->s.reloff != offset)
output_flush(offset, ms->s.reloff - offset);
offset = ms->s.reloff +
ms->s.nreloc * sizeof(struct relocation_info);
}
content = &(ms->next);
}
p = &(msg->next);
}
if(output_dysymtab_info.dysymtab_command.nlocrel != 0){
output_flush(offset,
output_dysymtab_info.dysymtab_command.locreloff -
offset);
offset = output_dysymtab_info.dysymtab_command.locreloff +
output_dysymtab_info.dysymtab_command.nlocrel *
sizeof(struct relocation_info);
}
if(output_for_dyld){
if(strip_level != STRIP_ALL){
if(output_symtab_info.symtab_command.symoff != offset)
output_flush(offset,
output_symtab_info.symtab_command.symoff - offset);
offset = output_symtab_info.symtab_command.symoff +
output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist);
}
}
if(output_for_dyld && twolevel_namespace == TRUE &&
twolevel_namespace_hints == TRUE){
output_flush(offset,
output_hints_info.twolevel_hints_command.offset -
offset);
offset = output_hints_info.twolevel_hints_command.offset +
output_hints_info.twolevel_hints_command.nhints *
sizeof(struct twolevel_hint);
}
if(output_dysymtab_info.dysymtab_command.nextrel != 0){
output_flush(offset,
output_dysymtab_info.dysymtab_command.extreloff -
offset);
offset = output_dysymtab_info.dysymtab_command.extreloff +
output_dysymtab_info.dysymtab_command.nextrel *
sizeof(struct relocation_info);
}
if(output_dysymtab_info.dysymtab_command.nindirectsyms != 0){
if(output_dysymtab_info.dysymtab_command.indirectsymoff != offset)
output_flush(offset, output_dysymtab_info.
dysymtab_command.indirectsymoff - offset);
offset = output_dysymtab_info.dysymtab_command.indirectsymoff +
output_dysymtab_info.dysymtab_command.nindirectsyms *
sizeof(unsigned long);
}
#ifndef RLD
if(output_dysymtab_info.dysymtab_command.ntoc != 0){
if(output_dysymtab_info.dysymtab_command.tocoff != offset)
output_flush(offset, output_dysymtab_info.
dysymtab_command.tocoff - offset);
offset = output_dysymtab_info.dysymtab_command.tocoff +
output_dysymtab_info.dysymtab_command.ntoc *
sizeof(struct dylib_table_of_contents);
}
if(output_dysymtab_info.dysymtab_command.nmodtab != 0){
if(output_dysymtab_info.dysymtab_command.modtaboff != offset)
output_flush(offset, output_dysymtab_info.
dysymtab_command.modtaboff - offset);
offset = output_dysymtab_info.dysymtab_command.modtaboff +
output_dysymtab_info.dysymtab_command.nmodtab *
sizeof(struct dylib_module);
}
if(output_dysymtab_info.dysymtab_command.nextrefsyms != 0){
if(output_dysymtab_info.dysymtab_command.extrefsymoff != offset)
output_flush(offset, output_dysymtab_info.
dysymtab_command.extrefsymoff - offset);
offset = output_dysymtab_info.dysymtab_command.extrefsymoff +
output_dysymtab_info.dysymtab_command.nextrefsyms *
sizeof(struct dylib_reference);
}
#endif
if(output_for_dyld == FALSE){
if(strip_level != STRIP_ALL){
if(output_symtab_info.symtab_command.symoff != offset)
output_flush(offset,
output_symtab_info.symtab_command.symoff - offset);
offset = output_symtab_info.symtab_command.symoff +
output_symtab_info.symtab_command.nsyms *
sizeof(struct nlist);
}
}
if(strip_level != STRIP_ALL){
if(output_symtab_info.symtab_command.stroff +
output_symtab_info.output_merged_strsize != offset)
output_flush(offset, output_symtab_info.symtab_command.stroff +
output_symtab_info.output_merged_strsize - offset);
if(output_symtab_info.output_strpad != 0){
output_flush(output_symtab_info.symtab_command.stroff +
output_symtab_info.symtab_command.strsize -
output_symtab_info.output_strpad,
output_symtab_info.output_strpad);
}
offset = output_symtab_info.symtab_command.stroff +
output_symtab_info.symtab_command.strsize;
}
if(offset != output_size)
output_flush(offset, output_size - offset);
}
__private_extern__
void
output_flush(
unsigned long offset,
unsigned long size)
{
unsigned long write_offset, write_size;
struct block **p, *block, *before, *after;
kern_return_t r;
if(flush == FALSE)
return;
if(offset + size > output_size)
fatal("internal error: output_flush(offset = %lu, size = %lu) out "
"of range for output_size = %lu", offset, size, output_size);
#ifdef DEBUG
if(debug & (1 << 12))
print_block_list();
if(debug & (1 << 11))
print("output_flush(offset = %lu, size %lu)", offset, size);
#endif
if(size == 0){
#ifdef DEBUG
if(debug & (1 << 11))
print("\n");
#endif
return;
}
before = NULL;
after = NULL;
p = &(output_blocks);
while(*p){
block = *p;
if(offset < block->offset){
after = block;
break;
}
else{
before = block;
}
p = &(block->next);
}
if(before != NULL){
if(before->offset + before->size > offset){
warning("internal error: output_flush(offset = %lu, size = %lu) "
"overlaps with flushed block(offset = %lu, size = %lu)",
offset, size, before->offset, before->size);
printf("calling abort()\n");
abort();
}
}
if(after != NULL){
if(offset + size > after->offset){
warning("internal error: output_flush(offset = %lu, size = %lu) "
"overlaps with flushed block(offset = %lu, size = %lu)",
offset, size, after->offset, after->size);
printf("calling abort()\n");
abort();
}
}
if(before != NULL && before->offset + before->size == offset){
if(after != NULL && offset + size == after->offset){
if(before->offset == 0 && before->written_size == 0){
write_offset = 0;
before->written_offset = 0;
}
else
write_offset =before->written_offset + before->written_size;
if(after->written_size == 0)
write_size = trnc(after->offset + after->size -
write_offset, host_pagesize);
else
write_size = trnc(after->written_offset - write_offset,
host_pagesize);
if(write_size != 0){
before->written_size += write_size;
}
if(after->written_size != 0)
before->written_size += after->written_size;
before->size += size + after->size;
before->next = after->next;
remove_block(after);
}
else{
write_offset = before->written_offset + before->written_size;
write_size = trnc(offset + size - write_offset, host_pagesize);
if(write_size != 0)
before->written_size += write_size;
before->size += size;
}
}
else if(after != NULL && offset + size == after->offset){
write_offset = rnd(offset, host_pagesize);
if(after->written_size == 0)
write_size = trnc(after->offset + after->size - write_offset,
host_pagesize);
else
write_size = trnc(after->written_offset - write_offset,
host_pagesize);
if(write_size != 0){
after->written_offset = write_offset;
after->written_size += write_size;
}
else if(write_offset != after->written_offset){
after->written_offset = write_offset;
}
after->offset = offset;
after->size += size;
}
else{
write_offset = rnd(offset, host_pagesize);
write_size = trnc(offset + size - write_offset, host_pagesize);
block = get_block();
block->offset = offset;
block->size = size;
block->written_offset = write_offset;
block->written_size = write_size;
if(before != NULL){
block->next = before->next;
before->next = block;
}
else{
block->next = output_blocks;
output_blocks = block;
}
}
if(write_size != 0){
#ifdef DEBUG
if((debug & (1 << 11)) || (debug & (1 << 10)))
print(" writing (write_offset = %lu write_size = %lu)\n",
write_offset, write_size);
#endif
lseek(fd, write_offset, L_SET);
if(write(fd, output_addr + write_offset, write_size) !=
(int)write_size)
system_fatal("can't write to output file");
if((r = vm_deallocate(mach_task_self(), (vm_address_t)(output_addr +
write_offset), write_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() buffer for output file");
}
#ifdef DEBUG
else{
if(debug & (1 << 11))
print(" no write\n");
}
#endif
}
static
void
final_output_flush(void)
{
struct block *block;
unsigned long write_offset, write_size;
kern_return_t r;
#ifdef DEBUG
write_offset = 0;
if((debug & (1 << 11)) || (debug & (1 << 10))){
print("final_output_flush block_list:\n");
print_block_list();
}
#endif
write_size = 0;
block = output_blocks;
if(block != NULL){
if(block->offset != 0)
fatal("internal error: first block not at offset 0");
if(block->written_size != 0){
if(block->written_offset != 0)
fatal("internal error: first block written_offset not 0");
write_offset = block->written_size;
write_size = block->size - block->written_size;
}
else{
write_offset = block->offset;
write_size = block->size;
}
if(block->next != NULL)
fatal("internal error: more than one block in final list");
}
if(write_size != 0){
#ifdef DEBUG
if((debug & (1 << 11)) || (debug & (1 << 10)))
print(" writing (write_offset = %lu write_size = %lu)\n",
write_offset, write_size);
#endif
lseek(fd, write_offset, L_SET);
if(write(fd, output_addr + write_offset, write_size) !=
(int)write_size)
system_fatal("can't write to output file");
if((r = vm_deallocate(mach_task_self(), (vm_address_t)(output_addr +
write_offset), write_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() buffer for output file");
}
}
#ifdef DEBUG
static
void
print_block_list(void)
{
struct block **p, *block;
p = &(output_blocks);
if(*p == NULL)
print("Empty block list\n");
while(*p){
block = *p;
print("block 0x%x\n", (unsigned int)block);
print(" offset %lu\n", block->offset);
print(" size %lu\n", block->size);
print(" written_offset %lu\n", block->written_offset);
print(" written_size %lu\n", block->written_size);
print(" next 0x%x\n", (unsigned int)(block->next));
p = &(block->next);
}
}
#endif
static
struct block *
get_block(void)
{
struct block *block;
block = allocate(sizeof(struct block));
return(block);
}
static
void
remove_block(
struct block *block)
{
free(block);
}
static
unsigned long
trnc(
unsigned long v,
unsigned long r)
{
if(((long)v) < 0)
return(0);
return(v & ~(r - 1));
}
#endif
static
void
output_headers(void)
{
unsigned long header_offset;
struct merged_segment **p, *msg;
struct merged_section **content, **zerofill, *ms;
#ifndef RLD
unsigned long i;
struct merged_fvmlib **q, *mfl;
struct dylinker_command *dyld;
struct merged_dylib *mdl;
struct dylib_command *dl;
struct dynamic_library *dp;
enum bool some_symbols_referenced, some_non_weak_refs;
#endif
struct mach_header *mh;
struct load_command *lc;
header_offset = 0;
mh = (struct mach_header *)output_addr;
memcpy(mh, &output_mach_header, sizeof(struct mach_header));
header_offset += sizeof(struct mach_header);
lc = (struct load_command *)(output_addr + header_offset);
p = &merged_segments;
while(*p){
msg = *p;
memcpy(output_addr + header_offset, &(msg->sg),
sizeof(struct segment_command));
header_offset += sizeof(struct segment_command);
content = &(msg->content_sections);
while(*content){
ms = *content;
memcpy(output_addr + header_offset, &(ms->s),
sizeof(struct section));
header_offset += sizeof(struct section);
content = &(ms->next);
}
zerofill = &(msg->zerofill_sections);
while(*zerofill){
ms = *zerofill;
memcpy(output_addr + header_offset, &(ms->s),
sizeof(struct section));
header_offset += sizeof(struct section);
zerofill = &(ms->next);
}
p = &(msg->next);
}
#ifndef RLD
q = &merged_fvmlibs;
while(*q){
mfl = *q;
memcpy(output_addr + header_offset, mfl->fl, mfl->fl->cmdsize);
header_offset += mfl->fl->cmdsize;
q = &(mfl->next);
}
if(merged_dylinker != NULL){
memcpy(output_addr + header_offset, merged_dylinker->dyld,
merged_dylinker->dyld->cmdsize);
if(filetype != MH_DYLINKER){
dyld = (struct dylinker_command *)(output_addr + header_offset);
dyld->cmd = LC_LOAD_DYLINKER;
}
header_offset += merged_dylinker->dyld->cmdsize;
}
mdl = merged_dylibs;
while(mdl != NULL){
memcpy(output_addr + header_offset, mdl->dl, mdl->dl->cmdsize);
if(mdl->output_id == FALSE){
dl = (struct dylib_command *)(output_addr + header_offset);
some_symbols_referenced =
mdl->dynamic_library->some_symbols_referenced;
some_non_weak_refs =
mdl->dynamic_library->some_non_weak_refs;
for(i = 0; i < mdl->dynamic_library->nsub_images; i++){
if(mdl->dynamic_library->sub_images[i]->
some_symbols_referenced == TRUE){
some_symbols_referenced = TRUE;
if(mdl->dynamic_library->sub_images[i]->
some_non_weak_refs == TRUE)
some_non_weak_refs = TRUE;
}
}
if((some_symbols_referenced == TRUE &&
some_non_weak_refs == FALSE) ||
mdl->dynamic_library->force_weak_dylib == TRUE){
if(macosx_deployment_target.major >= 2){
dl->cmd = LC_LOAD_WEAK_DYLIB;
}
else{
warning("dynamic shared library: %s not made a weak "
"library in output with "
"MACOSX_DEPLOYMENT_TARGET environment variable "
"set to: %s", mdl->definition_object->file_name,
macosx_deployment_target.name);
dl->cmd = LC_LOAD_DYLIB;
}
}
else
dl->cmd = LC_LOAD_DYLIB;
}
header_offset += mdl->dl->cmdsize;
mdl = mdl->next;
}
if(merged_sub_framework != NULL){
memcpy(output_addr + header_offset, merged_sub_framework->sub,
merged_sub_framework->sub->cmdsize);
header_offset += merged_sub_framework->sub->cmdsize;
}
for(i = 0; i < nsub_umbrellas ; i++){
memcpy(output_addr + header_offset, merged_sub_umbrellas[i].sub,
merged_sub_umbrellas[i].sub->cmdsize);
header_offset += merged_sub_umbrellas[i].sub->cmdsize;
}
for(i = 0; i < nsub_librarys ; i++){
memcpy(output_addr + header_offset, merged_sub_librarys[i].sub,
merged_sub_librarys[i].sub->cmdsize);
header_offset += merged_sub_librarys[i].sub->cmdsize;
}
for(i = 0; i < nallowable_clients ; i++){
memcpy(output_addr + header_offset, merged_sub_clients[i].sub,
merged_sub_clients[i].sub->cmdsize);
header_offset += merged_sub_clients[i].sub->cmdsize;
}
if(filetype == MH_EXECUTE){
for(dp = dynamic_libs; dp != NULL; dp = dp->next){
if(dp->type == DYLIB){
if(dp->pbdylib != NULL){
memcpy(output_addr + header_offset, dp->pbdylib,
dp->pbdylib->cmdsize);
header_offset += dp->pbdylib->cmdsize;
}
}
}
}
#endif
memcpy(output_addr + header_offset,
&(output_symtab_info.symtab_command),
output_symtab_info.symtab_command.cmdsize);
header_offset += output_symtab_info.symtab_command.cmdsize;
if(nindirectsyms != 0 || output_for_dyld){
memcpy(output_addr + header_offset,
&(output_dysymtab_info.dysymtab_command),
output_dysymtab_info.dysymtab_command.cmdsize);
header_offset += output_dysymtab_info.dysymtab_command.cmdsize;
}
if(output_for_dyld && twolevel_namespace == TRUE &&
twolevel_namespace_hints == TRUE){
memcpy(output_addr + header_offset,
&(output_hints_info.twolevel_hints_command),
output_hints_info.twolevel_hints_command.cmdsize);
header_offset += output_hints_info.twolevel_hints_command.cmdsize;
}
if(output_cksum_info.prebind_cksum_command.cmdsize != 0){
memcpy(output_addr + header_offset,
&(output_cksum_info.prebind_cksum_command),
output_cksum_info.prebind_cksum_command.cmdsize);
header_offset += output_cksum_info.prebind_cksum_command.cmdsize;
}
if(output_uuid_info.uuid_command.cmdsize != 0){
memcpy(output_addr + header_offset,
&(output_uuid_info.uuid_command),
output_uuid_info.uuid_command.cmdsize);
header_offset += output_uuid_info.uuid_command.cmdsize;
}
if(output_thread_info.thread_in_output == TRUE){
memcpy(output_addr + header_offset,
&(output_thread_info.thread_command),
sizeof(struct thread_command));
header_offset += sizeof(struct thread_command);
memcpy(output_addr + header_offset, &(output_thread_info.flavor),
sizeof(long));
header_offset += sizeof(long);
memcpy(output_addr + header_offset, &(output_thread_info.count),
sizeof(long));
header_offset += sizeof(long);
memcpy(output_addr + header_offset, output_thread_info.state,
output_thread_info.count * sizeof(long));
header_offset += output_thread_info.count * sizeof(long);
if(output_thread_info.second_count != 0){
memcpy(output_addr + header_offset,
&(output_thread_info.second_flavor),
sizeof(long));
header_offset += sizeof(long);
memcpy(output_addr + header_offset,
&(output_thread_info.second_count),
sizeof(long));
header_offset += sizeof(long);
memcpy(output_addr + header_offset,
output_thread_info.second_state,
output_thread_info.second_count * sizeof(long));
header_offset += output_thread_info.second_count * sizeof(long);
}
}
if(output_routines_info.routines_in_output == TRUE){
memcpy(output_addr + header_offset,
&(output_routines_info.routines_command),
sizeof(struct routines_command));
header_offset += sizeof(struct routines_command);
}
if(host_byte_sex != target_byte_sex)
if(swap_object_headers(mh, lc) == FALSE)
fatal("internal error: swap_object_headers() failed in "
"output_headers()");
#ifndef RLD
output_flush(0, sizeof(struct mach_header) +
output_mach_header.sizeofcmds);
#endif
}