+// determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
+void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* path, bool inCache, bool* compressed,
+ unsigned int* segCount, unsigned int* libCount, const LinkContext& context,
+ const linkedit_data_command** codeSigCmd,
+ const encryption_info_command** encryptCmd)
+{
+ *compressed = false;
+ *segCount = 0;
+ *libCount = 0;
+ *codeSigCmd = NULL;
+ *encryptCmd = NULL;
+
+ const uint32_t cmd_count = mh->ncmds;
+ const uint32_t sizeofcmds = mh->sizeofcmds;
+ if ( sizeofcmds > (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE-sizeof(macho_header)) )
+ dyld::throwf("malformed mach-o: load commands size (%u) > %u", sizeofcmds, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE);
+ if ( cmd_count > (sizeofcmds/sizeof(load_command)) )
+ dyld::throwf("malformed mach-o: ncmds (%u) too large to fit in sizeofcmds (%u)", cmd_count, sizeofcmds);
+ const struct load_command* const startCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
+ const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + sizeofcmds);
+ const struct load_command* cmd = startCmds;
+ bool foundLoadCommandSegment = false;
+ const macho_segment_command* linkeditSegCmd = NULL;
+ const macho_segment_command* startOfFileSegCmd = NULL;
+ const dyld_info_command* dyldInfoCmd = NULL;
+ const symtab_command* symTabCmd = NULL;
+ const dysymtab_command* dynSymbTabCmd = NULL;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ uint32_t cmdLength = cmd->cmdsize;
+ const macho_segment_command* segCmd;
+ const dylib_command* dylibCmd;
+ if ( cmdLength < 8 ) {
+ dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s",
+ i, cmdLength, path);
+ }
+ const struct load_command* const nextCmd = (const struct load_command*)(((char*)cmd)+cmdLength);
+ if ( (nextCmd > endCmds) || (nextCmd < cmd) ) {
+ dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
+ i, cmdLength, mh->sizeofcmds, path);
+ }
+ switch (cmd->cmd) {
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ if ( cmd->cmdsize != sizeof(dyld_info_command) )
+ throw "malformed mach-o image: LC_DYLD_INFO size wrong";
+ dyldInfoCmd = (struct dyld_info_command*)cmd;
+ *compressed = true;
+ break;
+ case LC_SEGMENT_COMMAND:
+ segCmd = (struct macho_segment_command*)cmd;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS)
+ if ( ((segCmd->filesize) > pageAlign(segCmd->vmsize)) && (segCmd->vmsize != 0) )
+#else
+ // <rdar://problem/19986776> dyld should support non-allocatable __LLVM segment
+ if ( (segCmd->filesize > segCmd->vmsize) && ((segCmd->vmsize != 0) || ((segCmd->flags & SG_NORELOC) == 0)) )
+#endif
+ dyld::throwf("malformed mach-o image: segment load command %s filesize (0x%0lX) is larger than vmsize (0x%0lX)", segCmd->segname, (long)segCmd->filesize , (long)segCmd->vmsize );
+ if ( cmd->cmdsize < sizeof(macho_segment_command) )
+ throw "malformed mach-o image: LC_SEGMENT size too small";
+ if ( cmd->cmdsize != (sizeof(macho_segment_command) + segCmd->nsects * sizeof(macho_section)) )
+ throw "malformed mach-o image: LC_SEGMENT size wrong for number of sections";
+ // ignore zero-sized segments
+ if ( segCmd->vmsize != 0 )
+ *segCount += 1;
+ if ( strcmp(segCmd->segname, "__LINKEDIT") == 0 ) {
+ #if TARGET_IPHONE_SIMULATOR
+ // Note: should check on all platforms that __LINKEDIT is read-only, but <rdar://problem/22637626&22525618>
+ if ( segCmd->initprot != VM_PROT_READ )
+ throw "malformed mach-o image: __LINKEDIT segment does not have read-only permissions";
+ #endif
+ if ( segCmd->fileoff == 0 )
+ throw "malformed mach-o image: __LINKEDIT has fileoff==0 which overlaps mach_header";
+ if ( linkeditSegCmd != NULL )
+ throw "malformed mach-o image: multiple __LINKEDIT segments";
+ linkeditSegCmd = segCmd;
+ }
+ else {
+ if ( segCmd->initprot & 0xFFFFFFF8 )
+ dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in initprot", segCmd->segname, segCmd->initprot);
+ if ( segCmd->maxprot & 0xFFFFFFF8 )
+ dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in maxprot", segCmd->segname, segCmd->maxprot);
+ if ( (segCmd->initprot != 0) && ((segCmd->initprot & VM_PROT_READ) == 0) )
+ dyld::throwf("malformed mach-o image: %s segment is not mapped readable", segCmd->segname);
+ }
+ if ( (segCmd->fileoff == 0) && (segCmd->filesize != 0) ) {
+ if ( (segCmd->initprot & VM_PROT_READ) == 0 )
+ dyld::throwf("malformed mach-o image: %s segment maps start of file but is not readable", segCmd->segname);
+ if ( (segCmd->initprot & VM_PROT_WRITE) == VM_PROT_WRITE ) {
+ if ( context.strictMachORequired )
+ dyld::throwf("malformed mach-o image: %s segment maps start of file but is writable", segCmd->segname);
+ }
+ if ( segCmd->filesize < (sizeof(macho_header) + mh->sizeofcmds) )
+ dyld::throwf("malformed mach-o image: %s segment does not map all of load commands", segCmd->segname);
+ if ( startOfFileSegCmd != NULL )
+ dyld::throwf("malformed mach-o image: multiple segments map start of file: %s %s", startOfFileSegCmd->segname, segCmd->segname);
+ startOfFileSegCmd = segCmd;
+ }
+ if ( context.strictMachORequired ) {
+ uintptr_t vmStart = segCmd->vmaddr;
+ uintptr_t vmSize = segCmd->vmsize;
+ uintptr_t vmEnd = vmStart + vmSize;
+ uintptr_t fileStart = segCmd->fileoff;
+ uintptr_t fileSize = segCmd->filesize;
+ if ( (intptr_t)(vmSize) < 0 )
+ dyld::throwf("malformed mach-o image: segment load command %s vmsize too large in %s", segCmd->segname, path);
+ if ( vmStart > vmEnd )
+ dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd->segname);
+ if ( vmSize != fileSize ) {
+ if ( segCmd->initprot == 0 ) {
+ // allow: fileSize == 0 && initprot == 0 e.g. __PAGEZERO
+ // allow: vmSize == 0 && initprot == 0 e.g. __LLVM
+ if ( (fileSize != 0) && (vmSize != 0) )
+ dyld::throwf("malformed mach-o image: unaccessable segment %s has non-zero filesize and vmsize", segCmd->segname);
+ }
+ else {
+ // allow: vmSize > fileSize && initprot != X e.g. __DATA
+ if ( vmSize < fileSize ) {
+ dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd->segname);
+ }
+ if ( segCmd->initprot & VM_PROT_EXECUTE ) {
+ dyld::throwf("malformed mach-o image: segment %s has vmsize != filesize and is executable", segCmd->segname);
+ }
+ }
+ }
+ if ( inCache ) {
+ if ( (fileSize != 0) && (segCmd->initprot == (VM_PROT_READ | VM_PROT_EXECUTE)) ) {
+ if ( foundLoadCommandSegment )
+ throw "load commands in multiple segments";
+ foundLoadCommandSegment = true;
+ }
+ }
+ else if ( (fileStart < mh->sizeofcmds) && (fileSize != 0) ) {
+ // <rdar://problem/7942521> all load commands must be in an executable segment
+ if ( (fileStart != 0) || (fileSize < (mh->sizeofcmds+sizeof(macho_header))) )
+ dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname);
+ if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) )
+ dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname);
+ if ( foundLoadCommandSegment )
+ throw "load commands in multiple segments";
+ foundLoadCommandSegment = true;
+ }
+
+ const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
+ const struct macho_section* const sectionsEnd = §ionsStart[segCmd->nsects];
+ for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ if (!inCache && sect->offset != 0 && ((sect->offset + sect->size) > (segCmd->fileoff + segCmd->filesize)))
+ dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect->segname, sect->sectname, path, segCmd->segname);
+ }
+ }
+ break;
+ case LC_SEGMENT_COMMAND_WRONG:
+ dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
+ break;
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_UPWARD_DYLIB:
+ *libCount += 1;
+ // fall thru
+ case LC_ID_DYLIB:
+ dylibCmd = (dylib_command*)cmd;
+ if ( dylibCmd->dylib.name.offset > cmdLength )
+ dyld::throwf("malformed mach-o image: dylib load command #%d has offset (%u) outside its size (%u)", i, dylibCmd->dylib.name.offset, cmdLength);
+ if ( (dylibCmd->dylib.name.offset + strlen((char*)dylibCmd + dylibCmd->dylib.name.offset) + 1) > cmdLength )
+ dyld::throwf("malformed mach-o image: dylib load command #%d string extends beyond end of load command", i);
+ break;
+ case LC_CODE_SIGNATURE:
+ if ( cmd->cmdsize != sizeof(linkedit_data_command) )
+ throw "malformed mach-o image: LC_CODE_SIGNATURE size wrong";
+ // <rdar://problem/22799652> only support one LC_CODE_SIGNATURE per image
+ if ( *codeSigCmd != NULL )
+ throw "malformed mach-o image: multiple LC_CODE_SIGNATURE load commands";
+ *codeSigCmd = (struct linkedit_data_command*)cmd;
+ break;
+ case LC_ENCRYPTION_INFO:
+ if ( cmd->cmdsize != sizeof(encryption_info_command) )
+ throw "malformed mach-o image: LC_ENCRYPTION_INFO size wrong";
+ // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO per image
+ if ( *encryptCmd != NULL )
+ throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO load commands";
+ *encryptCmd = (encryption_info_command*)cmd;
+ break;
+ case LC_ENCRYPTION_INFO_64:
+ if ( cmd->cmdsize != sizeof(encryption_info_command_64) )
+ throw "malformed mach-o image: LC_ENCRYPTION_INFO_64 size wrong";
+ // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO_64 per image
+ if ( *encryptCmd != NULL )
+ throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO_64 load commands";
+ *encryptCmd = (encryption_info_command*)cmd;
+ break;
+ case LC_SYMTAB:
+ if ( cmd->cmdsize != sizeof(symtab_command) )
+ throw "malformed mach-o image: LC_SYMTAB size wrong";
+ symTabCmd = (symtab_command*)cmd;
+ break;
+ case LC_DYSYMTAB:
+ if ( cmd->cmdsize != sizeof(dysymtab_command) )
+ throw "malformed mach-o image: LC_DYSYMTAB size wrong";
+ dynSymbTabCmd = (dysymtab_command*)cmd;
+ break;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ // <rdar://problem/26797345> error when loading iOS Simulator mach-o binary into macOS process
+ case LC_VERSION_MIN_WATCHOS:
+ case LC_VERSION_MIN_TVOS:
+ case LC_VERSION_MIN_IPHONEOS:
+ if ( !context.marzipan )
+ throw "mach-o, but built for simulator (not macOS)";
+ break;
+#endif
+ }
+ cmd = nextCmd;
+ }
+
+ if ( context.strictMachORequired && !foundLoadCommandSegment )
+ throw "load commands not in a segment";
+ if ( linkeditSegCmd == NULL )
+ throw "malformed mach-o image: missing __LINKEDIT segment";
+ if ( !inCache && (startOfFileSegCmd == NULL) )
+ throw "malformed mach-o image: missing __TEXT segment that maps start of file";
+ // <rdar://problem/13145644> verify every segment does not overlap another segment
+ if ( context.strictMachORequired ) {
+ uintptr_t lastFileStart = 0;
+ uintptr_t linkeditFileStart = 0;
+ const struct load_command* cmd1 = startCmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd1->cmd == LC_SEGMENT_COMMAND ) {
+ struct macho_segment_command* segCmd1 = (struct macho_segment_command*)cmd1;
+ uintptr_t vmStart1 = segCmd1->vmaddr;
+ uintptr_t vmEnd1 = segCmd1->vmaddr + segCmd1->vmsize;
+ uintptr_t fileStart1 = segCmd1->fileoff;
+ uintptr_t fileEnd1 = segCmd1->fileoff + segCmd1->filesize;
+
+ if (fileStart1 > lastFileStart)
+ lastFileStart = fileStart1;
+
+ if ( strcmp(&segCmd1->segname[0], "__LINKEDIT") == 0 ) {
+ linkeditFileStart = fileStart1;
+ }
+
+ const struct load_command* cmd2 = startCmds;
+ for (uint32_t j = 0; j < cmd_count; ++j) {
+ if ( cmd2 == cmd1 )
+ continue;
+ if ( cmd2->cmd == LC_SEGMENT_COMMAND ) {
+ struct macho_segment_command* segCmd2 = (struct macho_segment_command*)cmd2;
+ uintptr_t vmStart2 = segCmd2->vmaddr;
+ uintptr_t vmEnd2 = segCmd2->vmaddr + segCmd2->vmsize;
+ uintptr_t fileStart2 = segCmd2->fileoff;
+ uintptr_t fileEnd2 = segCmd2->fileoff + segCmd2->filesize;
+ if ( ((vmStart2 <= vmStart1) && (vmEnd2 > vmStart1) && (vmEnd1 > vmStart1))
+ || ((vmStart2 >= vmStart1) && (vmStart2 < vmEnd1) && (vmEnd2 > vmStart2)) )
+ dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1->segname, segCmd2->segname);
+ if ( ((fileStart2 <= fileStart1) && (fileEnd2 > fileStart1) && (fileEnd1 > fileStart1))
+ || ((fileStart2 >= fileStart1) && (fileStart2 < fileEnd1) && (fileEnd2 > fileStart2)) )
+ dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1->segname, segCmd2->segname);
+ }
+ cmd2 = (const struct load_command*)(((char*)cmd2)+cmd2->cmdsize);
+ }
+ }
+ cmd1 = (const struct load_command*)(((char*)cmd1)+cmd1->cmdsize);
+ }
+
+ if (lastFileStart != linkeditFileStart)
+ dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment");
+ }
+
+ // validate linkedit content
+ if ( (dyldInfoCmd == NULL) && (symTabCmd == NULL) )
+ throw "malformed mach-o image: missing LC_SYMTAB or LC_DYLD_INFO";
+ if ( dynSymbTabCmd == NULL )
+ throw "malformed mach-o image: missing LC_DYSYMTAB";
+
+ uint32_t linkeditFileOffsetStart = (uint32_t)linkeditSegCmd->fileoff;
+ uint32_t linkeditFileOffsetEnd = (uint32_t)linkeditSegCmd->fileoff + (uint32_t)linkeditSegCmd->filesize;
+
+ if ( !inCache && (dyldInfoCmd != NULL) && context.strictMachORequired ) {
+ // validate all LC_DYLD_INFO chunks fit in LINKEDIT and don't overlap
+ uint32_t offset = linkeditFileOffsetStart;
+ if ( dyldInfoCmd->rebase_size != 0 ) {
+ if ( dyldInfoCmd->rebase_size & 0x80000000 )
+ throw "malformed mach-o image: dyld rebase info size overflow";
+ if ( dyldInfoCmd->rebase_off < offset )
+ throw "malformed mach-o image: dyld rebase info underruns __LINKEDIT";
+ offset = dyldInfoCmd->rebase_off + dyldInfoCmd->rebase_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld rebase info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->bind_size != 0 ) {
+ if ( dyldInfoCmd->bind_size & 0x80000000 )
+ throw "malformed mach-o image: dyld bind info size overflow";
+ if ( dyldInfoCmd->bind_off < offset )
+ throw "malformed mach-o image: dyld bind info overlaps rebase info";
+ offset = dyldInfoCmd->bind_off + dyldInfoCmd->bind_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld bind info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->weak_bind_size != 0 ) {
+ if ( dyldInfoCmd->weak_bind_size & 0x80000000 )
+ throw "malformed mach-o image: dyld weak bind info size overflow";
+ if ( dyldInfoCmd->weak_bind_off < offset )
+ throw "malformed mach-o image: dyld weak bind info overlaps bind info";
+ offset = dyldInfoCmd->weak_bind_off + dyldInfoCmd->weak_bind_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld weak bind info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->lazy_bind_size != 0 ) {
+ if ( dyldInfoCmd->lazy_bind_size & 0x80000000 )
+ throw "malformed mach-o image: dyld lazy bind info size overflow";
+ if ( dyldInfoCmd->lazy_bind_off < offset )
+ throw "malformed mach-o image: dyld lazy bind info overlaps weak bind info";
+ offset = dyldInfoCmd->lazy_bind_off + dyldInfoCmd->lazy_bind_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld lazy bind info overruns __LINKEDIT";
+ }
+ if ( dyldInfoCmd->export_size != 0 ) {
+ if ( dyldInfoCmd->export_size & 0x80000000 )
+ throw "malformed mach-o image: dyld export info size overflow";
+ if ( dyldInfoCmd->export_off < offset )
+ throw "malformed mach-o image: dyld export info overlaps lazy bind info";
+ offset = dyldInfoCmd->export_off + dyldInfoCmd->export_size;
+ if ( offset > linkeditFileOffsetEnd )
+ throw "malformed mach-o image: dyld export info overruns __LINKEDIT";
+ }
+ }
+
+ if ( symTabCmd != NULL ) {
+ // validate symbol table fits in LINKEDIT
+ if ( (symTabCmd->nsyms > 0) && (symTabCmd->symoff < linkeditFileOffsetStart) )
+ throw "malformed mach-o image: symbol table underruns __LINKEDIT";
+ if ( symTabCmd->nsyms > 0x10000000 )
+ throw "malformed mach-o image: symbol table too large";
+ uint32_t symbolsSize = symTabCmd->nsyms * sizeof(macho_nlist);
+ if ( symbolsSize > linkeditSegCmd->filesize )
+ throw "malformed mach-o image: symbol table overruns __LINKEDIT";
+ if ( symTabCmd->symoff + symbolsSize < symTabCmd->symoff )
+ throw "malformed mach-o image: symbol table size wraps";
+ if ( symTabCmd->symoff + symbolsSize > symTabCmd->stroff )
+ throw "malformed mach-o image: symbol table overlaps symbol strings";
+ if ( symTabCmd->stroff + symTabCmd->strsize < symTabCmd->stroff )
+ throw "malformed mach-o image: symbol string size wraps";
+ if ( symTabCmd->stroff + symTabCmd->strsize > linkeditFileOffsetEnd ) {
+ // <rdar://problem/24220313> let old apps overflow as long as it stays within mapped page
+ if ( context.strictMachORequired || (symTabCmd->stroff + symTabCmd->strsize > ((linkeditFileOffsetEnd + 4095) & (-4096))) )
+ throw "malformed mach-o image: symbol strings overrun __LINKEDIT";
+ }
+ // validate indirect symbol table
+ if ( dynSymbTabCmd->nindirectsyms != 0 ) {
+ if ( dynSymbTabCmd->indirectsymoff < linkeditFileOffsetStart )
+ throw "malformed mach-o image: indirect symbol table underruns __LINKEDIT";
+ if ( dynSymbTabCmd->nindirectsyms > 0x10000000 )
+ throw "malformed mach-o image: indirect symbol table too large";
+ uint32_t indirectTableSize = dynSymbTabCmd->nindirectsyms * sizeof(uint32_t);
+ if ( indirectTableSize > linkeditSegCmd->filesize )
+ throw "malformed mach-o image: indirect symbol table overruns __LINKEDIT";
+ if ( dynSymbTabCmd->indirectsymoff + indirectTableSize < dynSymbTabCmd->indirectsymoff )
+ throw "malformed mach-o image: indirect symbol table size wraps";
+ if ( context.strictMachORequired && (dynSymbTabCmd->indirectsymoff + indirectTableSize > symTabCmd->stroff) )
+ throw "malformed mach-o image: indirect symbol table overruns string pool";
+ }
+ if ( (dynSymbTabCmd->nlocalsym > symTabCmd->nsyms) || (dynSymbTabCmd->ilocalsym > symTabCmd->nsyms) )
+ throw "malformed mach-o image: indirect symbol table local symbol count exceeds total symbols";
+ if ( dynSymbTabCmd->ilocalsym + dynSymbTabCmd->nlocalsym < dynSymbTabCmd->ilocalsym )
+ throw "malformed mach-o image: indirect symbol table local symbol count wraps";
+ if ( (dynSymbTabCmd->nextdefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iextdefsym > symTabCmd->nsyms) )
+ throw "malformed mach-o image: indirect symbol table extern symbol count exceeds total symbols";
+ if ( dynSymbTabCmd->iextdefsym + dynSymbTabCmd->nextdefsym < dynSymbTabCmd->iextdefsym )
+ throw "malformed mach-o image: indirect symbol table extern symbol count wraps";
+ if ( (dynSymbTabCmd->nundefsym > symTabCmd->nsyms) || (dynSymbTabCmd->iundefsym > symTabCmd->nsyms) )
+ throw "malformed mach-o image: indirect symbol table undefined symbol count exceeds total symbols";
+ if ( dynSymbTabCmd->iundefsym + dynSymbTabCmd->nundefsym < dynSymbTabCmd->iundefsym )
+ throw "malformed mach-o image: indirect symbol table undefined symbol count wraps";
+ }
+
+
+ // fSegmentsArrayCount is only 8-bits
+ if ( *segCount > 255 )
+ dyld::throwf("malformed mach-o image: more than 255 segments in %s", path);
+
+ // fSegmentsArrayCount is only 8-bits
+ if ( *libCount > 4095 )
+ dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path);
+
+ if ( needsAddedLibSystemDepency(*libCount, mh) )
+ *libCount = 1;
+}
+
+
+
+// create image for main executable
+ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context)
+{
+ //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
+ // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
+ bool compressed;
+ unsigned int segCount;
+ unsigned int libCount;
+ const linkedit_data_command* codeSigCmd;
+ const encryption_info_command* encryptCmd;
+ sniffLoadCommands(mh, path, false, &compressed, &segCount, &libCount, context, &codeSigCmd, &encryptCmd);
+ // instantiate concrete class based on content of load commands
+ if ( compressed )
+ return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
+ else
+#if SUPPORT_CLASSIC_MACHO
+ return ImageLoaderMachOClassic::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
+#else
+ throw "missing LC_DYLD_INFO load command";