X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/c7f24d34adf9643c842ab6c44f8e530661cffcc7..d696c285d331ab577dcabd00419d8c30336673da:/src/Readers/ObjectFileMachO.cpp diff --git a/src/Readers/ObjectFileMachO.cpp b/src/Readers/ObjectFileMachO.cpp deleted file mode 100644 index 154ff8b..0000000 --- a/src/Readers/ObjectFileMachO.cpp +++ /dev/null @@ -1,2376 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -namespace ObjectFileMachO { - -class Reference : public ObjectFile::Reference -{ -public: - Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget); - Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget); - Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget); - virtual ~Reference(); - - - virtual bool isTargetUnbound() const; - virtual bool isFromTargetUnbound() const; - virtual bool isWeakReference() const; - virtual bool requiresRuntimeFixUp(bool slideable) const; - virtual bool isLazyReference() const; - virtual Kind getKind() const; - virtual uint64_t getFixUpOffset() const; - virtual const char* getTargetName() const; - virtual ObjectFile::Atom& getTarget() const; - virtual uint64_t getTargetOffset() const; - virtual bool hasFromTarget() const; - virtual ObjectFile::Atom& getFromTarget() const; - virtual const char* getFromTargetName() const; - virtual void setTarget(ObjectFile::Atom&, uint64_t offset); - virtual void setFromTarget(ObjectFile::Atom&); - virtual void setFromTargetName(const char*); - virtual void setFromTargetOffset(uint64_t); - virtual const char* getDescription() const; - virtual uint64_t getFromTargetOffset() const; - - void setLazy(bool); - void setWeak(bool); -private: - ObjectFile::Atom* fTarget; - ObjectFile::Atom* fFromTarget; - const char* fTargetName; - const char* fFromTargetName; - macho_uintptr_t fTargetOffset; - macho_uintptr_t fFromTargetOffset; - macho_uintptr_t fFixUpOffsetInSrc; - Kind fKind; - bool fLazy; - bool fWeak; -}; - - - -class Reader : public ObjectFile::Reader -{ -public: - Reader(const char* path); - Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options); - virtual ~Reader(); - - virtual const char* getPath(); - virtual std::vector& getAtoms(); - virtual std::vector* getJustInTimeAtomsFor(const char* name); - virtual std::vector* getStabsDebugInfo(); // stabs info not associated with an atom - - -private: - friend class Atom; - void init(const macho_header* header, const char* path); - void buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set& offsets, std::set& dontUse); - void addRelocReference(const macho_section* sect, const macho_relocation_info* reloc); - Atom* findAtomCoveringOffset(uint32_t offset); - uint32_t findAtomIndex(const Atom& atom); - void addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr); - class Segment* makeSegmentFromSection(const macho_section*); - macho_uintptr_t commonsOffset(); - void insertOffsetIfText(std::set& offsets, uint32_t value); - void insertOffsetIfNotText(std::set& offsets, uint32_t value); - const macho_section* findSectionCoveringOffset(uint32_t offset); - void addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom); - void deadStub(Atom& target); - - const char* fPath; - const ObjectFile::ReaderOptions& fOptions; - const macho_header* fHeader; - const char* fStrings; - const macho_nlist* fSymbols; - uint32_t fSymbolCount; - const macho_segment_command* fSegment; - const uint32_t* fIndirectTable; - std::vector fAtoms; - std::vector fSegments; - std::set fDeadAtoms; - uint32_t fNonAtomStabsStartIndex; - uint32_t fNonAtomStabsCount; - std::vector fNonAtomExtras; -}; - -class Segment : public ObjectFile::Segment -{ -public: - virtual const char* getName() const; - virtual bool isContentReadable() const; - virtual bool isContentWritable() const; - virtual bool isContentExecutable() const; -protected: - Segment(const macho_section*); - friend class Reader; -private: - const macho_section* fSection; -}; - -class Atom : public ObjectFile::Atom -{ -public: - virtual ObjectFile::Reader* getFile() const; - virtual const char* getName() const; - virtual const char* getDisplayName() const; - virtual Scope getScope() const; - virtual bool isTentativeDefinition() const; - virtual bool isWeakDefinition() const; - virtual bool isCoalesableByName() const; - virtual bool isCoalesableByValue() const; - virtual bool isZeroFill() const; - virtual bool dontDeadStrip() const; - virtual bool dontStripName() const; // referenced dynamically - virtual bool isImportProxy() const; - virtual uint64_t getSize() const; - virtual std::vector& getReferences() const; - virtual bool mustRemainInSection() const; - virtual const char* getSectionName() const; - virtual Segment& getSegment() const; - virtual bool requiresFollowOnAtom() const; - virtual ObjectFile::Atom& getFollowOnAtom() const; - virtual std::vector* getStabsDebugInfo() const; - virtual uint8_t getAlignment() const; - virtual WeakImportSetting getImportWeakness() const { return ObjectFile::Atom::kWeakUnset; } - virtual void copyRawContent(uint8_t buffer[]) const; - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; - virtual void setScope(Scope); - virtual void setImportWeakness(bool weakImport) { } - - bool isLazyStub(); - -protected: - friend class Reader; - Atom(Reader&, const macho_nlist*); - Atom(Reader&, uint32_t offset); - virtual ~Atom(); - - const macho_section* findSectionFromOffset(uint32_t offset); - const macho_section* getCommonsSection(); - void setSize(macho_uintptr_t); - void setFollowOnAtom(Atom&); - static bool atomCompare(const Atom* lhs, const Atom* rhs); - Reference* addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget); - Reference* addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget); - Reference* addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget); - Reference* addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget); - - Reader& fOwner; - const macho_nlist* fSymbol; - macho_uintptr_t fOffset; - macho_uintptr_t fSize; - const macho_section* fSection; - Segment* fSegment; - const char* fSynthesizedName; - std::vector fReferences; - ObjectFile::Atom::Scope fScope; - uint32_t fStabsStartIndex; - uint32_t fStabsCount; - - static macho_section fgCommonsSection; // for us by tentative definitions -}; - - -Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options) -{ - return new Reader(mh, path, options); -} - - -Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options) - : fPath(NULL), fOptions(options), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL) -{ - init(header, path); -} - -Reader::Reader(const char* path) - : fPath(NULL), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), - fIndirectTable(NULL), fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0) -{ - struct stat stat_buf; - - int fd = ::open(path, O_RDONLY, 0); - ::fstat(fd, &stat_buf); - void* p = ::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0); - ::close(fd); - if ( ((macho_header*)p)->magic() == MH_MAGIC ) { - init((macho_header*)p, path); - return; - } - throw "add fat handling"; -} - - -Reader::~Reader() -{ -} - - -bool Atom::atomCompare(const Atom* lhs, const Atom* rhs) -{ - return lhs->fOffset < rhs->fOffset; -} - - - -void Reader::init(const macho_header* header, const char* path) -{ - // sanity check -#if defined(ARCH_PPC) - if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_POWERPC) ) - throw "not a valid ppc mach-o file"; -#elif defined(ARCH_I386) - if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_I386) ) - throw "not a valid i386 mach-o file"; -#elif defined(ARCH_PPC64) - if ( (header->magic() != MH_MAGIC_64) || (header->cputype() != CPU_TYPE_POWERPC64) ) - throw "not a valid ppc64 mach-o file"; -#endif - - // cache intersting pointers - fPath = strdup(path); - fHeader = header; - const uint32_t cmd_count = header->ncmds(); - const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size); - const macho_load_command* cmd = cmds; - for (uint32_t i = 0; i < cmd_count; ++i) { - switch (cmd->cmd()) { - case LC_SYMTAB: - { - const macho_symtab_command* symtab = (macho_symtab_command*)cmd; - fSymbolCount = symtab->nsyms(); - fSymbols = (const macho_nlist*)((char*)header + symtab->symoff()); - fStrings = (char*)header + symtab->stroff(); - } - break; - case LC_DYSYMTAB: - { - const macho_dysymtab_command* dsymtab = (struct macho_dysymtab_command*)cmd; - fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff()); - } - break; - default: - if ( cmd->cmd() == macho_segment_command::command ) { - fSegment= (macho_segment_command*)cmd; - } - break; - } - cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize()); - } - - // add all atoms that have entries in symbol table - std::set symbolAtomOffsets; - for (uint32_t i=0; i < fSymbolCount; ++i) { - const macho_nlist& sym = fSymbols[i]; - if ( (sym.n_type() & N_STAB) == 0 ) { - uint8_t type = (sym.n_type() & N_TYPE); - if ( (type == N_SECT) || ((type == N_UNDF) && (sym.n_value() != 0)) ) { - // real definition or "tentative definition" - Atom* newAtom = new Atom(*this, &sym); - fAtoms.push_back(newAtom); - symbolAtomOffsets.insert(newAtom->fOffset); - } - } - } - - // add all points referenced in relocations - const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command)); - const macho_section* const sectionsEnd = §ionsStart[fSegment->nsects()]; - std::set cleavePoints; - std::set dontCleavePoints; - for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { - const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff()); - const uint32_t relocCount = sect->nreloc(); - for (uint32_t r = 0; r < relocCount; ++r) { - buildOffsetsSet(&relocs[r], sect, cleavePoints, dontCleavePoints); - } - } - // add all stub functions and (non)lazy pointers - std::set deadStubOffsets; - for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { - uint8_t type (sect->flags() & SECTION_TYPE); - switch ( type ) { - case S_SYMBOL_STUBS: - { - const uint32_t stubSize = sect->reserved2(); - // TVector glue sections are marked as S_SYMBOL_STUBS but are only 8 bytes - if ( stubSize > 8 ) { - for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stubSize) { - uint32_t stubAddr = sect->addr() + sectOffset; - if ( cleavePoints.count(stubAddr) == 0 ) { - cleavePoints.insert(stubAddr); - deadStubOffsets.insert(stubAddr); - } - } - } - } - break; - case S_NON_LAZY_SYMBOL_POINTERS: - case S_LAZY_SYMBOL_POINTERS: - for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += sizeof(macho_uintptr_t)) { - uint32_t pointerAddr = sect->addr() + sectOffset; - cleavePoints.insert(pointerAddr); - } - break; - } - // also make sure each section break is a cleave point - if ( sect->size() != 0 ) - cleavePoints.insert(sect->addr()); - } - - for (std::set::iterator it=cleavePoints.begin(); it != cleavePoints.end(); it++) { - uint32_t cleavePoint = *it; - //printf("cleave offset 0x%08X, don't cleave=%d, isSymbol=%d\n", cleavePoint, dontCleavePoints.count(cleavePoint), symbolAtomOffsets.count(cleavePoint)); - // only create an atom if it is not a don't-cleave point and there is not already an atom at this offset - if ( (dontCleavePoints.count(cleavePoint) == 0) && (symbolAtomOffsets.count(cleavePoint) == 0) ) - fAtoms.push_back(new Atom(*this, cleavePoint)); - } - - const uint32_t atomCount = fAtoms.size(); - if ( atomCount > 0 ) { - // sort the atoms so the occur in source file order - std::sort(fAtoms.begin(), fAtoms.end(), Atom::atomCompare); - - // tell each atom its size and follow on - const bool dontDeadStrip = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0); - Atom* lastAtom = fAtoms[0]; - for (uint32_t i=1; i < atomCount; ++i) { - Atom* thisAtom = fAtoms[i]; - if ( lastAtom->getSize() == 0 ) { - if ( lastAtom->fSection == thisAtom->fSection ) - lastAtom->setSize(thisAtom->fOffset - lastAtom->fOffset); - else - lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset); - } - if ( dontDeadStrip ) - lastAtom->setFollowOnAtom(*thisAtom); - lastAtom = thisAtom; - } - lastAtom = fAtoms[atomCount-1]; - if ( lastAtom->getSize() == 0 ) - lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset); - - // add relocation based references - for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { - const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff()); - const uint32_t relocCount = sect->nreloc(); - for (uint32_t r = 0; r < relocCount; ++r) { - addRelocReference(sect, &relocs[r]); - } - } - - // add dead stubs to list to delete - for (std::set::iterator it=deadStubOffsets.begin(); it != deadStubOffsets.end(); it++) { - Atom* deadStub = findAtomCoveringOffset(*it); - this->deadStub(*deadStub); - } - - // remove dead stubs and lazy pointers - for (std::set::iterator deadIt=fDeadAtoms.begin(); deadIt != fDeadAtoms.end(); deadIt++) { - for (std::vector::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) { - if ( *deadIt == *it ) { - fAtoms.erase(it); - break; - } - } - } - - } - - // process stabs debugging info - if ( ! fOptions.fStripDebugInfo ) { - // scan symbol table for stabs entries - fNonAtomStabsStartIndex = 0xFFFFFFFF; - fNonAtomStabsCount = 0; - uint32_t possibleStart = 0; - Atom* atom = NULL; - const uint32_t atomCount = fAtoms.size(); - enum { start, inBeginEnd, foundFirst, inFunction } state = start; - for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) { - const macho_nlist* sym = &fSymbols[symbolIndex]; - uint8_t type = sym->n_type(); - if ( (type & N_STAB) != 0 ) { - if ( fNonAtomStabsStartIndex == 0xFFFFFFFF ) - fNonAtomStabsStartIndex = symbolIndex; - switch (state) { - case start: - if ( (type == N_SLINE) || (type == N_SOL) ) { - possibleStart = symbolIndex; - state = foundFirst; - } - else if ( type == N_BNSYM ) { - macho_uintptr_t targetAddr = sym->n_value(); - atom = this->findAtomCoveringOffset(targetAddr); - if ( (atom != NULL) || (atom->fOffset == targetAddr) ) { - atom->fStabsStartIndex = symbolIndex; - if ( fNonAtomStabsCount == 0 ) - fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex; - } - else { - fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path); - atom = NULL; - } - state = inBeginEnd; - } - else if ( (type == N_STSYM) || (type == N_LCSYM) ) { - macho_uintptr_t targetAddr = sym->n_value(); - atom = this->findAtomCoveringOffset(targetAddr); - if ( (atom != NULL) || (atom->fOffset == targetAddr) ) { - atom->fStabsStartIndex = symbolIndex; - atom->fStabsCount = 1; - if ( fNonAtomStabsCount == 0 ) - fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex; - } - else { - fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path); - atom = NULL; - } - } - else if ( type == N_GSYM ) { - // n_value field is NOT atom address ;-( - // need to find atom by name match - const char* symString = &fStrings[sym->n_strx()]; - const char* colon = strchr(symString, ':'); - bool found = false; - if ( colon != NULL ) { - int nameLen = colon - symString; - for (uint32_t searchIndex = 0; searchIndex < atomCount; ++searchIndex) { - const char* atomName = fAtoms[searchIndex]->getName(); - if ( (atomName != NULL) && (strncmp(&atomName[1], symString, nameLen) == 0) ) { - atom = fAtoms[searchIndex]; - atom->fStabsStartIndex = symbolIndex; - atom->fStabsCount = 1; - if ( fNonAtomStabsCount == 0 ) - fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex; - found = true; - break; - } - } - } - if ( !found ) { - fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path); - atom = NULL; - } - } - else if ( type == N_LSYM ) { - if ( fNonAtomStabsCount != 0 ) { - // built with -gfull and some type definition not at start of source - fNonAtomExtras.push_back(symbolIndex); - } - } - break; - case inBeginEnd: - if ( type == N_ENSYM ) { - state = start; - if ( atom != NULL ) - atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1; - } - break; - case foundFirst: - if ( (type == N_FUN) && (sym->n_sect() != 0) ) { - state = inFunction; - macho_uintptr_t targetAddr = sym->n_value(); - atom = this->findAtomCoveringOffset(targetAddr); - if ( (atom == NULL) || (atom->fOffset != targetAddr) ) { - fprintf(stderr, "can't find atom for stabs FUN index: %d at 0x%08llX in %s\n", symbolIndex, (uint64_t)targetAddr, path); - atom = NULL; - } - else { - atom->fStabsStartIndex = possibleStart; - if ( fNonAtomStabsCount == 0 ) - fNonAtomStabsCount = possibleStart - fNonAtomStabsStartIndex; - } - } - else if ( (type == N_FUN) && (sym->n_sect() == 0) ) { - fprintf(stderr, "end stab FUN found without start FUN, index=%d in %s\n", symbolIndex, path); - state = start; - } - break; - case inFunction: - if ( (type == N_FUN) && (sym->n_sect() == 0) ) { - state = start; - if ( atom != NULL ) - atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1; - } - break; - } - } - } - - } -} - - -void Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc) -{ - uint32_t srcAddr; - uint32_t dstAddr; - Atom* src; - Atom* dst; -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - uint32_t instruction; -#endif - uint32_t* fixUpPtr; - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - const macho_relocation_info* nextReloc = &reloc[1]; -#endif - switch ( reloc->r_type() ) { -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - case PPC_RELOC_BR24: - { - if ( reloc->r_extern() ) { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int32_t displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - uint32_t offsetInTarget = sect->addr() + reloc->r_address() + displacement; - srcAddr = sect->addr() + reloc->r_address(); - src = findAtomCoveringOffset(srcAddr); - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - const char* targetName = &fStrings[targetSymbol->n_strx()]; - src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch24, targetName, offsetInTarget, 0); - } - else { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - if ( (instruction & 0x4C000000) == 0x48000000 ) { - int32_t displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - srcAddr = sect->addr() + reloc->r_address(); - dstAddr = srcAddr + displacement; - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, dstAddr - dst->fOffset); - } - } - } - break; - case PPC_RELOC_BR14: - { - if ( reloc->r_extern() ) { - srcAddr = sect->addr() + reloc->r_address(); - src = findAtomCoveringOffset(srcAddr); - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - const char* targetName = &fStrings[targetSymbol->n_strx()]; - src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch14, targetName, 0, 0); - } - else { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int32_t displacement = (instruction & 0x0000FFFC); - if ( (displacement & 0x00008000) != 0 ) - displacement |= 0xFFFF0000; - srcAddr = sect->addr() + reloc->r_address(); - dstAddr = srcAddr + displacement; - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch14, *dst, 0, dstAddr - dst->fOffset); - } - } - break; - case PPC_RELOC_PAIR: - // skip, processed by a previous look ahead - break; - case PPC_RELOC_LO16: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_LO16 missing following pair\n"); - break; - } - srcAddr = sect->addr() + reloc->r_address(); - if ( reloc->r_extern() ) { - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - const char* targetName = &fStrings[targetSymbol->n_strx()]; - src = findAtomCoveringOffset(srcAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF); - src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, targetName, dstAddr, 0); - } - else { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (instruction & 0xFFFF); - dstAddr = (nextReloc->r_address() << 16) + (int32_t)lowBits; - if ( (lowBits & 0x8000) != 0 ) - dstAddr += 0x10000; - addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow16, 0); - } - } - break; - case PPC_RELOC_LO14: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_LO14 missing following pair\n"); - break; - } - srcAddr = sect->addr() + reloc->r_address(); - if ( reloc->r_extern() ) { - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - const char* targetName = &fStrings[targetSymbol->n_strx()]; - src = findAtomCoveringOffset(srcAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC); - src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, targetName, dstAddr, 0); - } - else { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC); - addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow14, 0); - } - } - break; - case PPC_RELOC_HI16: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_HI16 missing following pair\n"); - break; - } - srcAddr = sect->addr() + reloc->r_address(); - if ( reloc->r_extern() ) { - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - const char* targetName = &fStrings[targetSymbol->n_strx()]; - src = findAtomCoveringOffset(srcAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF); - src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16, targetName, dstAddr, 0); - } - else { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF); - addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16, 0); - } - } - break; - case PPC_RELOC_HA16: - { - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_HA16 missing following pair\n"); - break; - } - srcAddr = sect->addr() + reloc->r_address(); - if ( reloc->r_extern() ) { - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - const char* targetName = &fStrings[targetSymbol->n_strx()]; - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF); - dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; - src = findAtomCoveringOffset(srcAddr); - src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, targetName, dstAddr, 0); - } - else { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF); - dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; - addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16AddLow, 0); - } - } - break; - case GENERIC_RELOC_VANILLA: - { - srcAddr = sect->addr() + reloc->r_address(); - Atom* srcAtom = findAtomCoveringOffset(srcAddr); - uint32_t offsetInSrcAtom = srcAddr - srcAtom->fOffset; - macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr)); - if ( reloc->r_extern() ) { - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - uint8_t type = targetSymbol->n_type() & N_TYPE; - if ( type == N_UNDF ) { - const char* targetName = &fStrings[targetSymbol->n_strx()]; - macho_uintptr_t addend = pointerValue; - // ppc lazy pointers have initial reference to dyld_stub_binding_helper - if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) { - std::vector& refs = srcAtom->getReferences(); - if ( refs.size() > 0 ) { - Reference* ref = (Reference*)refs[0]; - #if defined(ARCH_PPC64) - // hack to work around bad crt1.o in Mac OS X 10.4 - targetName = "dyld_stub_binding_helper"; - #endif - ref->setFromTargetName(targetName); - } - else { - fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size()); - } - } - #if defined(ARCH_PPC64) - // hack to work around bad crt1.o in Mac OS X 10.4 - else if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) { - // ignore extra relocation - } - #endif - else { - srcAtom->addByNameReference(offsetInSrcAtom, Reference::pointer, targetName, addend, 0); - } - } - else { - dstAddr = targetSymbol->n_value(); - Atom* dstAtom = findAtomCoveringOffset(dstAddr); - macho_uintptr_t addend = pointerValue; - // ppc lazy pointers have initial reference to dyld_stub_binding_helper - if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) { - std::vector& refs = srcAtom->getReferences(); - if ( refs.size() > 0 ) { - Reference* ref = (Reference*)refs[0]; - ref->setFromTarget(*dstAtom); - ref->setFromTargetOffset(dstAddr - dstAtom->fOffset); - } - else { - fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size()); - } - } - else { - srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, addend, 0); - } - } - } - else { - Atom* dstAtom = findAtomCoveringOffset(pointerValue); - // lazy pointers have references to dyld_stub_binding_helper which need to be ignored - if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) { - std::vector& refs = srcAtom->getReferences(); - if ( refs.size() > 0 ) { - Reference* ref = (Reference*)refs[0]; - ref->setFromTarget(*dstAtom); - ref->setFromTargetOffset(pointerValue - dstAtom->fOffset); - } - else { - fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size()); - } - } - else { - srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, pointerValue-dstAtom->fOffset, 0); - } - } - } - break; - case PPC_RELOC_JBSR: - // ignore for now - break; -#endif -#if defined(ARCH_I386) - case GENERIC_RELOC_VANILLA: - { - srcAddr = sect->addr() + reloc->r_address(); - src = findAtomCoveringOffset(srcAddr); - if ( reloc->r_length() != 2 ) - throw "bad vanilla relocation length"; - Reference::Kind kind; - macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr)); - if ( reloc->r_pcrel() ) { - kind = Reference::x86FixupBranch32; - pointerValue += srcAddr + sizeof(macho_uintptr_t); - } - else { - kind = Reference::pointer; - } - uint32_t offsetInSrcAtom = srcAddr - src->fOffset; - if ( reloc->r_extern() ) { - const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()]; - uint8_t type = targetSymbol->n_type() & N_TYPE; - if ( type == N_UNDF ) { - const char* targetName = &fStrings[targetSymbol->n_strx()]; - macho_uintptr_t addend = pointerValue; - src->addByNameReference(offsetInSrcAtom, kind, targetName, addend, 0); - } - else { - dstAddr = targetSymbol->n_value(); - dst = findAtomCoveringOffset(dstAddr); - macho_uintptr_t addend = pointerValue - dstAddr; - src->addReference(offsetInSrcAtom, kind, *dst, addend, 0); - } - } - else { - dst = findAtomCoveringOffset(pointerValue); - // lazy pointers have references to dyld_stub_binding_helper which need to be ignored - if ( (src->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) { - std::vector& refs = src->getReferences(); - if ( refs.size() == 1 ) { - Reference* ref = (Reference*)refs[0]; - ref->setFromTarget(*dst); - ref->setFromTargetOffset(pointerValue - dst->fOffset); - } - else { - fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", src->getDisplayName(), refs.size()); - } - } - else if ( ((uint8_t*)fixUpPtr)[-1] == 0xE8 ) // special case call instruction - this->addCallSiteReference(*src, offsetInSrcAtom, kind, *dst, 0, pointerValue - dst->fOffset); - else - src->addReference(offsetInSrcAtom, kind, *dst, 0, 0); - } - } - break; -#endif - - default: - printf("unknown relocation type %d\n", reloc->r_type()); - } - } - else { - const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc; - srcAddr = sect->addr() + sreloc->r_address(); - dstAddr = sreloc->r_value(); - fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address()); - const macho_scattered_relocation_info* nextSReloc = &sreloc[1]; - const macho_relocation_info* nextReloc = &reloc[1]; - // file format allows pair to be scattered or not - bool nextRelocIsPair = false; - uint32_t nextRelocAddress = 0; - uint32_t nextRelocValue = 0; - if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) { - if ( nextReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextReloc->r_address(); - } - } - else { - if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextSReloc->r_address(); - nextRelocValue = nextSReloc->r_value(); - } - } - switch (sreloc->r_type()) { - case GENERIC_RELOC_VANILLA: - { - macho_uintptr_t betterDstAddr = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr)); - //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr); - // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) - Atom* src = findAtomCoveringOffset(srcAddr); - Atom* dst = findAtomCoveringOffset(dstAddr); - src->addReference(srcAddr - src->fOffset, Reference::pointer, *dst, betterDstAddr - dst->fOffset, 0); - } - break; -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - case PPC_RELOC_BR24: - { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - if ( (instruction & 0x4C000000) == 0x48000000 ) { - int32_t displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - srcAddr = sect->addr() + sreloc->r_address(); - dstAddr = sreloc->r_value(); - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, srcAddr + displacement - sreloc->r_value()); - } - } - break; - case PPC_RELOC_LO16_SECTDIFF: - { - if ( ! nextRelocIsPair) { - printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n"); - break; - } - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (instruction & 0xFFFF); - int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits; - if ( (lowBits & 0x8000) != 0 ) - displacement += 0x10000; - uint32_t picBaseOffset = nextRelocValue - src->fOffset; - int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset; - src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow16, *dst, dstOffset, picBaseOffset); - } - break; - case PPC_RELOC_LO14_SECTDIFF: - { - if ( ! nextRelocIsPair) { - printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n"); - break; - } - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (instruction & 0xFFFC); - int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits; - if ( (lowBits & 0x8000) != 0 ) - displacement += 0x10000; - uint32_t picBaseOffset = nextRelocValue - src->fOffset; - int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset; - src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow14, *dst, dstOffset, picBaseOffset); - } - break; - case PPC_RELOC_HA16_SECTDIFF: - { - if ( ! nextRelocIsPair) { - printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n"); - break; - } - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (nextRelocAddress & 0x0000FFFF); - int32_t displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; - uint32_t picBaseOffset = nextRelocValue - src->fOffset; - int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset; - src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseHigh16, *dst, dstOffset, picBaseOffset); - } - break; - case PPC_RELOC_LO14: - { - if ( ! nextRelocIsPair) { - printf("PPC_RELOC_LO14 missing following PAIR\n"); - break; - } - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (instruction & 0xFFFC); - uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits; - if ( (lowBits & 0x8000) != 0 ) - betterDstAddr += 0x10000; - src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, *dst, betterDstAddr - dst->fOffset, 0); - } - break; - case PPC_RELOC_LO16: - { - if ( ! nextRelocIsPair) { - printf("PPC_RELOC_LO16 missing following PAIR\n"); - break; - } - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (instruction & 0xFFFF); - uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits; - if ( (lowBits & 0x8000) != 0 ) - betterDstAddr += 0x10000; - src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, *dst, betterDstAddr - dst->fOffset, 0); - } - break; - case PPC_RELOC_HA16: - { - if ( ! nextRelocIsPair) { - printf("PPC_RELOC_HA16 missing following PAIR\n"); - break; - } - src = findAtomCoveringOffset(srcAddr); - dst = findAtomCoveringOffset(dstAddr); - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (nextRelocAddress & 0xFFFF); - uint32_t betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits; - src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, *dst, betterDstAddr - dst->fOffset, 0); - } - break; - case PPC_RELOC_SECTDIFF: - case PPC_RELOC_LOCAL_SECTDIFF: - { - const macho_scattered_relocation_info* nextReloc = &sreloc[1]; - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_SECTDIFF missing following pair\n"); - break; - } - srcAddr = sect->addr() + sreloc->r_address(); - uint32_t toAddr = sreloc->r_value(); - uint32_t fromAddr = nextReloc->r_value(); - src = findAtomCoveringOffset(srcAddr); - Atom* to = findAtomCoveringOffset(toAddr); - Atom* from = findAtomCoveringOffset(fromAddr); - //macho_intptr_t pointerValue = *(macho_intptr_t*)fixUpPtr; - //uint64_t toOffset = to->fOffset; - //uint64_t fromOffset = from->fOffset; - //int64_t pointerValue64 = pointerValue; - //uint64_t addend = pointerValue64 - (toOffset - fromOffset); - Reference::Kind kind = Reference::pointer32Difference; - if ( sreloc->r_length() == 3 ) - kind = Reference::pointer64Difference; - src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset); - } - break; - case PPC_RELOC_PAIR: - break; - case PPC_RELOC_HI16_SECTDIFF: - printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n"); - break; -#endif -#if defined(ARCH_I386) - case GENERIC_RELOC_SECTDIFF: - case GENERIC_RELOC_LOCAL_SECTDIFF: - { - if ( nextSReloc->r_type() != GENERIC_RELOC_PAIR ) { - printf("GENERIC_RELOC_SECTDIFF missing following pair\n"); - break; - } - srcAddr = sect->addr() + sreloc->r_address(); - uint32_t toAddr = sreloc->r_value(); - uint32_t fromAddr = nextSReloc->r_value(); - src = findAtomCoveringOffset(srcAddr); - Atom* to = findAtomCoveringOffset(toAddr); - Atom* from = findAtomCoveringOffset(fromAddr); - Reference::Kind kind = Reference::pointer32Difference; - if ( sreloc->r_length() != 2 ) - throw "bad length for GENERIC_RELOC_SECTDIFF"; - src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset); - } - break; - case GENERIC_RELOC_PAIR: - // do nothing, already used via a look ahead - break; -#endif - default: - printf("unknown scattered relocation type %d\n", sreloc->r_type()); - } - - } -} - - -void Reader::addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr) -{ - Atom* src = findAtomCoveringOffset(srcAddr); - Atom* dst = findAtomCoveringOffset(dstAddr); - src->addReference(srcAddr - src->fOffset, kind, *dst, dstAddr - dst->fOffset, picBaseAddr - src->fOffset); -} - -Atom* Reader::findAtomCoveringOffset(uint32_t offset) -{ -#if 1 - // binary search of sorted atoms - Atom** base = &fAtoms[0]; - for (uint32_t n = fAtoms.size(); n > 0; n /= 2) { - Atom** pivot = &base[n/2]; - Atom* pivotAtom = *pivot; - if ( pivotAtom->fOffset <= offset ) { - if ( offset < (pivotAtom->fOffset + pivotAtom->fSize) ) - return pivotAtom; - // key > pivot - // move base to symbol after pivot - base = &pivot[1]; - --n; - } - else { - // key < pivot - // keep same base - } - } - // possible that last atom is zero length - Atom* lastAtom = fAtoms.back(); - if ( (lastAtom->fOffset == offset) && (lastAtom->fSize == 0) ) - return lastAtom; -#else - const uint32_t atomCount = fAtoms.size(); - for (uint32_t i=0; i < atomCount; ++i) { - Atom* atom = fAtoms[i]; - if ( (atom->fOffset <= offset) && (offset < (atom->fOffset + atom->fSize)) ) - return atom; - } -#endif - throwf("address 0x%08X is not in any atom", offset); -} - -uint32_t Reader::findAtomIndex(const Atom& atom) -{ - const Atom* target = &atom; - const uint32_t atomCount = fAtoms.size(); - for (uint32_t i=0; i < atomCount; ++i) { - Atom* anAtom = fAtoms[i]; - if ( anAtom == target ) - return i; - } - return 0xffffffff; -} - -static void insertOffset(std::set& offsets, uint32_t value) -{ - //fprintf(stderr, "cleave point at 0x%08X\n", value); - offsets.insert(value); -} - -void Reader::insertOffsetIfNotText(std::set& offsets, uint32_t value) -{ - const macho_section* sect = findSectionCoveringOffset(value); - if ( (sect == NULL) || (strcmp(sect->segname(),"__TEXT") != 0) || (strncmp(sect->sectname(),"__text", 6) != 0) ) { - offsets.insert(value); - } -} - -void Reader::insertOffsetIfText(std::set& offsets, uint32_t value) -{ - const macho_section* sect = findSectionCoveringOffset(value); - if ( (sect != NULL) && (strcmp(sect->segname(),"__TEXT") == 0) && (strncmp(sect->sectname(),"__text", 6) == 0) ) { - //fprintf(stderr, "don't cleave point at 0x%08X\n", value); - offsets.insert(value); - } -} - -const macho_section* Reader::findSectionCoveringOffset(uint32_t offset) -{ - const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command)); - const macho_section* const sectionsEnd = §ionsStart[fSegment->nsects()]; - for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { - if ( (sect->addr() <= offset) && (offset < (sect->addr() + sect->size())) ) - return sect; - } - return NULL; -} - - -void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set& cleavePoints, std::set& dontCleavePoints) -{ -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - uint32_t targetAddr; -#endif - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - uint32_t* fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address()); -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - uint32_t instruction; -#endif - switch ( reloc->r_type() ) { -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - case PPC_RELOC_BR14: - // do nothing. local branch should not cleave - break; - case PPC_RELOC_BR24: - { - if ( ! reloc->r_extern() ) { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - if ( (instruction & 0x4C000000) == 0x48000000 ) { - int32_t displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - //cleavePoints.insert(reloc->r_address() + displacement); - insertOffset(cleavePoints, sect->addr() + reloc->r_address() + displacement); - } - } - } - break; - case PPC_RELOC_PAIR: - // skip, processed by a look ahead - break; - case PPC_RELOC_LO16: - { - const macho_relocation_info* nextReloc = &reloc[1]; - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_LO16 missing following pair\n"); - break; - } - if ( ! reloc->r_extern() ) { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF); - //cleavePoints.insert(targetAddr); - insertOffset(cleavePoints, (targetAddr)); - } - } - break; - case PPC_RELOC_LO14: - { - const macho_relocation_info* nextReloc = &reloc[1]; - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_LO14 missing following pair\n"); - break; - } - if ( ! reloc->r_extern() ) { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC); - //cleavePoints.insert(targetAddr); - insertOffset(cleavePoints, (targetAddr)); - } - } - break; - case PPC_RELOC_HI16: - { - const macho_relocation_info* nextReloc = &reloc[1]; - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_HI16 missing following pair\n"); - break; - } - if ( ! reloc->r_extern() ) { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - targetAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF); - //cleavePoints.insert(targetAddr); - insertOffset(cleavePoints, targetAddr); - } - } - break; - case PPC_RELOC_HA16: - { - const macho_relocation_info* nextReloc = &reloc[1]; - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_HA16 missing following pair\n"); - break; - } - if ( ! reloc->r_extern() ) { - instruction = OSSwapBigToHostInt32(*fixUpPtr); - int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF); - targetAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits; - //cleavePoints.insert(targetAddr); - insertOffset(cleavePoints, targetAddr); - } - } - break; - case PPC_RELOC_JBSR: - // ignore for now - break; -#endif - case GENERIC_RELOC_VANILLA: - { -#if defined(ARCH_PPC64) - if ( reloc->r_length() != 3 ) - throw "vanilla pointer relocation found that is not 8-bytes"; -#elif defined(ARCH_PPC) || defined(ARCH_I386) - if ( reloc->r_length() != 2 ) - throw "vanilla pointer relocation found that is not 4-bytes"; -#endif - //fprintf(stderr, "addr=0x%08X, pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_address(), reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type()); - if ( !reloc->r_extern() ) { - macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr)); -#if defined(ARCH_I386) - // i386 stubs have internal relocs that should not cause a cleave - if ( (sect->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) - break; -#endif - if ( reloc->r_pcrel() ) - pointerValue += reloc->r_address() + sect->addr() + sizeof(macho_uintptr_t); - // a pointer into code does not cleave the code (gcc always pointers to labels) - insertOffsetIfNotText(cleavePoints, pointerValue); - } - } - break; - default: - printf("unknown relocation type %d\n", reloc->r_type()); - } - } - else { - const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc; - switch (sreloc->r_type()) { - case GENERIC_RELOC_VANILLA: - insertOffset(cleavePoints, sreloc->r_value()); - break; -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - case PPC_RELOC_BR24: - insertOffset(cleavePoints, sreloc->r_value()); - break; - case PPC_RELOC_HA16: - case PPC_RELOC_HI16: - case PPC_RELOC_LO16: - case PPC_RELOC_LO14: - case PPC_RELOC_LO16_SECTDIFF: - case PPC_RELOC_LO14_SECTDIFF: - case PPC_RELOC_HA16_SECTDIFF: - case PPC_RELOC_HI16_SECTDIFF: - //cleavePoints.insert(sreloc->r_value()); - insertOffset(cleavePoints, sreloc->r_value()); - insertOffsetIfText(dontCleavePoints, sreloc->r_value()); - break; - case PPC_RELOC_SECTDIFF: - case PPC_RELOC_LOCAL_SECTDIFF: - // these do not cleave up a .o file - // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave - { - const macho_scattered_relocation_info* nextReloc = &sreloc[1]; - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) { - printf("PPC_RELOC_SECTDIFF missing following pair\n"); - break; - } - insertOffsetIfText(dontCleavePoints, sreloc->r_value()); - insertOffsetIfText(dontCleavePoints, nextReloc->r_value()); - } - break; - case PPC_RELOC_PAIR: - // do nothing, already used via a look ahead - break; -#endif -#if defined(ARCH_I386) - case GENERIC_RELOC_SECTDIFF: - case GENERIC_RELOC_LOCAL_SECTDIFF: - // these do not cleave up a .o file - // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave - { - const macho_scattered_relocation_info* nextReloc = &sreloc[1]; - if ( nextReloc->r_type() != GENERIC_RELOC_PAIR ) { - printf("GENERIC_RELOC_SECTDIFF missing following pair\n"); - break; - } - insertOffsetIfText(dontCleavePoints, sreloc->r_value()); - insertOffsetIfText(dontCleavePoints, nextReloc->r_value()); - } - break; - case GENERIC_RELOC_PAIR: - // do nothing, already used via a look ahead - break; -#endif - default: - printf("unknown relocation type %d\n", sreloc->r_type()); - } - - } -} - - -Segment* Reader::makeSegmentFromSection(const macho_section* sect) -{ - // make segment object if one does not already exist - const uint32_t segmentCount = fSegments.size(); - for (uint32_t i=0; i < segmentCount; ++i) { - Segment* seg = fSegments[i]; - if ( strcmp(sect->segname(), seg->getName()) == 0 ) - return seg; - } - Segment* seg = new Segment(sect); - fSegments.push_back(seg); - return seg; -} - -macho_uintptr_t Reader::commonsOffset() -{ - return fSegment->vmsize(); -} - -const char* Reader::getPath() -{ - return fPath; -} - -std::vector& Reader::getAtoms() -{ - return (std::vector&)(fAtoms); -} - -std::vector* Reader::getJustInTimeAtomsFor(const char* name) -{ - // object files have no just-in-time atoms - return NULL; -} - - -std::vector* Reader::getStabsDebugInfo() -{ - if ( fNonAtomStabsCount == 0 ) - return NULL; - - std::vector* stabs = new std::vector(); - stabs->reserve(fNonAtomStabsCount); - - for (uint32_t i=0; i < fNonAtomStabsCount; ++i) { - const macho_nlist* sym = &fSymbols[fNonAtomStabsStartIndex+i]; - if ( (sym->n_type() & N_STAB) != 0 ) { - ObjectFile::StabsInfo stab; - stab.atomOffset = sym->n_value(); - stab.string = &fStrings[sym->n_strx()]; - stab.type = sym->n_type(); - stab.other = sym->n_sect(); - stab.desc = sym->n_desc(); - // for N_SO n_value is offset of first atom, but our gdb ignores this, so we omit that calculation - if ( stab.type == N_SO ) - stab.atomOffset = 0; - stabs->push_back(stab); - } - } - - // add any extra N_LSYM's not at start of symbol table - for (std::vector::iterator it=fNonAtomExtras.begin(); it != fNonAtomExtras.end(); ++it) { - const macho_nlist* sym = &fSymbols[*it]; - ObjectFile::StabsInfo stab; - stab.atomOffset = sym->n_value(); - stab.string = &fStrings[sym->n_strx()]; - stab.type = sym->n_type(); - stab.other = sym->n_sect(); - stab.desc = sym->n_desc(); - stabs->push_back(stab); - } - - return stabs; -} - -void Reader::deadStub(Atom& target) -{ - // remove stub - fDeadAtoms.insert(&target); - - // remove lazy pointer - const int stubNameLen = strlen(target.fSynthesizedName); - char lazyName[stubNameLen+8]; - strcpy(lazyName, target.fSynthesizedName); - strcpy(&lazyName[stubNameLen-5], "$lazy_ptr"); - const uint32_t atomCount = fAtoms.size(); - for (uint32_t i=1; i < atomCount; ++i) { - Atom* atom = fAtoms[i]; - if ( (atom->fSynthesizedName != NULL) && (strcmp(atom->fSynthesizedName, lazyName) == 0) ) { - fDeadAtoms.insert(atom); - break; - } - } -} - - -void Reader::addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom) -{ - // the compiler some times produces stub to static functions and then calls the stubs - // we need to skip the stub if a static function exists with the same name and remove the stub - if ( target.isLazyStub() ) { - const macho_section* section = target.fSection; - uint32_t index = (target.fOffset - section->addr()) / section->reserved2(); - uint32_t indirectTableIndex = section->reserved1() + index; - uint32_t symbolIndex = ENDIAN_READ32(fIndirectTable[indirectTableIndex]); - if ( (symbolIndex & INDIRECT_SYMBOL_LOCAL) == 0 ) { - const macho_nlist* sym = &fSymbols[symbolIndex]; - if ( (sym->n_value() != 0) && ((sym->n_type() & N_EXT) == 0) ) { - Atom* betterTarget = this->findAtomCoveringOffset(sym->n_value()); - if ( (betterTarget != NULL) && (betterTarget->getScope() == ObjectFile::Atom::scopeTranslationUnit) ) { - // use direct reference to static function - src.addDirectReference(offsetInSrcAtom, kind, *betterTarget, offsetInTargetAtom, picBaseOffset); - - // remove stub and lazy pointer - this->deadStub(target); - return; - } - } - } - } - - // fall through to general case - src.addReference(offsetInSrcAtom, kind, target, offsetInTargetAtom, picBaseOffset); -} - - -Atom::Atom(Reader& owner, const macho_nlist* symbol) - : fOwner(owner), fSymbol(symbol), fOffset(0), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL), - fStabsStartIndex(0), fStabsCount(0) -{ - uint8_t type = symbol->n_type(); - if ( (type & N_EXT) == 0 ) - fScope = ObjectFile::Atom::scopeTranslationUnit; - else if ( (type & N_PEXT) != 0 ) - fScope = ObjectFile::Atom::scopeLinkageUnit; - else - fScope = ObjectFile::Atom::scopeGlobal; - if ( (type & N_TYPE) == N_SECT ) { - // real definition - const macho_section* sections = (macho_section*)((char*)fOwner.fSegment + sizeof(macho_segment_command)); - fSection = §ions[fSymbol->n_sect()-1]; - fSegment = owner.makeSegmentFromSection(fSection); - fOffset = fSymbol->n_value(); - uint8_t type = fSection->flags() & SECTION_TYPE; - switch ( type ) { - case S_LAZY_SYMBOL_POINTERS: - case S_NON_LAZY_SYMBOL_POINTERS: - { - // get target name out of indirect symbol table - uint32_t index = (fOffset - fSection->addr()) / sizeof(macho_uintptr_t); - index += fSection->reserved1(); - uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]); - uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx(); - const char* name = &fOwner.fStrings[strOffset]; - Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0); - if ( type == S_LAZY_SYMBOL_POINTERS ) { - ref->setLazy(true); - } - } - break; - } - } - else if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) { - // tentative definition - fSize = symbol->n_value(); - fSection = getCommonsSection(); - fSegment = owner.makeSegmentFromSection(fSection); - fOffset = owner.commonsOffset(); - } - else { - printf("unknown symbol type: %d\n", type); - } -} - -Atom::Atom(Reader& owner, uint32_t offset) - : fOwner(owner), fSymbol(NULL), fOffset(offset), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL), - fStabsStartIndex(0), fStabsCount(0) -{ - fSection = findSectionFromOffset(offset); - fScope = ObjectFile::Atom::scopeLinkageUnit; - fSegment = owner.makeSegmentFromSection(fSection); - uint8_t type = fSection->flags() & SECTION_TYPE; - switch ( type ) { - case S_SYMBOL_STUBS: - { - uint32_t index = (offset - fSection->addr()) / fSection->reserved2(); - index += fSection->reserved1(); - uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]); - uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx(); - const char* name = &fOwner.fStrings[strOffset]; - char* str = new char[strlen(name)+8]; - strcpy(str, name); - strcat(str, "$stub"); - fSynthesizedName = str; - } - break; - case S_LAZY_SYMBOL_POINTERS: - case S_NON_LAZY_SYMBOL_POINTERS: - { - uint32_t index = (offset - fSection->addr()) / sizeof(macho_uintptr_t); - index += fSection->reserved1(); - uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]); - uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx(); - const char* name = &fOwner.fStrings[strOffset]; - char* str = new char[strlen(name)+16]; - strcpy(str, name); - if ( type == S_LAZY_SYMBOL_POINTERS ) - strcat(str, "$lazy_ptr"); - else - strcat(str, "$non_lazy_ptr"); - fSynthesizedName = str; - Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0); - if ( type == S_LAZY_SYMBOL_POINTERS ) { - ref->setLazy(true); - } - const macho_nlist* sym = &fOwner.fSymbols[symbolIndex]; - if ( (sym->n_type() & N_TYPE) == N_UNDF ) { - if ( (sym->n_desc() & N_WEAK_REF) != 0 ) - ref->setWeak(true); - } - } - break; - } -} - - -Atom::~Atom() -{ -} - -macho_section Atom::fgCommonsSection; - - -bool Atom::isLazyStub() -{ - return ( (fSection->flags() & SECTION_TYPE) == S_SYMBOL_STUBS); -} - -const macho_section* Atom::getCommonsSection() { - if ( strcmp(fgCommonsSection.sectname(), "__common") != 0 ) { - fgCommonsSection.set_sectname("__common"); - fgCommonsSection.set_segname("__DATA"); - fgCommonsSection.set_flags(S_ZEROFILL); - } - return &fgCommonsSection; -} - -ObjectFile::Reader* Atom::getFile() const -{ - return &fOwner; -} - - -const char* Atom::getName() const -{ - if ( fSymbol != NULL ) - return &fOwner.fStrings[fSymbol->n_strx()]; - else - return fSynthesizedName; -} - -const char* Atom::getDisplayName() const -{ - if ( fSymbol != NULL ) - return &fOwner.fStrings[fSymbol->n_strx()]; - - if ( fSynthesizedName != NULL ) - return fSynthesizedName; - - static char temp[32]; - sprintf(temp, "atom #%u", fOwner.findAtomIndex(*this)); - return temp; -} - -ObjectFile::Atom::Scope Atom::getScope() const -{ - return fScope; -} - -void Atom::setScope(ObjectFile::Atom::Scope newScope) -{ - fScope = newScope; -} - - -bool Atom::isWeakDefinition() const -{ - if ( isTentativeDefinition() ) - return true; - if ( fSymbol != NULL ) - return ( (fSymbol->n_desc() & N_WEAK_DEF) != 0 ); - uint8_t type = fSection->flags() & SECTION_TYPE; - switch ( type ) { - case S_SYMBOL_STUBS: - case S_LAZY_SYMBOL_POINTERS: - case S_NON_LAZY_SYMBOL_POINTERS: - return true; - } - return false; -} - -bool Atom::isTentativeDefinition() const -{ - return (fSection == &fgCommonsSection); -} - -bool Atom::isCoalesableByName() const -{ - uint8_t type = fSection->flags() & SECTION_TYPE; - switch ( type ) { - case S_SYMBOL_STUBS: - case S_COALESCED: - return true; - }; - if ( isTentativeDefinition() ) - return true; - return false; -} - -bool Atom::isCoalesableByValue() const -{ - uint8_t type = fSection->flags() & SECTION_TYPE; - switch ( type ) { - case S_CSTRING_LITERALS: - case S_4BYTE_LITERALS: - case S_8BYTE_LITERALS: - return true; - }; - return false; -} - -bool Atom::isZeroFill() const -{ - return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); -} - -bool Atom::dontDeadStrip() const -{ - if ( fSymbol != NULL ) - return ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 ); - return false; -} - - -bool Atom::dontStripName() const -{ - if ( fSymbol != NULL ) - return ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0 ); - return false; -} - -bool Atom::isImportProxy() const -{ - return false; -} - - -uint64_t Atom::getSize() const -{ - //return fOffset; - return fSize; -} - - -std::vector& Atom::getReferences() const -{ - return (std::vector&)(fReferences); -} - -bool Atom::mustRemainInSection() const -{ - return true; -} - -const char* Atom::getSectionName() const -{ - if ( strlen(fSection->sectname()) > 15 ) { - static char temp[18]; - strncpy(temp, fSection->sectname(), 16); - temp[17] = '\0'; - return temp; - } - return fSection->sectname(); -} - -Segment& Atom::getSegment() const -{ - return *fSegment; -} - -bool Atom::requiresFollowOnAtom() const -{ - // requires follow-on if built with old compiler and not the last atom - if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) { - if ( fOwner.findAtomIndex(*this) < (fOwner.fAtoms.size()-1) ) - return true; - } - return false; -} - -ObjectFile::Atom& Atom::getFollowOnAtom() const -{ - uint32_t myIndex = fOwner.findAtomIndex(*this); - return *fOwner.fAtoms[myIndex+1]; -} - -std::vector* Atom::getStabsDebugInfo() const -{ - if ( fStabsCount == 0 ) - return NULL; - - std::vector* stabs = new std::vector(); - stabs->reserve(fStabsCount); - - for (uint32_t i=0; i < fStabsCount; ++i) { - const macho_nlist* sym = &fOwner.fSymbols[fStabsStartIndex+i]; - if ( (sym->n_type() & N_STAB) != 0 ) { - ObjectFile::StabsInfo stab; - stab.atomOffset = sym->n_value(); - stab.string = &fOwner.fStrings[sym->n_strx()]; - stab.type = sym->n_type(); - stab.other = sym->n_sect(); - stab.desc = sym->n_desc(); - switch ( stab.type ) { - case N_FUN: - if ( stab.other == 0 ) - break; - // end of function N_FUN has size (not address) so should not be adjusted - // fall through - case N_BNSYM: - case N_ENSYM: - case N_LBRAC: - case N_RBRAC: - case N_SLINE: - case N_STSYM: - case N_LCSYM: - // all these stab types need their value changed from an absolute address to the atom offset - stab.atomOffset -= fOffset; - break; - } - stabs->push_back(stab); - } - } - - return stabs; -} - -uint8_t Atom::getAlignment() const -{ - // mach-o file format has no alignment information for atoms - just whole sections - if ( fSection != NULL ) { - if ( isTentativeDefinition() ) { - // common symbols align to their size - // that is, a 4-byte common aligns to 4-bytes - // to be safe, odd size commons align to the next power-of-2 size - uint8_t alignment = (uint8_t)ceil(log2(this->getSize())); - // limit alignment of extremely large commons to 2^15 bytes (8-page) - if ( alignment < 15 ) - return alignment; - else - return 15; - } - else { - // so we assume every atom requires the same alignment as the whole section - return fSection->align(); - } - } - else { - return 2; - } -} - -void Atom::copyRawContent(uint8_t buffer[]) const -{ - // copy base bytes - if ( isZeroFill() ) - bzero(buffer, fSize); - else { - uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset; - memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize); - } -} - -void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - const uint32_t referencesCount = fReferences.size(); - - // skip copy if no fix-ups - if ( referencesCount == 0 ) { - uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset; - writer.write(0, (char*)(fOwner.fHeader)+fileOffset, fSize); - return; - } - - // copy base bytes - uint8_t buffer[this->getSize()]; - this->copyRawContent(buffer); - - // apply any fix-ups - for (uint32_t i=0; i < referencesCount; ++i) { - Reference* ref = fReferences[i]; - uint32_t offset = ref->getFixUpOffset(); - uint32_t* instructionPtr = (uint32_t*)&buffer[offset]; - ObjectFile::Atom& target = ref->getTarget(); - if ( &target == NULL ) { - if ( finalLinkedImage ) - throw "target not found"; - else - continue; - } - uint32_t instruction; - uint32_t newInstruction; - switch ( ref->getKind() ) { - case Reference::noFixUp: - break; - case Reference::pointer: - { - //fprintf(stderr, "writeContent: %s reference to %s\n", this->getDisplayName(), target.getDisplayName()); - if ( ref->isLazyReference() && finalLinkedImage ) { - // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target) - *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getFromTarget().getAddress()); - } - else if ( target.isImportProxy() ) { - // external realocation ==> pointer contains addend - *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset()); - } - else { - // internal relocation - if ( finalLinkedImage || (strcmp(target.getSectionName(), "__common") != 0) ) { - // pointer contains target address - //printf("Atom::writeContent() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress()); - *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(target.getAddress() + ref->getTargetOffset()); - } - else { - // pointer contains addend - *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset()); - } - } - } - break; - case Reference::ppcFixupBranch24: - { - //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress()); - int64_t displacement = (target.getAddress() + ref->getTargetOffset() ) - (this->getAddress() + offset); - if ( !finalLinkedImage && target.isImportProxy() ) { - // doing "ld -r" to an external symbol - // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target - displacement -= target.getAddress(); - } - else { - const int64_t bl_eightMegLimit = 0x00FFFFFF; - if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) { - //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); - throwf("bl out of range (%lld max is +/-16M) from %s in %s to %s in %s", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); - } - } - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC); - //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction); - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::ppcFixupBranch14: - break; - case Reference::ppcFixupPicBaseLow16: - { - uint64_t targetAddr = target.getAddress() + ref->getTargetOffset(); - uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset(); - int64_t displacement = targetAddr - picBaseAddr; - const int64_t picbase_twoGigLimit = 0x80000000; - if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) - throw "32-bit pic-base out of range"; - uint16_t instructionLowHalf = (displacement & 0xFFFF); - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf; - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::ppcFixupPicBaseLow14: - { - uint64_t targetAddr = target.getAddress() + ref->getTargetOffset(); - uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset(); - int64_t displacement = targetAddr - picBaseAddr; - const int64_t picbase_twoGigLimit = 0x80000000; - if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) - throw "32-bit pic-base out of range"; - uint16_t instructionLowHalf = (displacement & 0xFFFF); - if ( (instructionLowHalf & 0x3) != 0 ) - throw "bad address for lo14 instruction fix-up"; - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf; - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::ppcFixupPicBaseHigh16: - { - uint64_t targetAddr = target.getAddress() + ref->getTargetOffset(); - uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset(); - int64_t displacement = targetAddr - picBaseAddr; - const int64_t picbase_twoGigLimit = 0x80000000; - if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) - throw "32-bit pic-base out of range"; - uint16_t instructionLowHalf = displacement >> 16; - if ( (displacement & 0x00008000) != 0 ) - ++instructionLowHalf; - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf; - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::ppcFixupAbsLow16: - { - int64_t addr = target.getAddress() + ref->getTargetOffset(); - if ( !finalLinkedImage && target.isImportProxy() ) - addr -= target.getAddress() ; - uint16_t instructionLowHalf = (addr & 0xFFFF); - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf; - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::ppcFixupAbsLow14: - { - int64_t addr = target.getAddress() + ref->getTargetOffset(); - if ( !finalLinkedImage && target.isImportProxy() ) - addr -= target.getAddress() ; - uint16_t instructionLowHalf = (addr & 0xFFFF); - if ( (instructionLowHalf & 0x3) != 0 ) - throw "bad address for lo14 instruction fix-up"; - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf; - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::ppcFixupAbsHigh16: - { - int64_t addr = target.getAddress() + ref->getTargetOffset(); - if ( !finalLinkedImage && target.isImportProxy() ) - addr -= target.getAddress() ; - uint16_t hi16 = (addr >> 16); - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFFFF0000) | hi16; - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::ppcFixupAbsHigh16AddLow: - { - int64_t addr = target.getAddress() + ref->getTargetOffset(); - if ( !finalLinkedImage && target.isImportProxy() ) - addr -= target.getAddress() ; - if ( addr & 0x00008000 ) - addr += 0x00010000; - instruction = OSReadBigInt32(instructionPtr, 0); - newInstruction = (instruction & 0xFFFF0000) | (addr >> 16); - OSWriteBigInt32(instructionPtr, 0, newInstruction); - } - break; - case Reference::pointer32Difference: - ENDIAN_WRITE32(*instructionPtr, target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset())); - break; - case Reference::pointer64Difference: - *((uint64_t*)instructionPtr) = ENDIAN_SWAP64(target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset())); - break; - case Reference::x86FixupBranch32: - { - int64_t displacement = target.getAddress() - (this->getAddress() + offset); - if ( target.isImportProxy() ) { - displacement = 0; - } - else { - const int64_t bl_twoGigLimit = 0x7FFFFFFF; - if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_twoGigLimit)) ) { - //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath()); - throw "call out of range"; - } - } - OSWriteLittleInt32(instructionPtr, 0, (int32_t)displacement); - } - break; - } - } - - // write out - writer.write(0, buffer, getSize()); -} - - - -const macho_section* Atom::findSectionFromOffset(uint32_t offset) -{ - const macho_section* const sectionsStart = (const macho_section*)( (char*)fOwner.fSegment + sizeof(macho_segment_command) ); - const macho_section* const sectionsEnd = §ionsStart[fOwner.fSegment->nsects()]; - for (const macho_section* s = sectionsStart; s < sectionsEnd; ++s) { - if ( (s->addr() <= offset) && (offset < (s->addr()+s->size())) ) - return s; - } - throwf("address 0x%08X is not in any section", offset); -} - -void Atom::setSize(macho_uintptr_t size) -{ - fSize = size; -} - - -void Atom::setFollowOnAtom(Atom&) -{ - -} - -Reference* Atom::addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget) -{ - if ( (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && ((target.fSymbol != NULL) || (target.fSynthesizedName != NULL)) ) - return this->addByNameReference(offsetInSrcAtom, kind, target.getName(), offsetInTarget, offsetInFromTarget); - else - return this->addDirectReference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget); -} - - -Reference* Atom::addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget) -{ - Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget); - // in rare cases, there may already be a by-name reference to the same atom. If so, replace with this direct reference - for (std::vector::iterator it=fReferences.begin(); it != fReferences.end(); it++) { - ObjectFile::Reference* aRef = *it; - if ( (aRef->getFixUpOffset() == offsetInSrcAtom) && (aRef->getKind() == kind) ) { - *it = ref; - return ref; - } - } - - // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file - fReferences.insert(fReferences.begin(), ref); - return ref; -} - -Reference* Atom::addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget) -{ - Reference* ref = new Reference(offsetInSrcAtom, kind, targetName, offsetInTarget, offsetInFromTarget); - // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file - fReferences.insert(fReferences.begin(), ref); - return ref; -} - -Reference* Atom::addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget) -{ - Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, fromTarget, offsetInFromTarget); - // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file - fReferences.insert(fReferences.begin(), ref); - return ref; -} - - -Segment::Segment(const macho_section* sect) - : fSection(sect) -{ -} - -const char* Segment::getName() const -{ - return fSection->segname(); -} - -bool Segment::isContentReadable() const -{ - return true; -} - -bool Segment::isContentWritable() const -{ - if ( strcmp(fSection->segname(), "__DATA") == 0 ) - return true; - if ( strcmp(fSection->segname(), "__OBJC") == 0 ) - return true; - return false; -} - -bool Segment::isContentExecutable() const -{ - return ( strcmp(fSection->segname(), "__TEXT") == 0 ); -} - - -Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget) - : fTarget(NULL), fFromTarget(NULL), fTargetName(targetName), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget), - fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false) -{ -} - -Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget) - : fTarget(&target), fFromTarget(NULL), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget), - fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false) -{ -} - -Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget) - : fTarget(&target), fFromTarget(&fromTarget), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget), - fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false) -{ - // assure no direct references to something that might be coalesced - if ( (target.isWeakDefinition() || target.isCoalesableByName()) && (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (target.getName() != NULL) ) { - //fprintf(stderr, "change TO direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this); - fTargetName = target.getName(); - fTarget = NULL; - } -// Note: We should also allow by-name from references, but many other chunks of code assume from targets are always direct// -// if ( (fromTarget.isWeakDefinition() || fromTarget.isCoalesableByName()) && (fromTarget.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (fromTarget.getName() != NULL)) { -// fprintf(stderr, "change FROM direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this); -// fFromTargetName = fromTarget.getName(); -// fFromTarget = NULL; -// } -} - - - -Reference::~Reference() -{ -} - -bool Reference::isTargetUnbound() const -{ - return ( fTarget == NULL ); -} - -bool Reference::isFromTargetUnbound() const -{ - return ( fFromTarget == NULL ); -} - -bool Reference::isWeakReference() const -{ - return fWeak; -} - -bool Reference::requiresRuntimeFixUp(bool slideable) const -{ - // This static linker only supports pure code (no code fixups are runtime) -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - // Only data can be fixed up, and the codegen assures only "pointers" need runtime fixups - return ( (fKind == Reference::pointer) && (fTarget->isImportProxy() || fTarget->isWeakDefinition() || slideable) ); -#elif defined(ARCH_I386) - // For i386, Reference::pointer is used for both data pointers and instructions with 32-bit absolute operands - if ( fKind == Reference::pointer ) { - if ( fTarget->isImportProxy() ) - return true; - else - return slideable; - } - return false; -#else - #error -#endif -} - -bool Reference::isLazyReference() const -{ - return fLazy; -} - -ObjectFile::Reference::Kind Reference::getKind() const -{ - return fKind; -} - -uint64_t Reference::getFixUpOffset() const -{ - return fFixUpOffsetInSrc; -} - -const char* Reference::getTargetName() const -{ - if ( fTargetName != NULL ) - return fTargetName; - return fTarget->getName(); -} - -ObjectFile::Atom& Reference::getTarget() const -{ - return *fTarget; -} - -void Reference::setTarget(ObjectFile::Atom& target, uint64_t offset) -{ - fTarget = ⌖ - fTargetOffset = offset; -} - - -ObjectFile::Atom& Reference::getFromTarget() const -{ - return *fFromTarget; -} - -bool Reference::hasFromTarget() const -{ - return ( (fFromTarget != NULL) || (fFromTargetName != NULL) ); -} - -const char* Reference::getFromTargetName() const -{ - if ( fFromTargetName != NULL ) - return fFromTargetName; - return fFromTarget->getName(); -} - -void Reference::setFromTarget(ObjectFile::Atom& target) -{ - fFromTarget = ⌖ -} - -void Reference::setFromTargetName(const char* name) -{ - fFromTargetName = name; -} - -void Reference::setFromTargetOffset(uint64_t offset) -{ - fFromTargetOffset = offset; -} - -uint64_t Reference::getTargetOffset() const -{ - return fTargetOffset; -} - - -uint64_t Reference::getFromTargetOffset() const -{ - return fFromTargetOffset; -} - -void Reference::setLazy(bool lazy) -{ - fLazy = lazy; -} - -void Reference::setWeak(bool weak) -{ - fWeak = weak; -} - -const char* Reference::getDescription() const -{ - static char temp[256]; - if ( fKind == pointer32Difference ) { - // by-name references have quoted names - bool targetByName = ( &(this->getTarget()) == NULL ); - bool fromByName = ( &(this->getFromTarget()) == NULL ); - const char* targetQuotes = targetByName ? "\"" : ""; - const char* fromQuotes = fromByName ? "\"" : ""; - sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)", - this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(), - fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() ); - } - else if ( fKind == pointer64Difference ) { - // by-name references have quoted names - bool targetByName = ( &(this->getTarget()) == NULL ); - bool fromByName = ( &(this->getFromTarget()) == NULL ); - const char* targetQuotes = targetByName ? "\"" : ""; - const char* fromQuotes = fromByName ? "\"" : ""; - sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)", - this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(), - fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() ); - } - else { - switch( fKind ) { - case noFixUp: - sprintf(temp, "reference to "); - break; - case pointer: - { - const char* weak = ""; - if ( fWeak ) - weak = "weak "; - const char* lazy = ""; - if ( fLazy ) - lazy = "lazy "; - sprintf(temp, "offset 0x%04llX, %s%spointer to ", this->getFixUpOffset(), weak, lazy); - } - break; - case ppcFixupBranch14: - case ppcFixupBranch24: - sprintf(temp, "offset 0x%04llX, bl pc-rel fixup to ", this->getFixUpOffset()); - break; - case ppcFixupPicBaseLow16: - sprintf(temp, "offset 0x%04llX, low 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset()); - break; - case ppcFixupPicBaseLow14: - sprintf(temp, "offset 0x%04llX, low 14 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset()); - break; - case ppcFixupPicBaseHigh16: - sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset()); - break; - case ppcFixupAbsLow16: - sprintf(temp, "offset 0x%04llX, low 16 fixup to absolute address of ", this->getFixUpOffset()); - break; - case ppcFixupAbsLow14: - sprintf(temp, "offset 0x%04llX, low 14 fixup to absolute address of ", this->getFixUpOffset()); - break; - case ppcFixupAbsHigh16: - sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset()); - break; - case ppcFixupAbsHigh16AddLow: - sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset()); - break; - case pointer32Difference: - case pointer64Difference: - // handled above - break; - case x86FixupBranch32: - sprintf(temp, "offset 0x%04llX, pc-rel fixup to ", this->getFixUpOffset()); - break; - } - // always quote by-name references - if ( fTargetName != NULL ) { - strcat(temp, "\""); - strcat(temp, fTargetName); - strcat(temp, "\""); - } - else if ( fTarget != NULL ) { - strcat(temp, fTarget->getDisplayName()); - } - else { - strcat(temp, "NULL target"); - } - if ( fTargetOffset != 0 ) - sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getTargetOffset()); - if ( (fKind==pointer) && fLazy ) { - strcat(temp, " initially bound to \""); - if ( (fFromTarget != NULL) || (fFromTargetName != NULL) ) { - strcat(temp, this->getFromTargetName()); - strcat(temp, "\""); - if ( this->getFromTargetOffset() != 0 ) - sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getFromTargetOffset()); - } - else { - strcat(temp, "\" << missing >>"); - } - } - } - return temp; -} - -}; - - - - - - -