enum bool swap_object_headers( void *mach_header, struct load_command *load_commands) { unsigned long i; uint32_t magic, ncmds, sizeofcmds, cmd_multiple; cpu_type_t cputype; cpu_subtype_t cpusubtype; struct mach_header *mh; struct mach_header_64 *mh64; enum byte_sex target_byte_sex; struct load_command *lc, l; struct segment_command *sg; struct segment_command_64 *sg64; struct section *s; struct section_64 *s64; struct symtab_command *st; struct dysymtab_command *dyst; struct symseg_command *ss; struct fvmlib_command *fl; struct thread_command *ut; struct ident_command *id; struct dylib_command *dl; struct sub_framework_command *sub; struct sub_umbrella_command *usub; struct sub_library_command *lsub; struct sub_client_command *csub; struct prebound_dylib_command *pbdylib; struct dylinker_command *dyld; struct routines_command *rc; struct routines_command_64 *rc64; struct twolevel_hints_command *hints; struct prebind_cksum_command *cs; struct uuid_command *uuid; unsigned long flavor, count, nflavor; char *p, *state; magic = *((uint32_t *)mach_header); if(magic == MH_MAGIC){ mh = (struct mach_header *)mach_header; ncmds = mh->ncmds; sizeofcmds = mh->sizeofcmds; cputype = mh->cputype; cpusubtype = mh->cpusubtype; cmd_multiple = 4; mh64 = NULL; } else{ mh64 = (struct mach_header_64 *)mach_header; ncmds = mh64->ncmds; sizeofcmds = mh64->sizeofcmds; cputype = mh64->cputype; cpusubtype = mh64->cpusubtype; cmd_multiple = 8; mh = NULL; } /* * Make a pass through the load commands checking them to the level * that they can be parsed and then swapped. */ for(i = 0, lc = load_commands; i < ncmds; i++){ l = *lc; /* check load command size for a correct multiple size */ if(lc->cmdsize % cmd_multiple != 0){ error("in swap_object_headers(): malformed load command %lu " "(cmdsize not a multiple of %u)", i, cmd_multiple); return(FALSE); } /* check that load command does not extends past end of commands */ if((char *)lc + lc->cmdsize > (char *)load_commands + sizeofcmds){ error("in swap_object_headers(): truncated or malformed load " "command %lu (extends past the end of the all load " "commands)", i); return(FALSE); } /* check that the load command size is not zero */ if(lc->cmdsize == 0){ error("in swap_object_headers(): malformed load command %lu " "(cmdsize is zero)", i); return(FALSE); } switch(lc->cmd){ case LC_SEGMENT: sg = (struct segment_command *)lc; if(sg->cmdsize != sizeof(struct segment_command) + sg->nsects * sizeof(struct section)){ error("in swap_object_headers(): malformed load command " "(inconsistent cmdsize in LC_SEGMENT command %lu for " "the number of sections)", i); return(FALSE); } break; case LC_SEGMENT_64: sg64 = (struct segment_command_64 *)lc; if(sg64->cmdsize != sizeof(struct segment_command_64) + sg64->nsects * sizeof(struct section_64)){ error("in swap_object_headers(): malformed load command " "(inconsistent cmdsize in LC_SEGMENT_64 command %lu " "for the number of sections)", i); return(FALSE); } break; case LC_SYMTAB: st = (struct symtab_command *)lc; if(st->cmdsize != sizeof(struct symtab_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SYMTAB command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_DYSYMTAB: dyst = (struct dysymtab_command *)lc; if(dyst->cmdsize != sizeof(struct dysymtab_command)){ error("in swap_object_headers(): malformed load commands " "(LC_DYSYMTAB command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_SYMSEG: ss = (struct symseg_command *)lc; if(ss->cmdsize != sizeof(struct symseg_command)){ error("in swap_object_headers(): malformed load command " "(LC_SYMSEG command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_IDFVMLIB: case LC_LOADFVMLIB: fl = (struct fvmlib_command *)lc; if(fl->cmdsize < sizeof(struct fvmlib_command)){ error("in swap_object_headers(): malformed load commands " "(%s command %lu has too small cmdsize field)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB" : "LC_LOADFVMLIB", i); return(FALSE); } if(fl->fvmlib.name.offset >= fl->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of %s command %lu " "extends past the end of all load commands)", fl->cmd == LC_IDFVMLIB ? "LC_IDFVMLIB" : "LC_LOADFVMLIB", i); return(FALSE); } break; case LC_ID_DYLIB: case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: dl = (struct dylib_command *)lc; if(dl->cmdsize < sizeof(struct dylib_command)){ error("in swap_object_headers(): malformed load commands " "(%s command %lu has too small cmdsize field)", dl->cmd == LC_ID_DYLIB ? "LC_ID_DYLIB" : (dl->cmd == LC_LOAD_DYLIB ? "LC_LOAD_DYLIB" : "LC_LOAD_WEAK_DYLIB"), i); return(FALSE); } if(dl->dylib.name.offset >= dl->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of %s command %lu " "extends past the end of all load commands)", dl->cmd == LC_ID_DYLIB ? "LC_ID_DYLIB" : (dl->cmd == LC_LOAD_DYLIB ? "LC_LOAD_DYLIB" : "LC_LOAD_WEAK_DYLIB"), i); return(FALSE); } break; case LC_SUB_FRAMEWORK: sub = (struct sub_framework_command *)lc; if(sub->cmdsize < sizeof(struct sub_framework_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_FRAMEWORK command %lu has too small cmdsize " "field)", i); return(FALSE); } if(sub->umbrella.offset >= sub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (umbrella.offset field of " "LC_SUB_FRAMEWORK command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_SUB_UMBRELLA: usub = (struct sub_umbrella_command *)lc; if(usub->cmdsize < sizeof(struct sub_umbrella_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_UMBRELLA command %lu has too small cmdsize " "field)", i); return(FALSE); } if(usub->sub_umbrella.offset >= usub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (sub_umbrella.offset field of " "LC_SUB_UMBRELLA command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_SUB_LIBRARY: lsub = (struct sub_library_command *)lc; if(lsub->cmdsize < sizeof(struct sub_library_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_LIBRARY command %lu has too small cmdsize " "field)", i); return(FALSE); } if(lsub->sub_library.offset >= lsub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (sub_library.offset field of " "LC_SUB_LIBRARY command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_SUB_CLIENT: csub = (struct sub_client_command *)lc; if(csub->cmdsize < sizeof(struct sub_client_command)){ error("in swap_object_headers(): malformed load commands " "(LC_SUB_CLIENT command %lu has too small cmdsize " "field)", i); return(FALSE); } if(csub->client.offset >= csub->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (client.offset field of " "LC_SUB_CLIENT command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_PREBOUND_DYLIB: pbdylib = (struct prebound_dylib_command *)lc; if(pbdylib->cmdsize < sizeof(struct prebound_dylib_command)){ error("in swap_object_headers(): malformed load commands " "(LC_PREBOUND_DYLIB command %lu has too small " "cmdsize field)", i); return(FALSE); } if(pbdylib->name.offset >= pbdylib->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of " "LC_PREBOUND_DYLIB command %lu extends past the end " "of all load commands)", i); return(FALSE); } if(pbdylib->linked_modules.offset >= pbdylib->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (linked_modules.offset field of " "LC_PREBOUND_DYLIB command %lu extends past the end " "of all load commands)", i); return(FALSE); } break; case LC_ID_DYLINKER: case LC_LOAD_DYLINKER: dyld = (struct dylinker_command *)lc; if(dyld->cmdsize < sizeof(struct dylinker_command)){ error("in swap_object_headers(): malformed load commands " "(%s command %lu has too small cmdsize field)", dyld->cmd == LC_ID_DYLINKER ? "LC_ID_DYLINKER" : "LC_LOAD_DYLINKER", i); return(FALSE); } if(dyld->name.offset >= dyld->cmdsize){ error("in swap_object_headers(): truncated or malformed " "load commands (name.offset field of %s command %lu " "extends past the end of all load commands)", dyld->cmd == LC_ID_DYLINKER ? "LC_ID_DYLINKER" : "LC_LOAD_DYLINKER", i); return(FALSE); } break; case LC_UNIXTHREAD: case LC_THREAD: ut = (struct thread_command *)lc; state = (char *)ut + sizeof(struct thread_command); if(cputype == CPU_TYPE_MC680x0){ struct m68k_thread_state_regs *cpu; struct m68k_thread_state_68882 *fpu; struct m68k_thread_state_user_reg *user_reg; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case M68K_THREAD_STATE_REGS: if(count != M68K_THREAD_STATE_REGS_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M68K_THREAD_STATE_REGS_COUNT for " "flavor number %lu which is a M68K_THREAD_" "STATE_REGS flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct m68k_thread_state_regs *)state; state += sizeof(struct m68k_thread_state_regs); break; case M68K_THREAD_STATE_68882: if(count != M68K_THREAD_STATE_68882_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M68K_THREAD_STATE_68882_COUNT for " "flavor number %lu which is a M68K_THREAD_" "STATE_68882 flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct m68k_thread_state_68882 *)state; state += sizeof(struct m68k_thread_state_68882); break; case M68K_THREAD_STATE_USER_REG: if(count != M68K_THREAD_STATE_USER_REG_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M68K_THREAD_STATE_USER_REG_COUNT for " "flavor number %lu which is a M68K_THREAD_" "STATE_USER_REG flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } user_reg = (struct m68k_thread_state_user_reg *)state; state += sizeof(struct m68k_thread_state_user_reg); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_POWERPC || cputype == CPU_TYPE_VEO || cputype == CPU_TYPE_POWERPC64){ ppc_thread_state_t *cpu; ppc_float_state_t *fpu; ppc_exception_state_t *except; ppc_thread_state64_t *cpu64; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case PPC_THREAD_STATE: if(count != PPC_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_THREAD_STATE_COUNT for " "flavor number %lu which is a PPC_THREAD_" "STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (ppc_thread_state_t *)state; state += sizeof(ppc_thread_state_t); break; case PPC_FLOAT_STATE: if(count != PPC_FLOAT_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_FLOAT_STATE_COUNT for " "flavor number %lu which is a PPC_FLOAT_" "STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (ppc_float_state_t *)state; state += sizeof(ppc_float_state_t); break; case PPC_EXCEPTION_STATE: if(count != PPC_EXCEPTION_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_EXCEPTION_STATE_COUNT for " "flavor number %lu which is a PPC_EXCEPT" "ION_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } except = (ppc_exception_state_t *)state; state += sizeof(ppc_exception_state_t); break; case PPC_THREAD_STATE64: if(count != PPC_THREAD_STATE64_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not PPC_THREAD_STATE64_COUNT for " "flavor number %lu which is a PPC_THREAD_" "STATE64 flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu64 = (ppc_thread_state64_t *)state; state += sizeof(ppc_thread_state64_t); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_MC88000){ m88k_thread_state_grf_t *cpu; m88k_thread_state_xrf_t *fpu; m88k_thread_state_user_t *user; m88110_thread_state_impl_t *spu; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case M88K_THREAD_STATE_GRF: if(count != M88K_THREAD_STATE_GRF_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88K_THREAD_STATE_GRF_COUNT for " "flavor number %lu which is a M88K_THREAD_" "STATE_GRF flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (m88k_thread_state_grf_t *)state; state += sizeof(m88k_thread_state_grf_t); break; case M88K_THREAD_STATE_XRF: if(count != M88K_THREAD_STATE_XRF_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88K_THREAD_STATE_XRF_COUNT for " "flavor number %lu which is a M88K_THREAD_" "STATE_XRF flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (m88k_thread_state_xrf_t *)state; state += sizeof(m88k_thread_state_xrf_t); break; case M88K_THREAD_STATE_USER: if(count != M88K_THREAD_STATE_USER_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88K_THREAD_STATE_USER_COUNT for " "flavor number %lu which is a M88K_THREAD_" "STATE_USER flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } user = (m88k_thread_state_user_t *)state; state += sizeof(m88k_thread_state_user_t); break; case M88110_THREAD_STATE_IMPL: if(count != M88110_THREAD_STATE_IMPL_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not M88110_THREAD_STATE_IMPL_COUNT for " "flavor number %lu which is a M88110_THREAD" "_STATE_IMPL flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } spu = (m88110_thread_state_impl_t *)state; state += sizeof(m88110_thread_state_impl_t); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_I860){ struct i860_thread_state_regs *cpu; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case I860_THREAD_STATE_REGS: if(count != I860_THREAD_STATE_REGS_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not I860_THREAD_STATE_REGS_COUNT for " "flavor number %lu which is a I860_THREAD_" "STATE_REGS flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct i860_thread_state_regs *)state; state += sizeof(struct i860_thread_state_regs); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_I386 #ifdef x86_THREAD_STATE64 || cputype == CPU_TYPE_X86_64 #endif /* x86_THREAD_STATE64 */ ){ i386_thread_state_t *cpu; #ifdef x86_THREAD_STATE64 x86_thread_state64_t *cpu64; #endif /* x86_THREAD_STATE64 */ /* current i386 thread states */ #if i386_THREAD_STATE == 1 struct i386_float_state *fpu; i386_exception_state_t *exc; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 i386_thread_fpstate_t *fpu; i386_thread_exceptstate_t *exc; i386_thread_cthreadstate_t *user; #endif /* i386_THREAD_STATE == -1 */ nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case i386_THREAD_STATE: /* current i386 thread states */ #if i386_THREAD_STATE == 1 case -1: #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case 1: #endif /* i386_THREAD_STATE == -1 */ if(count != i386_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_STATE_COUNT for flavor " "number %lu which is a i386_THREAD_STATE " "flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (i386_thread_state_t *)state; state += sizeof(i386_thread_state_t); break; /* current i386 thread states */ #if i386_THREAD_STATE == 1 case i386_FLOAT_STATE: if(count != i386_FLOAT_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_FLOAT_STATE_COUNT for flavor " "number %lu which is a i386_FLOAT_STATE " "flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct i386_float_state *)state; state += sizeof(struct i386_float_state); break; case i386_EXCEPTION_STATE: if(count != I386_EXCEPTION_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not I386_EXCEPTION_STATE_COUNT for " "flavor number %lu which is a i386_" "EXCEPTION_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } exc = (i386_exception_state_t *)state; state += sizeof(i386_exception_state_t); break; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case i386_THREAD_FPSTATE: if(count != i386_THREAD_FPSTATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_FPSTATE_COUNT for flavor " "number %lu which is a i386_THREAD_FPSTATE " "flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (i386_thread_fpstate_t *)state; state += sizeof(i386_thread_fpstate_t); break; case i386_THREAD_EXCEPTSTATE: if(count != i386_THREAD_EXCEPTSTATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_EXCEPTSTATE_COUNT for " "flavor number %lu which is a i386_THREAD_" "EXCEPTSTATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } exc = (i386_thread_exceptstate_t *)state; state += sizeof(i386_thread_fpstate_t); break; case i386_THREAD_CTHREADSTATE: if(count != i386_THREAD_CTHREADSTATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not i386_THREAD_CTHREADSTATE_COUNT for " "flavor number %lu which is a i386_THREAD_" "CTHREADSTATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } user = (i386_thread_cthreadstate_t *)state; state += sizeof(i386_thread_fpstate_t); break; #endif /* i386_THREAD_STATE == -1 */ #ifdef x86_THREAD_STATE64 case x86_THREAD_STATE64: if(count != x86_THREAD_STATE64_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not x86_THREAD_STATE64_COUNT for " "flavor number %lu which is an x86_THREAD_" "STATE64 flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu64 = (x86_thread_state64_t *)state; state += sizeof(x86_thread_state64_t); break; #endif /* x86_THREAD_STATE64 */ default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_HPPA){ struct hp_pa_integer_thread_state *cpu; struct hp_pa_frame_thread_state *frame; struct hp_pa_fp_thread_state *fpu; nflavor = 0; p = (char *)ut + ut->cmdsize; while(state < p){ flavor = *((unsigned long *)state); state += sizeof(unsigned long); count = *((unsigned long *)state); state += sizeof(unsigned long); switch(flavor){ case HPPA_INTEGER_THREAD_STATE: if(count != HPPA_INTEGER_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not HPPA_INTEGER_THREAD_STATE_COUNT for " "flavor number %lu which is a HPPA_INTEGER" "_THREAD_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct hp_pa_integer_thread_state *)state; state += sizeof(struct hp_pa_integer_thread_state); break; case HPPA_FRAME_THREAD_STATE: if(count != HPPA_FRAME_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not HPPA_FRAME_THREAD_STATE_COUNT for " "flavor number %lu which is a HPPA_FRAME" "_THREAD_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } frame = (struct hp_pa_frame_thread_state *)state; state += sizeof(struct hp_pa_frame_thread_state); break; case HPPA_FP_THREAD_STATE: if(count != HPPA_FP_THREAD_STATE_COUNT){ error("in swap_object_headers(): malformed " "load commands (count " "not HPPA_FP_THREAD_STATE_COUNT for " "flavor number %lu which is a HPPA_FP" "_THREAD_STATE flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct hp_pa_fp_thread_state *)state; state += sizeof(struct hp_pa_fp_thread_state); break; default: error("in swap_object_headers(): malformed " "load commands (unknown " "flavor %lu for flavor number %lu in %s command" " %lu can't byte swap it)", flavor, nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } nflavor++; } break; } if(cputype == CPU_TYPE_SPARC) { struct sparc_thread_state_regs *cpu; struct sparc_thread_state_fpu *fpu; nflavor = 0; p = (char *)ut + ut->cmdsize; while (state < p) { flavor = *((unsigned long *) state); state += sizeof(unsigned long); count = *((unsigned int *) state); state += sizeof(unsigned long); switch (flavor) { case SPARC_THREAD_STATE_REGS: if (count != SPARC_THREAD_STATE_REGS_COUNT) { error("in swap_object_headers(): malformed " "load commands (count " "not SPARC_THREAD_STATE_REGS_COUNT for " "flavor number %lu which is a SPARC_THREAD_" "STATE_REGS flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } cpu = (struct sparc_thread_state_regs *) state; state += sizeof(struct sparc_thread_state_regs); break; case SPARC_THREAD_STATE_FPU: if (count != SPARC_THREAD_STATE_FPU_COUNT) { error("in swap_object_headers(): malformed " "load commands (count " "not SPARC_THREAD_STATE_FPU_COUNT for " "flavor number %lu which is a SPARC_THREAD_" "STATE_FPU flavor in %s command %lu)", nflavor, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); } fpu = (struct sparc_thread_state_fpu *) state; state += sizeof(struct sparc_thread_state_fpu); break; } } break; } if (cputype == CPU_TYPE_ARM) { nflavor = 0; p = (char *)ut + ut->cmdsize; while (state < p) { state += 8 + sizeof(arm_thread_state_t); nflavor++; } break; } error("in swap_object_headers(): malformed load commands " "(unknown cputype (%d) and cpusubtype (%d) of object and " "can't byte swap %s command %lu)", cputype, cpusubtype, ut->cmd == LC_UNIXTHREAD ? "LC_UNIXTHREAD" : "LC_THREAD", i); return(FALSE); case LC_IDENT: id = (struct ident_command *)lc; if((char *)id + id->cmdsize > (char *)load_commands + sizeofcmds){ error("in swap_object_headers(): truncated or malformed " "load commands (cmdsize field of LC_IDENT command %lu " "extends past the end of the load commands)", i); return(FALSE); } break; case LC_ROUTINES: rc = (struct routines_command *)lc; if(rc->cmdsize != sizeof(struct routines_command)){ error("in swap_object_headers(): malformed load commands (" "LC_ROUTINES command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_ROUTINES_64: rc64 = (struct routines_command_64 *)lc; if(rc64->cmdsize != sizeof(struct routines_command_64)){ error("in swap_object_headers(): malformed load commands (" "LC_ROUTINES_64 command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_TWOLEVEL_HINTS: hints = (struct twolevel_hints_command *)lc; if(hints->cmdsize != sizeof(struct twolevel_hints_command)){ error("in swap_object_headers(): malformed load commands " "(LC_TWOLEVEL_HINTS command %lu has incorrect " "cmdsize", i); return(FALSE); } break; case LC_PREBIND_CKSUM: cs = (struct prebind_cksum_command *)lc; if(cs->cmdsize != sizeof(struct prebind_cksum_command)){ error("in swap_object_headers(): malformed load commands " "(LC_PREBIND_CKSUM command %lu has incorrect cmdsize", i); return(FALSE); } break; case LC_UUID: uuid = (struct uuid_command *)lc; if(uuid->cmdsize != sizeof(struct uuid_command)){ error("in swap_object_headers(): malformed load commands " "(LC_UUID command %lu has incorrect cmdsize", i); return(FALSE); } break; default: error("in swap_object_headers(): malformed load commands " "(unknown load command %lu)", i); return(FALSE); } lc = (struct load_command *)((char *)lc + l.cmdsize); /* check that next load command does not extends past the end */ if((char *)lc > (char *)load_commands + sizeofcmds){ error("in swap_object_headers(): truncated or malformed load " "commands (load command %lu extends past the end of all " "load commands)", i + 1); return(FALSE); } } /* check for an inconsistent size of the load commands */ if((char *)load_commands + sizeofcmds != (char *)lc){ error("in swap_object_headers(): malformed load commands " "(inconsistent sizeofcmds field in mach header)"); return(FALSE); } /* * Now knowing the load commands can be parsed swap them. */ target_byte_sex = get_host_byte_sex() == BIG_ENDIAN_BYTE_SEX ? LITTLE_ENDIAN_BYTE_SEX : BIG_ENDIAN_BYTE_SEX; for(i = 0, lc = load_commands; i < ncmds; i++){ l = *lc; switch(lc->cmd){ case LC_SEGMENT: sg = (struct segment_command *)lc; s = (struct section *) ((char *)sg + sizeof(struct segment_command)); swap_section(s, sg->nsects, target_byte_sex); swap_segment_command(sg, target_byte_sex); break; case LC_SEGMENT_64: sg64 = (struct segment_command_64 *)lc; s64 = (struct section_64 *) ((char *)sg64 + sizeof(struct segment_command_64)); swap_section_64(s64, sg64->nsects, target_byte_sex); swap_segment_command_64(sg64, target_byte_sex); break; case LC_SYMTAB: st = (struct symtab_command *)lc; swap_symtab_command(st, target_byte_sex); break; case LC_DYSYMTAB: dyst = (struct dysymtab_command *)lc; swap_dysymtab_command(dyst, target_byte_sex); break; case LC_SYMSEG: ss = (struct symseg_command *)lc; swap_symseg_command(ss, target_byte_sex); break; case LC_IDFVMLIB: case LC_LOADFVMLIB: fl = (struct fvmlib_command *)lc; swap_fvmlib_command(fl, target_byte_sex); break; case LC_ID_DYLIB: case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: dl = (struct dylib_command *)lc; swap_dylib_command(dl, target_byte_sex); break; case LC_SUB_FRAMEWORK: sub = (struct sub_framework_command *)lc; swap_sub_framework_command(sub, target_byte_sex); break; case LC_SUB_UMBRELLA: usub = (struct sub_umbrella_command *)lc; swap_sub_umbrella_command(usub, target_byte_sex); break; case LC_SUB_LIBRARY: lsub = (struct sub_library_command *)lc; swap_sub_library_command(lsub, target_byte_sex); break; case LC_SUB_CLIENT: csub = (struct sub_client_command *)lc; swap_sub_client_command(csub, target_byte_sex); break; case LC_PREBOUND_DYLIB: pbdylib = (struct prebound_dylib_command *)lc; swap_prebound_dylib_command(pbdylib, target_byte_sex); break; case LC_ID_DYLINKER: case LC_LOAD_DYLINKER: dyld = (struct dylinker_command *)lc; swap_dylinker_command(dyld, target_byte_sex); break; case LC_UNIXTHREAD: case LC_THREAD: ut = (struct thread_command *)lc; state = (char *)ut + sizeof(struct thread_command); p = (char *)ut + ut->cmdsize; swap_thread_command(ut, target_byte_sex); if(cputype == CPU_TYPE_MC680x0){ struct m68k_thread_state_regs *cpu; struct m68k_thread_state_68882 *fpu; struct m68k_thread_state_user_reg *user_reg; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case M68K_THREAD_STATE_REGS: cpu = (struct m68k_thread_state_regs *)state; swap_m68k_thread_state_regs(cpu, target_byte_sex); state += sizeof(struct m68k_thread_state_regs); break; case M68K_THREAD_STATE_68882: fpu = (struct m68k_thread_state_68882 *)state; swap_m68k_thread_state_68882(fpu, target_byte_sex); state += sizeof(struct m68k_thread_state_68882); break; case M68K_THREAD_STATE_USER_REG: user_reg = (struct m68k_thread_state_user_reg *)state; swap_m68k_thread_state_user_reg(user_reg, target_byte_sex); state += sizeof(struct m68k_thread_state_user_reg); break; } } break; } if(cputype == CPU_TYPE_POWERPC || cputype == CPU_TYPE_VEO || cputype == CPU_TYPE_POWERPC64){ ppc_thread_state_t *cpu; ppc_thread_state64_t *cpu64; ppc_float_state_t *fpu; ppc_exception_state_t *except; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case PPC_THREAD_STATE: cpu = (ppc_thread_state_t *)state; swap_ppc_thread_state_t(cpu, target_byte_sex); state += sizeof(ppc_thread_state_t); break; case PPC_THREAD_STATE64: cpu64 = (ppc_thread_state64_t *)state; swap_ppc_thread_state64_t(cpu64, target_byte_sex); state += sizeof(ppc_thread_state64_t); break; case PPC_FLOAT_STATE: fpu = (ppc_float_state_t *)state; swap_ppc_float_state_t(fpu, target_byte_sex); state += sizeof(ppc_float_state_t); case PPC_EXCEPTION_STATE: except = (ppc_exception_state_t *)state; swap_ppc_exception_state_t(except, target_byte_sex); state += sizeof(ppc_exception_state_t); break; } } break; } if(cputype == CPU_TYPE_MC88000){ m88k_thread_state_grf_t *cpu; m88k_thread_state_xrf_t *fpu; m88k_thread_state_user_t *user; m88110_thread_state_impl_t *spu; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case M88K_THREAD_STATE_GRF: cpu = (m88k_thread_state_grf_t *)state; swap_m88k_thread_state_grf_t(cpu, target_byte_sex); state += sizeof(m88k_thread_state_grf_t); break; case M88K_THREAD_STATE_XRF: fpu = (m88k_thread_state_xrf_t *)state; swap_m88k_thread_state_xrf_t(fpu, target_byte_sex); state += sizeof(m88k_thread_state_xrf_t); break; case M88K_THREAD_STATE_USER: user = (m88k_thread_state_user_t *)state; swap_m88k_thread_state_user_t(user, target_byte_sex); state += sizeof(m88k_thread_state_user_t); break; case M88110_THREAD_STATE_IMPL: spu = (m88110_thread_state_impl_t *)state; swap_m88110_thread_state_impl_t(spu, target_byte_sex); state += sizeof(m88110_thread_state_impl_t); break; } } break; } if(cputype == CPU_TYPE_I860){ struct i860_thread_state_regs *cpu; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case I860_THREAD_STATE_REGS: cpu = (struct i860_thread_state_regs *)state; swap_i860_thread_state_regs(cpu, target_byte_sex); state += sizeof(struct i860_thread_state_regs); break; } } break; } if(cputype == CPU_TYPE_I386 #ifdef x86_THREAD_STATE64 || cputype == CPU_TYPE_X86_64 #endif /* x86_THREAD_STATE64 */ ){ i386_thread_state_t *cpu; #ifdef x86_THREAD_STATE64 x86_thread_state64_t *cpu64; #endif /* x86_THREAD_STATE64 */ /* current i386 thread states */ #if i386_THREAD_STATE == 1 struct i386_float_state *fpu; i386_exception_state_t *exc; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 i386_thread_fpstate_t *fpu; i386_thread_exceptstate_t *exc; i386_thread_cthreadstate_t *user; #endif /* i386_THREAD_STATE == -1 */ while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case i386_THREAD_STATE: /* current i386 thread states */ #if i386_THREAD_STATE == 1 case -1: #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case 1: #endif /* i386_THREAD_STATE == -1 */ cpu = (i386_thread_state_t *)state; swap_i386_thread_state(cpu, target_byte_sex); state += sizeof(i386_thread_state_t); break; /* current i386 thread states */ #if i386_THREAD_STATE == 1 case i386_FLOAT_STATE: fpu = (struct i386_float_state *)state; swap_i386_float_state(fpu, target_byte_sex); state += sizeof(struct i386_float_state); break; case i386_EXCEPTION_STATE: exc = (i386_exception_state_t *)state; swap_i386_exception_state(exc, target_byte_sex); state += sizeof(i386_exception_state_t); break; #endif /* i386_THREAD_STATE == 1 */ /* i386 thread states on older releases */ #if i386_THREAD_STATE == -1 case i386_THREAD_FPSTATE: fpu = (i386_thread_fpstate_t *)state; swap_i386_thread_fpstate(fpu, target_byte_sex); state += sizeof(i386_thread_fpstate_t); break; case i386_THREAD_EXCEPTSTATE: exc = (i386_thread_exceptstate_t *)state; swap_i386_thread_exceptstate(exc, target_byte_sex); state += sizeof(i386_thread_exceptstate_t); break; case i386_THREAD_CTHREADSTATE: user = (i386_thread_cthreadstate_t *)state; swap_i386_thread_cthreadstate(user,target_byte_sex); state += sizeof(i386_thread_cthreadstate_t); break; #endif /* i386_THREAD_STATE == -1 */ #ifdef x86_THREAD_STATE64 case x86_THREAD_STATE64: cpu64 = (x86_thread_state64_t *)state; swap_x86_thread_state64(cpu64, target_byte_sex); state += sizeof(x86_thread_state64_t); break; #endif /* x86_THREAD_STATE64 */ } } break; } if(cputype == CPU_TYPE_HPPA){ struct hp_pa_integer_thread_state *cpu; struct hp_pa_frame_thread_state *frame; struct hp_pa_fp_thread_state *fpu; while(state < p){ flavor = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned long *)state); *((unsigned long *)state) = SWAP_LONG(count); state += sizeof(unsigned long); switch(flavor){ case HPPA_INTEGER_THREAD_STATE: cpu = (struct hp_pa_integer_thread_state *)state; swap_hppa_integer_thread_state(cpu, target_byte_sex); state += sizeof(struct hp_pa_integer_thread_state); break; case HPPA_FRAME_THREAD_STATE: frame = (struct hp_pa_frame_thread_state *)state; swap_hppa_frame_thread_state(frame, target_byte_sex); state += sizeof(struct hp_pa_frame_thread_state); break; case HPPA_FP_THREAD_STATE: fpu = (struct hp_pa_fp_thread_state *)state; swap_hppa_fp_thread_state(fpu, target_byte_sex); state += sizeof(struct hp_pa_fp_thread_state); break; } } break; } if(cputype == CPU_TYPE_SPARC) { struct sparc_thread_state_regs *cpu; struct sparc_thread_state_fpu *fpu; while (state < p) { flavor = *((unsigned long *) state); *((unsigned long *) state) = SWAP_LONG(flavor); state += sizeof(unsigned long); count = *((unsigned int *) state); *((unsigned int *) state) = SWAP_LONG(count); state += sizeof(unsigned long); switch (flavor) { case SPARC_THREAD_STATE_REGS: cpu = (struct sparc_thread_state_regs *) state; swap_sparc_thread_state_regs(cpu, target_byte_sex); state += sizeof(struct sparc_thread_state_regs); break; case SPARC_THREAD_STATE_FPU: fpu = (struct sparc_thread_state_fpu *) state; swap_sparc_thread_state_fpu(fpu, target_byte_sex); state += sizeof(struct sparc_thread_state_fpu); break; } } break; } if (cputype == CPU_TYPE_ARM) { arm_thread_state_t *thread_state; while (state < p) { u_int32_t n; n = *((u_int32_t *)state); *((u_int32_t *)state) = SWAP_LONG(n); state += 4; n = *((u_int32_t *)state); *((u_int32_t *)state) = SWAP_LONG(n); state += 4; thread_state = (arm_thread_state_t *)state; swap_arm_thread_state(thread_state, target_byte_sex); state += sizeof(arm_thread_state_t); } } break; case LC_IDENT: id = (struct ident_command *)lc; swap_ident_command(id, target_byte_sex); break; case LC_ROUTINES: rc = (struct routines_command *)lc; swap_routines_command(rc, target_byte_sex); break; case LC_ROUTINES_64: rc64 = (struct routines_command_64 *)lc; swap_routines_command_64(rc64, target_byte_sex); break; case LC_TWOLEVEL_HINTS: hints = (struct twolevel_hints_command *)lc; swap_twolevel_hints_command(hints, target_byte_sex); break; case LC_PREBIND_CKSUM: cs = (struct prebind_cksum_command *)lc; swap_prebind_cksum_command(cs, target_byte_sex); break; case LC_UUID: uuid = (struct uuid_command *)lc; swap_uuid_command(uuid, target_byte_sex); break; } lc = (struct load_command *)((char *)lc + l.cmdsize); } if(mh != NULL) swap_mach_header(mh, target_byte_sex); else swap_mach_header_64(mh64, target_byte_sex); return(TRUE); }
/* * write_object() writes a Mach-O object file from the built up data structures. */ void write_object( char *out_file_name) { /* The structures for Mach-O relocatables */ mach_header_t header; segment_command_t reloc_segment; struct symtab_command symbol_table; struct dysymtab_command dynamic_symbol_table; uint32_t section_type; uint32_t *indirect_symbols; isymbolS *isymbolP; uint32_t i, j, nsects, nsyms, strsize, nindirectsyms; /* locals to fill in section struct fields */ uint32_t offset, zero; /* The GAS data structures */ struct frchain *frchainP, *p; struct symbol *symbolP; struct frag *fragP; struct fix *fixP; uint32_t output_size; char *output_addr; kern_return_t r; enum byte_sex host_byte_sex; uint32_t reloff, nrelocs; int32_t count; char *fill_literal; int32_t fill_size; int32_t num_bytes; char *symbol_name; int fd; uint32_t local; struct stat stat_buf; #ifdef I860 I860_tweeks(); #endif i = 0; /* to shut up a compiler "may be used uninitialized" warning */ /* * The first group of things to do is to set all the fields in the * header structures which includes offsets and determining the final * sizes of things. */ /* * Fill in the addr and size fields of each section structure and count * the number of sections. */ nsects = 0; for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ frchainP->frch_section.addr = frchainP->frch_root->fr_address; frchainP->frch_section.size = frchainP->frch_last->fr_address - frchainP->frch_root->fr_address; nsects++; } /* * Setup the indirect symbol tables by looking up or creating symbol * from the indirect symbol names and recording the symbol pointers. */ nindirectsyms = layout_indirect_symbols(); /* * Setup the symbol table to include only those symbols that will be in * the object file, assign the string table offsets into the symbols * and size the string table. */ nsyms = 0; strsize = 0; layout_symbols((int32_t *)&nsyms, (int32_t *)&strsize); /* fill in the Mach-O header */ header.magic = MH_MAGIC_VALUE; header.cputype = md_cputype; if(archflag_cpusubtype != -1) header.cpusubtype = archflag_cpusubtype; else header.cpusubtype = md_cpusubtype; header.filetype = MH_OBJECT; header.ncmds = 0; header.sizeofcmds = 0; if(nsects != 0){ header.ncmds += 1; header.sizeofcmds += sizeof(segment_command_t) + nsects * sizeof(section_t); } if(nsyms != 0){ header.ncmds += 1; header.sizeofcmds += sizeof(struct symtab_command); if(flagseen['k']){ header.ncmds += 1; header.sizeofcmds += sizeof(struct dysymtab_command); } } else strsize = 0; header.flags = 0; if(subsections_via_symbols == TRUE) header.flags |= MH_SUBSECTIONS_VIA_SYMBOLS; #ifdef ARCH64 header.reserved = 0; #endif /* fill in the segment command */ memset(&reloc_segment, '\0', sizeof(segment_command_t)); reloc_segment.cmd = LC_SEGMENT_VALUE; reloc_segment.cmdsize = sizeof(segment_command_t) + nsects * sizeof(section_t); /* leave reloc_segment.segname full of zeros */ reloc_segment.vmaddr = 0; reloc_segment.vmsize = 0; reloc_segment.filesize = 0; offset = header.sizeofcmds + sizeof(mach_header_t); reloc_segment.fileoff = offset; reloc_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; reloc_segment.initprot= VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; reloc_segment.nsects = nsects; reloc_segment.flags = 0; /* * Set the offsets to the contents of the sections (for non-zerofill * sections) and set the filesize and vmsize of the segment. This is * complicated by the fact that all the zerofill sections have addresses * after the non-zerofill sections and that the alignment of sections * produces gaps that are not in any section. For the vmsize we rely on * the fact the the sections start at address 0 so it is just the last * zerofill section or the last not-zerofill section. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL) continue; for(p = frchainP->frch_next; p != NULL; p = p->frch_next) if((p->frch_section.flags & SECTION_TYPE) != S_ZEROFILL) break; if(p != NULL) i = p->frch_section.addr - frchainP->frch_section.addr; else i = frchainP->frch_section.size; reloc_segment.filesize += i; frchainP->frch_section.offset = offset; offset += i; reloc_segment.vmsize = frchainP->frch_section.addr + frchainP->frch_section.size; } for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL) continue; reloc_segment.vmsize = frchainP->frch_section.addr + frchainP->frch_section.size; } offset = round(offset, sizeof(int32_t)); /* * Count the number of relocation entries for each section. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ frchainP->frch_section.nreloc = 0; for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){ frchainP->frch_section.nreloc += nrelocs_for_fix(fixP); } } /* * Fill in the offset to the relocation entries of the sections. */ offset = round(offset, sizeof(int32_t)); reloff = offset; nrelocs = 0; for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if(frchainP->frch_section.nreloc == 0) frchainP->frch_section.reloff = 0; else frchainP->frch_section.reloff = offset; offset += frchainP->frch_section.nreloc * sizeof(struct relocation_info); nrelocs += frchainP->frch_section.nreloc; } if(flagseen['k']){ /* fill in the fields of the dysymtab_command */ dynamic_symbol_table.cmd = LC_DYSYMTAB; dynamic_symbol_table.cmdsize = sizeof(struct dysymtab_command); dynamic_symbol_table.ilocalsym = ilocalsym; dynamic_symbol_table.nlocalsym = nlocalsym; dynamic_symbol_table.iextdefsym = iextdefsym; dynamic_symbol_table.nextdefsym = nextdefsym; dynamic_symbol_table.iundefsym = iundefsym; dynamic_symbol_table.nundefsym = nundefsym; if(nindirectsyms == 0){ dynamic_symbol_table.nindirectsyms = 0; dynamic_symbol_table.indirectsymoff = 0; } else{ dynamic_symbol_table.nindirectsyms = nindirectsyms; dynamic_symbol_table.indirectsymoff = offset; offset += nindirectsyms * sizeof(uint32_t); } dynamic_symbol_table.tocoff = 0; dynamic_symbol_table.ntoc = 0; dynamic_symbol_table.modtaboff = 0; dynamic_symbol_table.nmodtab = 0; dynamic_symbol_table.extrefsymoff = 0; dynamic_symbol_table.nextrefsyms = 0; dynamic_symbol_table.extreloff = 0; dynamic_symbol_table.nextrel = 0; dynamic_symbol_table.locreloff = 0; dynamic_symbol_table.nlocrel = 0; } /* fill in the fields of the symtab_command (except the string table) */ symbol_table.cmd = LC_SYMTAB; symbol_table.cmdsize = sizeof(struct symtab_command); if(nsyms == 0) symbol_table.symoff = 0; else symbol_table.symoff = offset; symbol_table.nsyms = nsyms; offset += symbol_table.nsyms * sizeof(nlist_t); /* fill in the string table fields of the symtab_command */ if(strsize == 0) symbol_table.stroff = 0; else symbol_table.stroff = offset; symbol_table.strsize = round(strsize, sizeof(uint32_t)); offset += round(strsize, sizeof(uint32_t)); /* * The second group of things to do is now with the size of everything * known the object file and the offsets set in the various structures * the contents of the object file can be created. */ /* * Create the buffer to copy the parts of the output file into. */ output_size = offset; if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr, output_size, TRUE)) != KERN_SUCCESS) as_fatal("can't vm_allocate() buffer for output file of size %u", output_size); /* put the headers in the output file's buffer */ host_byte_sex = get_host_byte_sex(); offset = 0; /* put the mach_header in the buffer */ memcpy(output_addr + offset, &header, sizeof(mach_header_t)); if(host_byte_sex != md_target_byte_sex) swap_mach_header_t((mach_header_t *)(output_addr + offset), md_target_byte_sex); offset += sizeof(mach_header_t); /* put the segment_command in the buffer */ if(nsects != 0){ memcpy(output_addr + offset, &reloc_segment, sizeof(segment_command_t)); if(host_byte_sex != md_target_byte_sex) swap_segment_command_t((segment_command_t *) (output_addr + offset), md_target_byte_sex); offset += sizeof(segment_command_t); } /* put the segment_command's section structures in the buffer */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ memcpy(output_addr + offset, &(frchainP->frch_section), sizeof(section_t)); if(host_byte_sex != md_target_byte_sex) swap_section_t((section_t *)(output_addr + offset), 1, md_target_byte_sex); offset += sizeof(section_t); } /* put the symbol_command in the buffer */ if(nsyms != 0){ memcpy(output_addr + offset, &symbol_table, sizeof(struct symtab_command)); if(host_byte_sex != md_target_byte_sex) swap_symtab_command((struct symtab_command *) (output_addr + offset), md_target_byte_sex); offset += sizeof(struct symtab_command); } if(flagseen['k']){ /* put the dysymbol_command in the buffer */ if(nsyms != 0){ memcpy(output_addr + offset, &dynamic_symbol_table, sizeof(struct dysymtab_command)); if(host_byte_sex != md_target_byte_sex) swap_dysymtab_command((struct dysymtab_command *) (output_addr + offset), md_target_byte_sex); offset += sizeof(struct dysymtab_command); } } /* put the section contents (frags) in the buffer */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ offset = frchainP->frch_section.offset; for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){ know(fragP->fr_type == rs_fill); /* put the fixed part of the frag in the buffer */ memcpy(output_addr + offset, fragP->fr_literal, fragP->fr_fix); offset += fragP->fr_fix; /* put the variable repeated part of the frag in the buffer */ fill_literal = fragP->fr_literal + fragP->fr_fix; fill_size = fragP->fr_var; num_bytes = fragP->fr_offset * fragP->fr_var; for(count = 0; count < num_bytes; count += fill_size){ memcpy(output_addr + offset, fill_literal, fill_size); offset += fill_size; } } } /* put the symbols in the output file's buffer */ offset = symbol_table.symoff; for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ if((symbolP->sy_type & N_EXT) == 0){ symbol_name = symbolP->sy_name; symbolP->sy_nlist.n_un.n_strx = symbolP->sy_name_offset; if(symbolP->expression != 0) { expressionS *exp; exp = (expressionS *)symbolP->expression; if((exp->X_add_symbol->sy_type & N_TYPE) == N_UNDF) as_fatal("undefined symbol `%s' in operation setting " "`%s'", exp->X_add_symbol->sy_name, symbol_name); if((exp->X_subtract_symbol->sy_type & N_TYPE) == N_UNDF) as_fatal("undefined symbol `%s' in operation setting " "`%s'", exp->X_subtract_symbol->sy_name, symbol_name); if(exp->X_add_symbol->sy_other != exp->X_subtract_symbol->sy_other) as_fatal("invalid sections for operation on `%s' and " "`%s' setting `%s'",exp->X_add_symbol->sy_name, exp->X_subtract_symbol->sy_name, symbol_name); symbolP->sy_nlist.n_value += exp->X_add_symbol->sy_value - exp->X_subtract_symbol->sy_value; } memcpy(output_addr + offset, (char *)(&symbolP->sy_nlist), sizeof(nlist_t)); symbolP->sy_name = symbol_name; offset += sizeof(nlist_t); } } for(i = 0; i < nextdefsym; i++){ symbol_name = extdefsyms[i]->sy_name; extdefsyms[i]->sy_nlist.n_un.n_strx = extdefsyms[i]->sy_name_offset; memcpy(output_addr + offset, (char *)(&extdefsyms[i]->sy_nlist), sizeof(nlist_t)); extdefsyms[i]->sy_name = symbol_name; offset += sizeof(nlist_t); } for(j = 0; j < nundefsym; j++){ symbol_name = undefsyms[j]->sy_name; undefsyms[j]->sy_nlist.n_un.n_strx = undefsyms[j]->sy_name_offset; memcpy(output_addr + offset, (char *)(&undefsyms[j]->sy_nlist), sizeof(nlist_t)); undefsyms[j]->sy_name = symbol_name; offset += sizeof(nlist_t); } if(host_byte_sex != md_target_byte_sex) swap_nlist_t((nlist_t *)(output_addr + symbol_table.symoff), symbol_table.nsyms, md_target_byte_sex); /* * Put the relocation entries for each section in the buffer. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ offset = frchainP->frch_section.reloff; for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){ offset += fix_to_relocation_entries( fixP, frchainP->frch_section.addr, (struct relocation_info *)(output_addr + offset), frchainP->frch_section.flags & S_ATTR_DEBUG); } } if(host_byte_sex != md_target_byte_sex) swap_relocation_info((struct relocation_info *) (output_addr + reloff), nrelocs, md_target_byte_sex); if(flagseen['k']){ /* put the indirect symbol table in the buffer */ offset = dynamic_symbol_table.indirectsymoff; for(frchainP = frchain_root; frchainP != NULL; frchainP = frchainP->frch_next){ section_type = frchainP->frch_section.flags & SECTION_TYPE; if(section_type == S_NON_LAZY_SYMBOL_POINTERS || section_type == S_LAZY_SYMBOL_POINTERS || section_type == S_SYMBOL_STUBS){ /* * For each indirect symbol put out the symbol number. */ for(isymbolP = frchainP->frch_isym_root; isymbolP != NULL; isymbolP = isymbolP->isy_next){ /* * If this is a non-lazy pointer symbol section and * if the symbol is a local symbol then put out * INDIRECT_SYMBOL_LOCAL as the indirect symbol table * entry. This is used with code gen for fix-n-continue * where the compiler generates indirection for static * data references. See the comments at the end of * fixup_section() that explains the assembly code used. */ if(section_type == S_NON_LAZY_SYMBOL_POINTERS && (isymbolP->isy_symbol->sy_nlist.n_type & N_EXT) != N_EXT){ local = INDIRECT_SYMBOL_LOCAL; if((isymbolP->isy_symbol->sy_nlist.n_type & N_TYPE) == N_ABS) local |= INDIRECT_SYMBOL_ABS; memcpy(output_addr + offset, (char *)(&local), sizeof(uint32_t)); } else{ memcpy(output_addr + offset, (char *)(&isymbolP->isy_symbol->sy_number), sizeof(uint32_t)); } offset += sizeof(uint32_t); } } } if(host_byte_sex != md_target_byte_sex){ indirect_symbols = (uint32_t *)(output_addr + dynamic_symbol_table.indirectsymoff); swap_indirect_symbols(indirect_symbols, nindirectsyms, md_target_byte_sex); } } /* put the strings in the output file's buffer */ offset = symbol_table.stroff; if(symbol_table.strsize != 0){ zero = 0; memcpy(output_addr + offset, (char *)&zero, sizeof(char)); offset += sizeof(char); } for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ /* Ordinary case: not .stabd. */ if(symbolP->sy_name != NULL){ if((symbolP->sy_type & N_EXT) != 0){ memcpy(output_addr + offset, symbolP->sy_name, strlen(symbolP->sy_name) + 1); offset += strlen(symbolP->sy_name) + 1; } } } for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ /* Ordinary case: not .stabd. */ if(symbolP->sy_name != NULL){ if((symbolP->sy_type & N_EXT) == 0){ memcpy(output_addr + offset, symbolP->sy_name, strlen(symbolP->sy_name) + 1); offset += strlen(symbolP->sy_name) + 1; } } } /* * Create the output file. The unlink() is done to handle the problem * when the out_file_name is not writable but the directory allows the * file to be removed (since the file may not be there the return code * of the unlink() is ignored). */ if(bad_error != 0) return; /* * Avoid doing the unlink() on special files, just unlink regular files * that exist. */ if(stat(out_file_name, &stat_buf) != -1){ if(stat_buf.st_mode & S_IFREG) (void)unlink(out_file_name); } if((fd = open(out_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) as_fatal("can't create output file: %s", out_file_name); if(write(fd, output_addr, output_size) != (int)output_size) as_fatal("can't write output file"); if(close(fd) == -1) as_fatal("can't close output file"); }