void MachObject::classicBindExterns() { const uintptr_t relocBase = getClassicRelocBase(); const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]); const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel]; for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { if (reloc->r_length == RELOC_SIZE) { if (reloc->r_type == POINTER_RELOC) { const struct nlist* undefinedSymbol = &fSymtab[reloc->r_symbolnum]; uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase)); uintptr_t value = *location; if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) { value -= (undefinedSymbol->n_value+1); lnk::halt("weird arm thumb thing detected!"); } else { /* is undefined or non-weak symbol, so do subtraction to get addend */ value -= undefinedSymbol->n_value; } const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx]; uint8_t symbolFlags = 0; /* currently unused */ uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc); //lnk::log("classicBindExtern: %s, ord: %d:(%s)", symbolName, ord, fDependencies[ord-1]->getShortName()); /* bind */ bind((uintptr_t)location, BIND_TYPE_POINTER, symbolName, symbolFlags, value, ord, "extern"); } else { lnk::halt("unknown reloc type!"); } } else { lnk::halt("bad reloc size!"); } } }
MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid) : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0), fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false), fHasDyldInfo(false), fDyldInfoExports(NULL) { fDylibID.name = NULL; fDylibID.currentVersion = 0; fDylibID.compatibilityVersion = 0; bzero(fUUID, sizeof(fUUID)); const macho_header<P>* mh = (const macho_header<P>*)machHeader; if ( mh->cputype() != arch() ) throw "Layout object is wrong architecture"; switch ( mh->filetype() ) { case MH_DYLIB: fIsDylib = true; break; case MH_BUNDLE: case MH_EXECUTE: case MH_DYLIB_STUB: case MH_DYLINKER: break; default: throw "file is not a mach-o final linked image"; } fFlags = mh->flags(); fFileType = mh->filetype(); fArchPair.arch = mh->cputype(); fArchPair.subtype = mh->cpusubtype(); const macho_dyld_info_command<P>* dyldInfo = NULL; const macho_symtab_command<P>* symbolTableCmd = NULL; const macho_dysymtab_command<P>* dynamicSymbolTableCmd = NULL; const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>)); const uint32_t cmd_count = mh->ncmds(); const macho_load_command<P>* cmd = cmds; for (uint32_t i = 0; i < cmd_count; ++i) { switch ( cmd->cmd() ) { case LC_ID_DYLIB: { macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd; fDylibID.name = strdup(dylib->name()); fDylibID.currentVersion = dylib->current_version(); fDylibID.compatibilityVersion = dylib->compatibility_version(); fNameFileOffset = dylib->name() - (char*)machHeader; fShareableLocation = ( (strncmp(fDylibID.name, "/usr/lib/", 9) == 0) || (strncmp(fDylibID.name, "/System/Library/", 16) == 0) ); } break; case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: case LC_REEXPORT_DYLIB: case LC_LOAD_UPWARD_DYLIB: { macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd; Library lib; lib.name = strdup(dylib->name()); lib.currentVersion = dylib->current_version(); lib.compatibilityVersion = dylib->compatibility_version(); lib.weakImport = ( cmd->cmd() == LC_LOAD_WEAK_DYLIB ); fLibraries.push_back(lib); } break; case LC_SEGMENT_SPLIT_INFO: fHasSplitSegInfo = true; break; case macho_segment_command<P>::CMD: { macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd; fSegments.push_back(Segment(segCmd->vmaddr(), segCmd->vmsize(), segCmd->fileoff(), segCmd->filesize(), segCmd->initprot(), segCmd->segname())); } break; case LC_SYMTAB: symbolTableCmd = (macho_symtab_command<P>*)cmd; break; case LC_DYSYMTAB: dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)cmd; break; case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: fHasDyldInfo = true; dyldInfo = (struct macho_dyld_info_command<P>*)cmd; break; case LC_UUID: { const macho_uuid_command<P>* uc = (macho_uuid_command<P>*)cmd; memcpy(&fUUID, uc->uuid(), 16); } break; } cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize()); } fLowSegment = NULL; fLowExecutableSegment = NULL; fLowWritableSegment = NULL; fLowReadOnlySegment = NULL; fVMExecutableSize = 0; fVMWritablSize = 0; fVMReadOnlySize = 0; fVMSize = 0; const Segment* highSegment = NULL; for(std::vector<Segment>::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) { const Segment& seg = *it; if ( (fLowSegment == NULL) || (seg.address() < fLowSegment->address()) ) fLowSegment = &seg; if ( (highSegment == NULL) || (seg.address() > highSegment->address()) ) highSegment = &seg; if ( seg.executable() ) { if ( (fLowExecutableSegment == NULL) || (seg.address() < fLowExecutableSegment->address()) ) fLowExecutableSegment = &seg; fVMExecutableSize += seg.size(); } else if ( seg.writable()) { if ( (fLowWritableSegment == NULL) || (seg.address() < fLowWritableSegment->address()) ) fLowWritableSegment = &seg; fVMWritablSize += seg.size(); } else { if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) ) fLowReadOnlySegment = &seg; fVMReadOnlySize += seg.size(); } } if ( (highSegment != NULL) && (fLowSegment != NULL) ) fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096); // scan undefines looking, for magic ordinals if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) { const macho_nlist<P>* symbolTable = (macho_nlist<P>*)((uint8_t*)machHeader + symbolTableCmd->symoff()); const uint32_t startUndefs = dynamicSymbolTableCmd->iundefsym(); const uint32_t endUndefs = startUndefs + dynamicSymbolTableCmd->nundefsym(); for (uint32_t i=startUndefs; i < endUndefs; ++i) { uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[i].n_desc()); if ( ordinal == DYNAMIC_LOOKUP_ORDINAL ) fDynamicLookupLinkage = true; else if ( ordinal == EXECUTABLE_ORDINAL ) fMainExecutableLookupLinkage = true; } } if ( dyldInfo != NULL ) { if ( dyldInfo->export_off() != 0 ) { fDyldInfoExports = (uint8_t*)machHeader + dyldInfo->export_off(); } } }
void MachObject::classicBindIndirect() { const uint32_t cmd_count = fHeader->ncmds; const struct load_command* const cmds = (struct load_command*)(fHeader+1); const struct load_command* cmd = cmds; const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff]; bool bindNonLazys = true; bool bindLazys = true; for (uint32_t i = 0; i < cmd_count; ++i) { if (cmd->cmd == LC_SEGMENT_COMMAND) { const macho_segment_command* seg = (macho_segment_command*)cmd; const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command)); const macho_section* const sectionsEnd = §ionsStart[seg->nsects]; for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { bool isLazySymbol = false; const uint8_t type = sect->flags & SECTION_TYPE; uint32_t elementSize = sizeof(uintptr_t); uint32_t elementCount = sect->size / elementSize; if ( type == S_NON_LAZY_SYMBOL_POINTERS ) { if ( ! bindNonLazys ) continue; } else if ( type == S_LAZY_SYMBOL_POINTERS ) { // process each symbol pointer in this section isLazySymbol = true; if ( ! bindLazys ) continue; } else { continue; } const uint32_t indirectTableOffset = sect->reserved1; uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide); for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) { uint32_t symbolIndex = indirectTable[indirectTableOffset + j]; if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) { /* LOCA PEOPLE! */ //lnk::log("classicBindIndirect: [local] *%p = %p", ptrToBind, *ptrToBind); *((uintptr_t*)ptrToBind) += this->fSlide; } else if ( symbolIndex == INDIRECT_SYMBOL_ABS) { // do nothing since already has absolute address lnk::halt("ABS!"); } else { const struct nlist* sym = &fSymtab[symbolIndex]; if ( symbolIndex == 0 ) { lnk::halt("malformed classic image!"); } /* actually do stuff */ const char* symbolName = &fStrings[sym->n_un.n_strx]; uint8_t symbolFlags = 0; /* currently unused */ uint8_t ord = GET_LIBRARY_ORDINAL(sym->n_desc); //lnk::log("classicBindIndirect: %s, ord: %d:(%s)", symbolName, ord, fDependencies[ord-1]->getShortName()); bind((uintptr_t)ptrToBind, BIND_TYPE_POINTER, symbolName, symbolFlags, 0, ord, "indirect"); } } } } cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize); } }