X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/c7f24d34adf9643c842ab6c44f8e530661cffcc7..d696c285d331ab577dcabd00419d8c30336673da:/src/Writers/ExecutableFileMachO.cpp diff --git a/src/Writers/ExecutableFileMachO.cpp b/src/Writers/ExecutableFileMachO.cpp deleted file mode 100644 index 90a9527..0000000 --- a/src/Writers/ExecutableFileMachO.cpp +++ /dev/null @@ -1,2807 +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 ExecutableFileMachO { - -class Writer : public ExecutableFile::Writer -{ -public: - Writer(const char* path, Options& options, std::vector& dynamicLibraries); - virtual ~Writer(); - - virtual const char* getPath(); - virtual std::vector& getAtoms(); - virtual std::vector* getJustInTimeAtomsFor(const char* name); - virtual std::vector* getStabsDebugInfo(); - - virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name); - virtual void write(std::vector& atoms, class ObjectFile::Atom* entryPointAtom); - -private: - void assignFileOffsets(); - void partitionIntoSections(); - bool addBranchIslands(); - void adjustLoadCommandsAndPadding(); - void createDynamicLinkerCommand(); - void createDylibCommands(); - void buildLinkEdit(); - void writeAtoms(); - void collectExportedAndImportedAndLocalAtoms(); - void setNlistRange(std::vector& atoms, uint32_t startIndex, uint32_t count); - void buildSymbolTable(); - void setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry); - void setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry); - void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry); - uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom); - uint8_t ordinalForLibrary(ObjectFile::Reader* file); - bool shouldExport(ObjectFile::Atom& atom); - void buildFixups(); - void adjustLinkEditSections(); - void buildObjectFileFixups(); - void buildExecutableFixups(); - uint32_t symbolIndex(ObjectFile::Atom& atom); - uint32_t addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref); - unsigned int collectStabs(); - macho_uintptr_t valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom); - void addStabs(uint32_t startIndex, uint32_t count); - - - class SectionInfo : public ObjectFile::Section { - public: - SectionInfo(); - void setIndex(unsigned int index) { fIndex=index; } - std::vector fAtoms; - char fSegmentName[20]; - char fSectionName[20]; - uint64_t fFileOffset; - uint64_t fSize; - uint32_t fRelocCount; - uint32_t fRelocOffset; - uint32_t fIndirectSymbolOffset; - uint8_t fAlignment; - bool fAllLazyPointers; - bool fAllNonLazyPointers; - bool fAllZeroFill; - bool fVirtualSection; - }; - - class SegmentInfo - { - public: - SegmentInfo(); - std::vector fSections; - char fName[20]; - uint32_t fInitProtection; - uint32_t fMaxProtection; - uint64_t fFileOffset; - uint64_t fFileSize; - uint64_t fBaseAddress; - uint64_t fSize; - bool fFixedAddress; - }; - - - struct DirectLibrary { - class ObjectFile::Reader* fLibrary; - bool fWeak; - bool fReExport; - }; - - struct IndirectEntry { - uint32_t indirectIndex; - uint32_t symbolIndex; - }; - - struct StabChunks { - ObjectFile::Atom* fAtom; - ObjectFile::Reader* fReader; - unsigned int fReaderOrder; - unsigned int fOrderInReader; - std::vector* fStabs; - }; - - static bool stabChunkCompare(const StabChunks& lhs, const StabChunks& rhs); - - friend class WriterAtom; - friend class PageZeroAtom; - friend class CustomStackAtom; - friend class MachHeaderAtom; - friend class SegmentLoadCommandsAtom; - friend class SymbolTableLoadCommandsAtom; - friend class ThreadsLoadCommandsAtom; - friend class DylibIDLoadCommandsAtom; - friend class RoutinesLoadCommandsAtom; - friend class DyldLoadCommandsAtom; - friend class LinkEditAtom; - friend class LocalRelocationsLinkEditAtom; - friend class ExternalRelocationsLinkEditAtom; - friend class SymbolTableLinkEditAtom; - friend class IndirectTableLinkEditAtom; - friend class StringsLinkEditAtom; - - const char* fFilePath; - Options& fOptions; - int fFileDescriptor; - std::vector* fAllAtoms; - class SectionInfo* fLoadCommandsSection; - class SegmentInfo* fLoadCommandsSegment; - class SegmentLoadCommandsAtom* fSegmentCommands; - class SymbolTableLoadCommandsAtom* fSymbolTableCommands; - class LoadCommandsPaddingAtom* fHeaderPadding; - std::vector fWriterSynthesizedAtoms; - std::vector fSegmentInfos; - class ObjectFile::Atom* fEntryPoint; - std::vector fDirectLibraries; - std::map fLibraryToOrdinal; - std::vector fStabChunks; - std::vector fExportedAtoms; - std::vector fImportedAtoms; - std::vector fLocalSymbolAtoms; - LocalRelocationsLinkEditAtom* fLocalRelocationsAtom; - ExternalRelocationsLinkEditAtom* fExternalRelocationsAtom; - SymbolTableLinkEditAtom* fSymbolTableAtom; - IndirectTableLinkEditAtom* fIndirectTableAtom; - StringsLinkEditAtom* fStringsAtom; - macho_nlist* fSymbolTable; - //char* fStringPool; - //uint32_t fStringPoolUsed; - //uint32_t fStringPoolSize; - std::vector fInternalRelocs; - std::vector fExternalRelocs; - std::vector fIndirectSymbolTable; - uint32_t fSymbolTableCount; - uint32_t fSymbolTableStabsCount; - uint32_t fSymbolTableStabsStartIndex; - uint32_t fSymbolTableLocalCount; - uint32_t fSymbolTableLocalStartIndex; - uint32_t fSymbolTableExportCount; - uint32_t fSymbolTableExportStartIndex; - uint32_t fSymbolTableImportCount; - uint32_t fSymbolTableImportStartIndex; - bool fEmitVirtualSections; - bool fHasWeakExports; - bool fReferencesWeakImports; -}; - - -class WriterAtom : public ObjectFile::Atom -{ -protected: - class Segment; -public: - enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy }; - WriterAtom(Writer& writer, class WriterAtom::Segment& segment) : fWriter(writer), fSegment(segment) {} - - virtual ObjectFile::Reader* getFile() const { return &fWriter; } - virtual const char* getName() const { return NULL; } - virtual const char* getDisplayName() const { return this->getName(); } - virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; } - virtual bool isTentativeDefinition() const { return false; } - virtual bool isWeakDefinition() const { return false; } - virtual bool isCoalesableByName() const { return false; } - virtual bool isCoalesableByValue() const { return false; } - virtual bool isZeroFill() const { return false; } - virtual bool dontDeadStrip() const { return true; } - virtual bool dontStripName() const { return false; } - virtual bool isImportProxy() const { return false; } - virtual std::vector& getReferences() const { return fgEmptyReferenceList; } - virtual bool mustRemainInSection() const { return true; } - virtual ObjectFile::Segment& getSegment() const { return fSegment; } - virtual bool requiresFollowOnAtom() const { return false; } - virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); } - virtual std::vector* getStabsDebugInfo() const { return NULL; } - virtual uint8_t getAlignment() const { return 2; } - virtual WeakImportSetting getImportWeakness() const { return Atom::kWeakUnset; } - virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; } - virtual void setScope(Scope) { } - virtual void setImportWeakness(bool weakImport) { } - - -protected: - virtual ~WriterAtom() {} - - class Segment : public ObjectFile::Segment - { - public: - Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress) - : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {} - virtual const char* getName() const { return fName; } - virtual bool isContentReadable() const { return fReadable; } - virtual bool isContentWritable() const { return fWritable; } - virtual bool isContentExecutable() const { return fExecutable; } - virtual bool hasFixedAddress() const { return fFixedAddress; } - private: - const char* fName; - const bool fReadable; - const bool fWritable; - const bool fExecutable; - const bool fFixedAddress; - }; - - static std::vector fgEmptyReferenceList; - static Segment fgTextSegment; - static Segment fgPageZeroSegment; - static Segment fgLinkEditSegment; - static Segment fgStackSegment; - - - Writer& fWriter; - Segment& fSegment; -}; - - -WriterAtom::Segment WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false, true); -WriterAtom::Segment WriterAtom::fgTextSegment("__TEXT", true, false, true, false); -WriterAtom::Segment WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false, false); -WriterAtom::Segment WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false, true); -std::vector WriterAtom::fgEmptyReferenceList; - -class PageZeroAtom : public WriterAtom -{ -public: - PageZeroAtom(Writer& writer) : WriterAtom(writer, fgPageZeroSegment) {} - virtual const char* getDisplayName() const { return "page zero content"; } - virtual bool isZeroFill() const { return true; } - virtual uint64_t getSize() const { return fWriter.fOptions.zeroPageSize(); } - virtual const char* getSectionName() const { return "._zeropage"; } - virtual uint8_t getAlignment() const { return 12; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {} -}; - -class MachHeaderAtom : public WriterAtom -{ -public: - MachHeaderAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {} - virtual const char* getName() const; - virtual const char* getDisplayName() const; - virtual Scope getScope() const; - virtual bool dontStripName() const; - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 12; } - virtual const char* getSectionName() const { return "._mach_header"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class CustomStackAtom : public WriterAtom -{ -public: - CustomStackAtom(Writer& writer); - virtual const char* getDisplayName() const { return "custom stack content"; } - virtual bool isZeroFill() const { return true; } - virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); } - virtual const char* getSectionName() const { return "._stack"; } - virtual uint8_t getAlignment() const { return 12; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {} -}; - -class SegmentLoadCommandsAtom : public WriterAtom -{ -public: - SegmentLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment), fCommandCount(0), fSize(0) { writer.fSegmentCommands = this; } - virtual const char* getDisplayName() const { return "segment load commands"; } - virtual uint64_t getSize() const { return fSize; } - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; - - void computeSize(); - void setup(); - unsigned int commandCount() { return fCommandCount; } - void assignFileOffsets(); -private: - unsigned int fCommandCount; - uint32_t fSize; -}; - -class SymbolTableLoadCommandsAtom : public WriterAtom -{ -public: - SymbolTableLoadCommandsAtom(Writer&); - virtual const char* getDisplayName() const { return "symbol table load commands"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; - -private: - macho_symtab_command fSymbolTable; - macho_dysymtab_command fDynamicSymbolTable; -}; - -class ThreadsLoadCommandsAtom : public WriterAtom -{ -public: - ThreadsLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {} - virtual const char* getDisplayName() const { return "thread load commands"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -private: - uint8_t* fBuffer; - uint32_t fBufferSize; -}; - -class DyldLoadCommandsAtom : public WriterAtom -{ -public: - DyldLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {} - virtual const char* getDisplayName() const { return "dyld load command"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class DylibLoadCommandsAtom : public WriterAtom -{ -public: - DylibLoadCommandsAtom(Writer& writer, ExecutableFile::DyLibUsed& info) : WriterAtom(writer, fgTextSegment), fInfo(info) {} - virtual const char* getDisplayName() const { return "dylib load command"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -private: - ExecutableFile::DyLibUsed& fInfo; -}; - -class DylibIDLoadCommandsAtom : public WriterAtom -{ -public: - DylibIDLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {} - virtual const char* getDisplayName() const { return "dylib ID load command"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class RoutinesLoadCommandsAtom : public WriterAtom -{ -public: - RoutinesLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {} - virtual const char* getDisplayName() const { return "routines load command"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class SubUmbrellaLoadCommandsAtom : public WriterAtom -{ -public: - SubUmbrellaLoadCommandsAtom(Writer& writer, const char* name) : WriterAtom(writer, fgTextSegment), fName(name) {} - virtual const char* getDisplayName() const { return "sub-umbrella load command"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -private: - const char* fName; -}; - -class SubLibraryLoadCommandsAtom : public WriterAtom -{ -public: - SubLibraryLoadCommandsAtom(Writer& writer, const char* nameStart, int nameLen) - : WriterAtom(writer, fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {} - virtual const char* getDisplayName() const { return "sub-library load command"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -private: - const char* fNameStart; - int fNameLength; -}; - -class UmbrellaLoadCommandsAtom : public WriterAtom -{ -public: - UmbrellaLoadCommandsAtom(Writer& writer, const char* name) - : WriterAtom(writer, fgTextSegment), fName(name) {} - virtual const char* getDisplayName() const { return "umbrella load command"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_commands"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -private: - const char* fName; -}; - -class LoadCommandsPaddingAtom : public WriterAtom -{ -public: - LoadCommandsPaddingAtom(Writer& writer) - : WriterAtom(writer, fgTextSegment), fSize(0) {} - virtual const char* getDisplayName() const { return "header padding"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._load_cmds_pad"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; - - void setSize(uint64_t newSize) { fSize = newSize; } -private: - uint64_t fSize; -}; - -class LinkEditAtom : public WriterAtom -{ -public: - LinkEditAtom(Writer& writer) : WriterAtom(writer, fgLinkEditSegment) {} - uint64_t getFileOffset() const; -}; - -class LocalRelocationsLinkEditAtom : public LinkEditAtom -{ -public: - LocalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } - virtual const char* getDisplayName() const { return "local relocations"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 3; } - virtual const char* getSectionName() const { return "._local_relocs"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class SymbolTableLinkEditAtom : public LinkEditAtom -{ -public: - SymbolTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } - virtual const char* getDisplayName() const { return "symbol table"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._symbol_table"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class ExternalRelocationsLinkEditAtom : public LinkEditAtom -{ -public: - ExternalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } - virtual const char* getDisplayName() const { return "external relocations"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 3; } - virtual const char* getSectionName() const { return "._extern_relocs"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class IndirectTableLinkEditAtom : public LinkEditAtom -{ -public: - IndirectTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { } - virtual const char* getDisplayName() const { return "indirect symbol table"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._indirect_syms"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -}; - -class StringsLinkEditAtom : public LinkEditAtom -{ -public: - StringsLinkEditAtom(Writer& writer); - virtual const char* getDisplayName() const { return "string pool"; } - virtual uint64_t getSize() const; - virtual uint8_t getAlignment() const { return 2; } - virtual const char* getSectionName() const { return "._string_pool"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; - - int32_t add(const char* name); - int32_t emptyString(); - -private: - enum { kBufferSize = 0x01000000 }; - - std::vector fFullBuffers; - char* fCurrentBuffer; - uint32_t fCurrentBufferUsed; -}; - - - -class UndefinedSymbolProxyAtom : public WriterAtom -{ -public: - UndefinedSymbolProxyAtom(Writer& writer, const char* name) : WriterAtom(writer, fgLinkEditSegment), fName(name), fWeakImportSetting(Atom::kWeakUnset) {} - virtual const char* getName() const { return fName; } - virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; } - virtual uint64_t getSize() const { return 0; } - virtual bool isWeakDefinition() const { return true; } - virtual bool isImportProxy() const { return true; } - virtual const char* getSectionName() const { return "._imports"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {} - virtual WeakImportSetting getImportWeakness() const { return fWeakImportSetting; } - virtual void setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; } -private: - const char* fName; - WeakImportSetting fWeakImportSetting; -}; - -#if defined(ARCH_PPC) || defined(ARCH_PPC64) -class BranchIslandAtom : public WriterAtom -{ -public: - BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset); - virtual const char* getName() const { return fName; } - virtual Scope getScope() const { return ObjectFile::Atom::scopeLinkageUnit; } - virtual uint64_t getSize() const { return 4; } - virtual const char* getSectionName() const { return "__text"; } - virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const; -private: - const char* fName; - ObjectFile::Atom& fTarget; - uint32_t fTargetOffset; -}; -#endif - -struct ExportSorter -{ - bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right) - { - return (strcmp(left->getName(), right->getName()) < 0); - } -}; - - -ExecutableFile::Writer* MakeWriter(const char* path, Options& options, std::vector& dynamicLibraries) -{ - return new Writer(path, options, dynamicLibraries); -} - -Writer::SectionInfo::SectionInfo() - : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0), - fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false) -{ - fSegmentName[0] = '\0'; - fSectionName[0] = '\0'; -} - -Writer::SegmentInfo::SegmentInfo() - : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0), fFixedAddress(false) -{ - fName[0] = '\0'; -} - - -Writer::Writer(const char* path, Options& options, std::vector& dynamicLibraries) - : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL), - fLoadCommandsSegment(NULL), - //fStringPool(NULL), fStringPoolUsed(0), fStringPoolSize(0), - fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false) -{ - int permissions = 0777; - if ( fOptions.outputKind() == Options::kObjectFile ) - permissions = 0666; - // Calling unlink first assures the file is gone so that open creates it with correct permissions - // It also handles the case where fFilePath file is not writeable but its directory is - // And it means we don't have to truncate the file when done writing (in case new is smaller than old) - (void)unlink(fFilePath); - fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions); - if ( fFileDescriptor == -1 ) { - throw "can't open file for writing"; - } - - switch ( fOptions.outputKind() ) { - case Options::kDynamicExecutable: - case Options::kStaticExecutable: - fWriterSynthesizedAtoms.push_back(new PageZeroAtom(*this)); - fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this)); - fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this)); - fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this)); - if ( fOptions.outputKind() == Options::kDynamicExecutable ) - fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this)); - fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this)); - if ( fOptions.hasCustomStack() ) - fWriterSynthesizedAtoms.push_back(new CustomStackAtom(*this)); - fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this)); - fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this)); - break; - case Options::kDynamicLibrary: - case Options::kDynamicBundle: - case Options::kObjectFile: - fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this)); - fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this)); - if ( fOptions.outputKind() == Options::kDynamicLibrary ) { - fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom(*this)); - if ( fOptions.initFunctionName() != NULL ) - fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom(*this)); - } - fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this)); - fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this)); - fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this)); - break; - case Options::kDyld: - fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this)); - fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this)); - fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this)); - fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this)); - fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this)); - fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this)); - fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this)); - fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this)); - break; - } - - // add extra commmands - uint8_t ordinal = 1; - switch ( fOptions.outputKind() ) { - case Options::kDynamicExecutable: - case Options::kDynamicLibrary: - case Options::kDynamicBundle: - { - // add dylib load command atoms for all dynamic libraries - const unsigned int libCount = dynamicLibraries.size(); - for (unsigned int i=0; i < libCount; ++i) { - ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i]; - if ( dylibInfo.indirect ) { - // find ordinal of direct reader - if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) { - bool found = false; - for (std::map::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) { - if ( it->first == dylibInfo.directReader ) { - //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath()); - fLibraryToOrdinal[dylibInfo.reader] = it->second; - found = true; - break; - } - } - if ( ! found ) - fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL); - } - } - else { - // see if a DylibLoadCommandsAtom has already been created for this install path - bool newDylib = true; - const char* dylibInstallPath = dylibInfo.reader->getInstallPath(); - if ( dylibInfo.options.fInstallPathOverride != NULL ) - dylibInstallPath = dylibInfo.options.fInstallPathOverride; - for (unsigned int seenLib=0; seenLib < i; ++seenLib) { - ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib]; - if ( !seenDylibInfo.indirect ) { - const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath(); - if ( seenDylibInfo.options.fInstallPathOverride != NULL ) - seenDylibInstallPath = dylibInfo.options.fInstallPathOverride; - if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) { - fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader]; - newDylib = false; - break; - } - } - } - - if ( newDylib ) { - // assign new ordinal and check for other paired load commands - fLibraryToOrdinal[dylibInfo.reader] = ordinal++; - fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom(*this, dylibInfo)); - if ( dylibInfo.options.fReExport ) { - // this dylib also needs a sub_x load command - bool isFrameworkReExport = false; - const char* lastSlash = strrchr(dylibInstallPath, '/'); - if ( lastSlash != NULL ) { - char frameworkName[strlen(lastSlash)+20]; - sprintf(frameworkName, "/%s.framework/", &lastSlash[1]); - isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL); - } - if ( isFrameworkReExport ) { - // needs a LC_SUB_UMBRELLA command - fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom(*this, &lastSlash[1])); - } - else { - // needs a LC_SUB_LIBRARY command - const char* nameStart = &lastSlash[1]; - if ( lastSlash == NULL ) - nameStart = dylibInstallPath; - int len = strlen(nameStart); - const char* dot = strchr(nameStart, '.'); - if ( dot != NULL ) - len = dot - nameStart; - fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom(*this, nameStart, len)); - } - } - } - } - } - // add umbrella command if needed - if ( fOptions.umbrellaName() != NULL ) { - fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions.umbrellaName())); - } - } - break; - case Options::kStaticExecutable: - case Options::kObjectFile: - case Options::kDyld: - break; - } - - //fprintf(stderr, "ordinals table:\n"); - //for (std::map::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) { - // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath()); - //} -} - -Writer::~Writer() -{ - if ( fFilePath != NULL ) - free((void*)fFilePath); - if ( fSymbolTable != NULL ) - delete [] fSymbolTable; - //if ( fStringPool != NULL ) - // delete [] fStringPool; -} - -const char* Writer::getPath() -{ - return fFilePath; -} - - -std::vector& Writer::getAtoms() -{ - return fWriterSynthesizedAtoms; -} - -std::vector* Writer::getJustInTimeAtomsFor(const char* name) -{ - return NULL; -} - -std::vector* Writer::getStabsDebugInfo() -{ - return NULL; -} - -ObjectFile::Atom* Writer::getUndefinedProxyAtom(const char* name) -{ - if ( (fOptions.outputKind() == Options::kObjectFile) - || (fOptions.undefinedTreatment() != Options::kUndefinedError) ) - return new UndefinedSymbolProxyAtom(*this, name); - else - return NULL; -} - -uint8_t Writer::ordinalForLibrary(ObjectFile::Reader* lib) -{ - // flat namespace images use zero for all ordinals - if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace ) - return 0; - - // is an UndefinedSymbolProxyAtom - if ( lib == this ) - if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) - return DYNAMIC_LOOKUP_ORDINAL; - - std::map::iterator pos = fLibraryToOrdinal.find(lib); - if ( pos != fLibraryToOrdinal.end() ) - return pos->second; - - throw "can't find ordinal for imported symbol"; -} - - -void Writer::write(std::vector& atoms, class ObjectFile::Atom* entryPointAtom) -{ - fAllAtoms = &atoms; - fEntryPoint = entryPointAtom; - - // create SegmentInfo and SectionInfo objects and assign all atoms to a section - partitionIntoSections(); - - // segment load command can now be sized and padding can be set - adjustLoadCommandsAndPadding(); - - // assign each section a file offset - assignFileOffsets(); - - // if need to add branch islands, reassign file offsets - if ( addBranchIslands() ) - assignFileOffsets(); - - // build symbol table and relocations - buildLinkEdit(); - - // write everything - writeAtoms(); -} - -void Writer::buildLinkEdit() -{ - this->collectExportedAndImportedAndLocalAtoms(); - this->buildSymbolTable(); - this->buildFixups(); - this->adjustLinkEditSections(); -} - - - -uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom* atom) -{ - return atom->getAddress(); -// SectionInfo* info = (SectionInfo*)atom->getSection(); -// return info->getBaseAddress() + atom->getSectionOffset(); -} - -void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry) -{ - // set n_type - entry->set_n_type(N_EXT | N_SECT); - if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) ) - entry->set_n_type(N_EXT | N_SECT | N_PEXT); - - // set n_sect (section number of implementation ) - uint8_t sectionIndex = atom->getSection()->getIndex(); - entry->set_n_sect(sectionIndex); - - // the __mh_execute_header is magic and must be an absolute symbol - if ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0) && atom->dontStripName()) - entry->set_n_type(N_EXT | N_ABS); - - // set n_desc - uint16_t desc = 0; - if ( atom->dontStripName() ) - desc |= REFERENCED_DYNAMICALLY; - if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) { - desc |= N_WEAK_DEF; - fHasWeakExports = true; - } - entry->set_n_desc(desc); - - // set n_value ( address this symbol will be at if this executable is loaded at it preferred address ) - entry->set_n_value(this->getAtomLoadAddress(atom)); -} - -void Writer::setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry) -{ - // set n_type - entry->set_n_type(N_UNDF | N_EXT); - - // set n_sect - entry->set_n_sect(0); - - uint16_t desc = 0; - if ( fOptions.outputKind() != Options::kObjectFile ) { - // set n_desc ( high byte is library ordinal, low byte is reference type ) - desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME - try { - uint8_t ordinal = this->ordinalForLibrary(atom->getFile()); - SET_LIBRARY_ORDINAL(desc, ordinal); - } - catch (const char* msg) { - throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath()); - } - } - if ( atom->dontStripName() ) - desc |= REFERENCED_DYNAMICALLY; - // an import proxy is always weak (overridden by definition in .o files) - // so we ask its reader if the exported symbol in its dylib is weak - if ( ( fOptions.outputKind() != Options::kObjectFile) && atom->getFile()->isDefinitionWeak(*atom) ) { - desc |= N_REF_TO_WEAK; - fReferencesWeakImports = true; - } - // set weak_import attribute - if ( atom->getImportWeakness() == ObjectFile::Atom::kWeakImport ) - desc |= N_WEAK_REF; - entry->set_n_desc(desc); - - // set n_value, zero for import proxy and size for tentative definition - entry->set_n_value(atom->getSize()); -} - -void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry) -{ - // set n_type - uint8_t type = N_SECT; - if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit ) - type |= N_PEXT; - entry->set_n_type(type); - - // set n_sect (section number of implementation ) - uint8_t sectIndex = atom->getSection()->getIndex(); - if ( sectIndex == 0 ) { - // see synthesized lable for mach_header needs special section number... - if ( strcmp(atom->getSectionName(), "._mach_header") == 0 ) - sectIndex = 1; - } - entry->set_n_sect(sectIndex); - - // set n_desc - uint16_t desc = 0; - if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) // commons on not weak - desc |= N_WEAK_DEF; - entry->set_n_desc(desc); - - // set n_value ( address this symbol will be at if this executable is loaded at it preferred address ) - entry->set_n_value(this->getAtomLoadAddress(atom)); -} - - -void Writer::setNlistRange(std::vector& atoms, uint32_t startIndex, uint32_t count) -{ - macho_nlist* entry = &fSymbolTable[startIndex]; - for (uint32_t i=0; i < count; ++i, ++entry) { - ObjectFile::Atom* atom = atoms[i]; - entry->set_n_strx(this->fStringsAtom->add(atom->getName())); - if ( &atoms == &fExportedAtoms ) { - this->setExportNlist(atom, entry); - } - else if ( &atoms == &fImportedAtoms ) { - this->setImportNlist(atom, entry); - } - else { - this->setLocalNlist(atom, entry); - } - } -} - -void Writer::buildSymbolTable() -{ - fSymbolTableStabsStartIndex = 0; - fSymbolTableStabsCount = this->collectStabs(); - fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount; - fSymbolTableLocalCount = fLocalSymbolAtoms.size(); - fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount; - fSymbolTableExportCount = fExportedAtoms.size(); - fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount; - fSymbolTableImportCount = fImportedAtoms.size(); - - // allocate symbol table - fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount; - fSymbolTable = new macho_nlist[fSymbolTableCount]; - - // fill in symbol table and string pool (do stabs last so strings are at end of pool) - setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fSymbolTableLocalCount); - setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount); - setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount); - addStabs(fSymbolTableStabsStartIndex, fSymbolTableStabsCount); -} - - - -bool Writer::shouldExport(ObjectFile::Atom& atom) -{ - switch ( atom.getScope() ) { - case ObjectFile::Atom::scopeGlobal: - return true; - case ObjectFile::Atom::scopeLinkageUnit: - return ( fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) ); - default: - return false; - } -} - -void Writer::collectExportedAndImportedAndLocalAtoms() -{ - const int atomCount = fAllAtoms->size(); - for (int i=0; i < atomCount; ++i) { - ObjectFile::Atom* atom = (*fAllAtoms)[i]; - // only named atoms go in symbol table - if ( atom->getName() != NULL ) { - // put atom into correct bucket: imports, exports, locals - //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName()); - if ( atom->isImportProxy() || ((fOptions.outputKind() == Options::kObjectFile) && (strcmp(atom->getSectionName(), "__common") == 0)) ) - fImportedAtoms.push_back(atom); - else if ( this->shouldExport(*atom) ) - fExportedAtoms.push_back(atom); - else if ( !fOptions.stripLocalSymbols() ) - fLocalSymbolAtoms.push_back(atom); - } - } - - // sort exported atoms by name - std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter()); -} - - -bool Writer::stabChunkCompare(const struct StabChunks& lhs, const struct StabChunks& rhs) -{ - if ( lhs.fReader != rhs.fReader ) { - return lhs.fReaderOrder < rhs.fReaderOrder; - } - return lhs.fOrderInReader < rhs.fOrderInReader; -} - -unsigned int Writer::collectStabs() -{ - unsigned int count = 0; - - // collect all stabs chunks - std::set seenReaders; - std::map readerOrdinals; - const int atomCount = fAllAtoms->size(); - for (int i=0; i < atomCount; ++i) { - ObjectFile::Atom* atom = (*fAllAtoms)[i]; - ObjectFile::Reader* atomsReader = atom->getFile(); - unsigned int readerOrder = 0; - if ( atomsReader != NULL ) { - std::map::iterator pos = readerOrdinals.find(atomsReader); - if ( pos == readerOrdinals.end() ) { - readerOrder = readerOrdinals.size(); - readerOrdinals[atomsReader] = readerOrder; - std::vector* readerStabs = atomsReader->getStabsDebugInfo(); - if ( readerStabs != NULL ) { - StabChunks chunk; - chunk.fAtom = NULL; - chunk.fReader = atomsReader; - chunk.fReaderOrder = readerOrder; - chunk.fOrderInReader = 0; - chunk.fStabs = readerStabs; - fStabChunks.push_back(chunk); - count += readerStabs->size() + 1; // extra one is for trailing N_SO - } - } - else { - readerOrder = pos->second; - } - } - std::vector* atomStabs = atom->getStabsDebugInfo(); - if ( atomStabs != NULL ) { - StabChunks chunk; - chunk.fAtom = atom; - chunk.fReader = atomsReader; - chunk.fReaderOrder = readerOrder; - chunk.fOrderInReader = atom->getSortOrder(); - chunk.fStabs = atomStabs; - fStabChunks.push_back(chunk); - count += atomStabs->size(); - } - } - - // sort stabs: group by .o file - std::sort(fStabChunks.begin(), fStabChunks.end(), stabChunkCompare); - - //fprintf(stderr, "Sorted stabs:\n"); - //for (std::vector::iterator it=fStabChunks.begin(); it != fStabChunks.end(); it++) { - // ObjectFile::Atom* atom = (*it).fAtom; - // if ( atom != NULL ) - // fprintf(stderr, "\t%s\n", (*it).fAtom->getDisplayName()); - // else - // fprintf(stderr, "\t%s\n", (*it).fReader->getPath()); - //} - - return count; -} - -macho_uintptr_t Writer::valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom) -{ - 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 offset in the atom to an address - if ( atom != NULL ) - return getAtomLoadAddress(atom) + stab.atomOffset; - } - return stab.atomOffset; -} - - -void Writer::addStabs(uint32_t startIndex, uint32_t count) -{ - macho_nlist* entry = &fSymbolTable[startIndex]; - const int chunkCount = fStabChunks.size(); - for (int i=0; i < chunkCount; ++i ) { - const StabChunks& chunk = fStabChunks[i]; - const int stabCount = chunk.fStabs->size(); - for (int j=0; j < stabCount; ++j ) { - const ObjectFile::StabsInfo& stab = (*chunk.fStabs)[j]; - entry->set_n_type(stab.type); - entry->set_n_sect(stab.other); - entry->set_n_desc(stab.desc); - entry->set_n_value(valueForStab(stab, chunk.fAtom)); - entry->set_n_strx(this->fStringsAtom->add(stab.string)); - ++entry; - } - if ( (i == chunkCount-1) || (fStabChunks[i+1].fReader != chunk.fReader) ) { - // need to add empty SO at end of each file - entry->set_n_type(N_SO); - entry->set_n_sect(1); - entry->set_n_desc(0); - entry->set_n_value(0); - entry->set_n_strx(this->fStringsAtom->emptyString()); - ++entry; - } - } -} - - - -uint32_t Writer::symbolIndex(ObjectFile::Atom& atom) -{ - // search imports - int i = 0; - for(std::vector::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) { - if ( &atom == *it ) - return i + fSymbolTableImportStartIndex; - ++i; - } - - // search locals - i = 0; - for(std::vector::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) { - if ( &atom == *it ) - return i + fSymbolTableLocalStartIndex; - ++i; - } - - // search exports - i = 0; - for(std::vector::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) { - if ( &atom == *it ) - return i + fSymbolTableExportStartIndex; - ++i; - } - - fprintf(stderr, "symbolIndex(%s)\n", atom.getDisplayName()); - fprintf(stderr, "from %s\n", atom.getFile()->getPath()); - throw "atom not found"; -} - -void Writer::buildFixups() -{ - if ( fOptions.outputKind() == Options::kObjectFile ) - this->buildObjectFileFixups(); - else - this->buildExecutableFixups(); -} - -uint32_t Writer::addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref) -{ - ObjectFile::Atom& target = ref->getTarget(); - bool isExtern = target.isImportProxy() || ( strcmp(target.getSectionName(), "__common") == 0 ); - uint32_t symbolIndex = 0; - if ( isExtern ) - symbolIndex = this->symbolIndex(target); - uint32_t sectionNum = target.getSection()->getIndex(); - uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset(); - macho_relocation_info reloc1; - macho_relocation_info reloc2; - macho_scattered_relocation_info* sreloc1 = (macho_scattered_relocation_info*)&reloc1; - macho_scattered_relocation_info* sreloc2 = (macho_scattered_relocation_info*)&reloc2; - - switch ( ref->getKind() ) { - case ObjectFile::Reference::noFixUp: - return 0; - - case ObjectFile::Reference::pointer: - reloc1.set_r_address(address); - if ( isExtern ) - reloc1.set_r_symbolnum(symbolIndex); - else - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(macho_relocation_info::pointer_length); - reloc1.set_r_extern(isExtern); - reloc1.set_r_type(GENERIC_RELOC_VANILLA); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 1; - - case ObjectFile::Reference::ppcFixupBranch24: - if ( (ref->getTargetOffset() == 0) || isExtern ) { - reloc1.set_r_address(address); - if ( isExtern ) - reloc1.set_r_symbolnum(symbolIndex); - else - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(true); - reloc1.set_r_length(2); - reloc1.set_r_type(PPC_RELOC_BR24); - reloc1.set_r_extern(isExtern); - } - else { - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(true); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_BR24); - sreloc1->set_r_address(address); - sreloc1->set_r_value(target.getAddress()); - } - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 1; - - case ObjectFile::Reference::ppcFixupBranch14: - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(true); - reloc1.set_r_length(2); - reloc1.set_r_extern(false); - reloc1.set_r_type(PPC_RELOC_BR14); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 1; - - case ObjectFile::Reference::ppcFixupPicBaseLow14: - case ObjectFile::Reference::ppcFixupPicBaseLow16: - { - macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset(); - macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset(); - uint32_t overflow = 0; - if ( ((toAddr-fromAddr) & 0x00008000) != 0 ) - overflow = 1; - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - if ( ref->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16 ) - sreloc1->set_r_type(PPC_RELOC_LO16_SECTDIFF); - else - sreloc1->set_r_type(PPC_RELOC_LO14_SECTDIFF); - sreloc1->set_r_address(address); - sreloc1->set_r_value(target.getAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address(((toAddr-fromAddr) >> 16)); - sreloc2->set_r_value(fromAddr); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc2); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 2; - } - - case ObjectFile::Reference::ppcFixupPicBaseHigh16: - { - macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset(); - macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset(); - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF); - sreloc1->set_r_address(address); - sreloc1->set_r_value(target.getAddress()); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(2); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF); - sreloc2->set_r_value(fromAddr); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc2); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 2; - } - - case ObjectFile::Reference::ppcFixupAbsLow14: - case ObjectFile::Reference::ppcFixupAbsLow16: - { - macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset(); - if ( (ref->getTargetOffset() == 0) || isExtern ) { - reloc1.set_r_address(address); - if ( isExtern ) - reloc1.set_r_symbolnum(symbolIndex); - else - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(isExtern); - if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 ) - reloc1.set_r_type(PPC_RELOC_LO16); - else - reloc1.set_r_type(PPC_RELOC_LO14); - } - else { - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 ) - sreloc1->set_r_type(PPC_RELOC_LO16); - else - sreloc1->set_r_type(PPC_RELOC_LO14); - sreloc1->set_r_address(address); - sreloc1->set_r_value(target.getAddress()); - } - if ( isExtern ) - reloc2.set_r_address(ref->getTargetOffset() >> 16); - else - reloc2.set_r_address(toAddr >> 16); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc2); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 2; - } - - case ObjectFile::Reference::ppcFixupAbsHigh16: - { - macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset(); - if ( (ref->getTargetOffset() == 0) || isExtern ) { - reloc1.set_r_address(address); - if ( isExtern ) - reloc1.set_r_symbolnum(symbolIndex); - else - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(isExtern); - reloc1.set_r_type(PPC_RELOC_HI16); - } - else { - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HI16); - sreloc1->set_r_address(address); - sreloc1->set_r_value(target.getAddress()); - } - if ( isExtern ) - reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF); - else - reloc2.set_r_address(toAddr & 0xFFFF); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc2); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 2; - } - - case ObjectFile::Reference::ppcFixupAbsHigh16AddLow: - { - macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset(); - uint32_t overflow = 0; - if ( (toAddr & 0x00008000) != 0 ) - overflow = 0x10000; - if ( (ref->getTargetOffset() == 0) || isExtern ) { - reloc1.set_r_address(address); - if ( isExtern ) - reloc1.set_r_symbolnum(symbolIndex); - else - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(2); - reloc1.set_r_extern(isExtern); - reloc1.set_r_type(PPC_RELOC_HA16); - } - else { - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - sreloc1->set_r_length(2); - sreloc1->set_r_type(PPC_RELOC_HA16); - sreloc1->set_r_address(address); - sreloc1->set_r_value(target.getAddress()); - } - if ( isExtern ) - reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF); - else - reloc2.set_r_address(toAddr & 0xFFFF); - reloc2.set_r_symbolnum(0); - reloc2.set_r_pcrel(false); - reloc2.set_r_length(2); - reloc2.set_r_extern(false); - reloc2.set_r_type(PPC_RELOC_PAIR); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc2); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 2; - } - - case ObjectFile::Reference::pointer32Difference: - case ObjectFile::Reference::pointer64Difference: - { - macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset(); - macho_uintptr_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset(); - sreloc1->set_r_scattered(true); - sreloc1->set_r_pcrel(false); - if ( ref->getKind() == ObjectFile::Reference::pointer64Difference ) - sreloc1->set_r_length(3); - else - sreloc1->set_r_length(2); - if ( ref->getTargetOffset() != 0 ) - sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF); - else - sreloc1->set_r_type(PPC_RELOC_SECTDIFF); - sreloc1->set_r_address(address); - sreloc1->set_r_value(toAddr); - sreloc2->set_r_scattered(true); - sreloc2->set_r_pcrel(false); - sreloc2->set_r_length(macho_relocation_info::pointer_length); - sreloc2->set_r_type(PPC_RELOC_PAIR); - sreloc2->set_r_address(0); - sreloc2->set_r_value(fromAddr); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc2); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 2; - } - - case ObjectFile::Reference::x86FixupBranch32: - reloc1.set_r_address(address); - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(true); - reloc1.set_r_length(2); - reloc1.set_r_extern(false); - reloc1.set_r_type(GENERIC_RELOC_VANILLA); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - return 1; - - } - return 0; -} - - -void Writer::buildObjectFileFixups() -{ - uint32_t relocIndex = 0; - std::vector& segmentInfos = fSegmentInfos; - const int segCount = segmentInfos.size(); - for(int i=0; i < segCount; ++i) { - SegmentInfo* curSegment = segmentInfos[i]; - std::vector& sectionInfos = curSegment->fSections; - const int sectionCount = sectionInfos.size(); - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - std::vector& sectionAtoms = curSection->fAtoms; - if ( ! curSection->fAllZeroFill ) { - if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) - curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size(); - curSection->fRelocOffset = relocIndex; - const int atomCount = sectionAtoms.size(); - for (int k=0; k < atomCount; ++k) { - ObjectFile::Atom* atom = sectionAtoms[k]; - std::vector& refs = atom->getReferences(); - const int refCount = refs.size(); - for (int l=0; l < refCount; ++l) { - ObjectFile::Reference* ref = refs[l]; - if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) { - uint32_t offsetInSection = atom->getSectionOffset(); - uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t); - uint32_t undefinedSymbolIndex = this->symbolIndex(ref->getTarget()); - uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset; - IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex }; - //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize()); - fIndirectSymbolTable.push_back(entry); - if ( curSection->fAllLazyPointers ) { - ObjectFile::Atom& target = ref->getTarget(); - ObjectFile::Atom& fromTarget = ref->getFromTarget(); - if ( &fromTarget == NULL ) { - fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName()); - } - else { - bool isExtern = target.isImportProxy(); - uint32_t symbolIndex = 0; - if ( isExtern ) - symbolIndex = this->symbolIndex(target); - uint32_t sectionNum = target.getSection()->getIndex(); - uint32_t address = atom->getSectionOffset(); - macho_relocation_info reloc1; - reloc1.set_r_address(address); - if ( isExtern ) - reloc1.set_r_symbolnum(symbolIndex); - else - reloc1.set_r_symbolnum(sectionNum); - reloc1.set_r_pcrel(false); - reloc1.set_r_length(macho_relocation_info::pointer_length); - reloc1.set_r_extern(isExtern); - reloc1.set_r_type(GENERIC_RELOC_VANILLA); - fInternalRelocs.insert(fInternalRelocs.begin(), reloc1); - ++relocIndex; - } - } - } - else { - relocIndex += this->addRelocs(atom, ref); - } - } - } - curSection->fRelocCount = relocIndex - curSection->fRelocOffset; - } - } - } - - // now reverse reloc entries - for(int i=0; i < segCount; ++i) { - SegmentInfo* curSegment = segmentInfos[i]; - std::vector& sectionInfos = curSegment->fSections; - const int sectionCount = sectionInfos.size(); - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount; - } - } - -} - - -void Writer::buildExecutableFixups() -{ - const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable); - std::vector& segmentInfos = fSegmentInfos; - const int segCount = segmentInfos.size(); - for(int i=0; i < segCount; ++i) { - SegmentInfo* curSegment = segmentInfos[i]; - std::vector& sectionInfos = curSegment->fSections; - const int sectionCount = sectionInfos.size(); - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - std::vector& sectionAtoms = curSection->fAtoms; - if ( ! curSection->fAllZeroFill ) { - if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) - curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size(); - const int atomCount = sectionAtoms.size(); - for (int k=0; k < atomCount; ++k) { - ObjectFile::Atom* atom = sectionAtoms[k]; - std::vector& refs = atom->getReferences(); - const int refCount = refs.size(); - //printf("atom %s has %d references\n", atom->getDisplayName(), refCount); - for (int l=0; l < refCount; ++l) { - ObjectFile::Reference* ref = refs[l]; - if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) { - // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol - if ( atom->getSize() != sizeof(macho_uintptr_t) ) { - printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath()); - } - uint32_t offsetInSection = atom->getSectionOffset(); - uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t); - uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL; - //fprintf(stderr,"indirect pointer atom %p %s section offset = %d\n", atom, atom->getDisplayName(), offsetInSection); - if ( ref->getTarget().isImportProxy() - || ref->getTarget().isWeakDefinition() - || (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName())) - || (fOptions.nameSpace() == Options::kFlatNameSpace) - || (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) { - undefinedSymbolIndex = this->symbolIndex(ref->getTarget()); - } - uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset; - IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex }; - //fprintf(stderr,"fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize()); - fIndirectSymbolTable.push_back(entry); - if ( slideable && curSection->fAllLazyPointers ) { - // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides - macho_relocation_info pblaReloc; - SectionInfo* sectInfo = (SectionInfo*)ref->getFromTarget().getSection(); - uint32_t sectionNum = sectInfo->getIndex(); - pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress()); - pblaReloc.set_r_symbolnum(sectionNum); - pblaReloc.set_r_pcrel(false); - pblaReloc.set_r_length(macho_relocation_info::pointer_length); - pblaReloc.set_r_extern(false); - pblaReloc.set_r_type(GENERIC_RELOC_VANILLA); - fInternalRelocs.push_back(pblaReloc); - } - } - else if ( ref->requiresRuntimeFixUp(slideable) ) { - if ( ! atom->getSegment().isContentWritable() ) - throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom->getDisplayName(), atom->getFile()->getPath(), ref->getTarget().getDisplayName()); - if ( ref->getTarget().isImportProxy() ) { - // if import is to antoher dylib, this is encoded as an external relocation - macho_relocation_info externalReloc; - externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress()); - externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget())); - externalReloc.set_r_pcrel(false); - externalReloc.set_r_length(macho_relocation_info::pointer_length); - externalReloc.set_r_extern(true); - externalReloc.set_r_type(GENERIC_RELOC_VANILLA); - fExternalRelocs.push_back(externalReloc); - } - else { - // if this is a dylib/bundle, need fix-up encoded as an internal relocation - macho_relocation_info internalReloc; - SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection(); - uint32_t sectionNum = sectInfo->getIndex(); - // special case _mh_dylib_header and friends which are not in any real section - if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) ) - sectionNum = 1; - internalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress()); - internalReloc.set_r_symbolnum(sectionNum); - internalReloc.set_r_pcrel(false); - internalReloc.set_r_length(macho_relocation_info::pointer_length); - internalReloc.set_r_extern(false); - internalReloc.set_r_type(GENERIC_RELOC_VANILLA); - fInternalRelocs.push_back(internalReloc); - } - } - } - } - } - } - } -} - -class ContentWriter : public ObjectFile::ContentWriter -{ -public: - ContentWriter(int fd, uint64_t fileOffset) : fFileDescriptor(fd), fFileOffset(fileOffset) {} - virtual void write(uint64_t atomOffset, const void* buffer, uint64_t size) { - ::pwrite(fFileDescriptor, buffer, size, fFileOffset+atomOffset); - } -private: - int fFileDescriptor; - uint64_t fFileOffset; -}; - - -void Writer::writeAtoms() -{ - const bool requireAllFixUps = (fOptions.outputKind() != Options::kObjectFile); - - std::vector& segmentInfos = fSegmentInfos; - const int segCount = segmentInfos.size(); - for(int i=0; i < segCount; ++i) { - SegmentInfo* curSegment = segmentInfos[i]; - bool isText = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0); - std::vector& sectionInfos = curSegment->fSections; - const int sectionCount = sectionInfos.size(); - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - std::vector& sectionAtoms = curSection->fAtoms; - //printf("writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName); - if ( ! curSection->fAllZeroFill ) { - const int atomCount = sectionAtoms.size(); - uint32_t end = curSection->fFileOffset; - for (int k=0; k < atomCount; ++k) { - ObjectFile::Atom* atom = sectionAtoms[k]; - if ( !atom->isImportProxy() ) { - uint32_t offset = curSection->fFileOffset + atom->getSectionOffset(); - if ( isText && (offset != end) ) { - // fill gaps with no-ops - #if defined(ARCH_PPC) || defined(ARCH_PPC64) - uint32_t ppcNop; - OSWriteBigInt32(&ppcNop, 0, 0x60000000); - for (uint32_t p=end; p < offset; p += 4) - ::pwrite(fFileDescriptor, &ppcNop, 4, p); - #else defined(ARCH_I386) - uint8_t x86Nop = 0x90; - for (uint32_t p=end; p < offset; ++p) - ::pwrite(fFileDescriptor, &x86Nop, 1, p); - #endif - } - end = offset+atom->getSize(); - //fprintf(stderr, "writing 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName()); - ContentWriter writer(fFileDescriptor, offset); - atom->writeContent(requireAllFixUps, writer); - } - } - } - } - } -} - - -void Writer::partitionIntoSections() -{ - const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile); - - // for every atom, set its sectionInfo object and section offset - // build up fSegmentInfos along the way - ObjectFile::Section* curSection = NULL; - SectionInfo* currentSectionInfo = NULL; - SegmentInfo* currentSegmentInfo = NULL; - unsigned int sectionIndex = 1; - for (unsigned int i=0; i < fAllAtoms->size(); ++i) { - ObjectFile::Atom* atom = (*fAllAtoms)[i]; - if ( atom->getSection() != curSection ) { - if ( oneSegmentCommand ) { - if ( currentSegmentInfo == NULL ) { - currentSegmentInfo = new SegmentInfo(); - currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; - currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; - this->fSegmentInfos.push_back(currentSegmentInfo); - } - currentSectionInfo = new SectionInfo(); - strcpy(currentSectionInfo->fSectionName, atom->getSectionName()); - strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName()); - currentSectionInfo->fAlignment = atom->getAlignment(); - currentSectionInfo->fAllZeroFill = atom->isZeroFill(); - currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.'); - if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections ) - currentSectionInfo->setIndex(sectionIndex++); - currentSegmentInfo->fSections.push_back(currentSectionInfo); - } - else { - if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) { - currentSegmentInfo = new SegmentInfo(); - strcpy(currentSegmentInfo->fName, atom->getSegment().getName()); - uint32_t initprot = 0; - if ( atom->getSegment().isContentReadable() ) - initprot |= VM_PROT_READ; - if ( atom->getSegment().isContentWritable() ) - initprot |= VM_PROT_WRITE; - if ( atom->getSegment().isContentExecutable() ) - initprot |= VM_PROT_EXECUTE; - currentSegmentInfo->fInitProtection = initprot; - if ( initprot == 0 ) - currentSegmentInfo->fMaxProtection = 0; // pagezero should have maxprot==initprot==0 - else - currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; - currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress(); - currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress(); - this->fSegmentInfos.push_back(currentSegmentInfo); - } - currentSectionInfo = new SectionInfo(); - strcpy(currentSectionInfo->fSectionName, atom->getSectionName()); - strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName()); - currentSectionInfo->fAlignment = atom->getAlignment(); - // check for -sectalign override - std::vector& alignmentOverrides = fOptions.sectionAlignments(); - for(std::vector::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) { - if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) ) - currentSectionInfo->fAlignment = it->alignment; - } - currentSectionInfo->fAllZeroFill = atom->isZeroFill(); - currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.'); - if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections ) - currentSectionInfo->setIndex(sectionIndex++); - currentSegmentInfo->fSections.push_back(currentSectionInfo); - } - if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) { - fLoadCommandsSection = currentSectionInfo; - fLoadCommandsSegment = currentSegmentInfo; - } - if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) ) - currentSectionInfo->fAllLazyPointers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) ) - currentSectionInfo->fAllLazyPointers = true; - if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) ) - currentSectionInfo->fAllNonLazyPointers = true; - curSection = atom->getSection(); - } - // any non-zero fill atoms make whole section marked not-zero-fill - if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() ) - currentSectionInfo->fAllZeroFill = false; - // change section object to be Writer's SectionInfo object - atom->setSection(currentSectionInfo); - // section alignment is that of a contained atom with the greatest alignment - uint8_t atomAlign = atom->getAlignment(); - if ( currentSectionInfo->fAlignment < atomAlign ) - currentSectionInfo->fAlignment = atomAlign; - // calculate section offset for this atom - uint64_t offset = currentSectionInfo->fSize; - uint64_t alignment = 1 << atomAlign; - offset = ( (offset+alignment-1) & (-alignment) ); - atom->setSectionOffset(offset); - currentSectionInfo->fSize = offset + atom->getSize(); - // add atom to section vector - currentSectionInfo->fAtoms.push_back(atom); - } -} - - -struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; }; -class TargetAndOffsetComparor -{ -public: - bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const - { - if ( left.atom != right.atom ) - return ( left.atom < right.atom ); - return ( left.offset < right.offset ); - } -}; - -// -// PowerPC can do PC relative branches as far as +/-16MB. -// If a branch target is >16MB then we insert one or more -// "branch islands" between the branch and its target that -// allows island hoping to the target. -// -// Branch Island Algorithm -// -// If the __TEXT segment < 16MB, then no branch islands needed -// Otherwise, every 15MB into the __TEXT segment is region is -// added which can contain branch islands. Every out of range -// bl instruction is checked. If it crosses a region, an island -// is added to that region with the same target and the bl is -// adjusted to target the island instead. -// -// In theory, if too many islands are added to one region, it -// could grow the __TEXT enough that other previously in-range -// bl branches could be pushed out of range. We reduce the -// probability this could happen by placing the ranges every -// 15MB which means the region would have to be 1MB (256K islands) -// before any branches could be pushed out of range. -// -bool Writer::addBranchIslands() -{ - bool result = false; -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - // Can only possibly need branch islands if __TEXT segment > 16M - if ( fLoadCommandsSegment->fSize > 16000000 ) { - const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB in __text section - SectionInfo* textSection = NULL; - for (std::vector::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) { - if ( strcmp((*it)->fSectionName, "__text") == 0 ) - textSection = *it; - } - const int kIslandRegionsCount = textSection->fSize / kBetweenRegions; - typedef std::map AtomToIsland; - AtomToIsland regionsMap[kIslandRegionsCount]; - std::vector regionsIslands[kIslandRegionsCount]; - unsigned int islandCount = 0; - - // create islands for branch references that are out of range - for (std::vector::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) { - ObjectFile::Atom* atom = *it; - std::vector& references = atom->getReferences(); - for (std::vector::iterator rit=references.begin(); rit != references.end(); rit++) { - ObjectFile::Reference* ref = *rit; - if ( ref->getKind() == ObjectFile::Reference::ppcFixupBranch24 ) { - ObjectFile::Atom& target = ref->getTarget(); - int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset(); - int64_t dstAddr = target.getAddress() + ref->getTargetOffset(); - int64_t displacement = dstAddr - srcAddr; - const int64_t kFifteenMegLimit = kBetweenRegions; - if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) { - for (int i=0; i < kIslandRegionsCount; ++i) { - AtomToIsland* region=®ionsMap[i]; - int64_t islandRegionAddr = kBetweenRegions * (i+1); - if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr)) - ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) { - TargetAndOffset islandTarget = { &target, ref->getTargetOffset() }; - AtomToIsland::iterator pos = region->find(islandTarget); - if ( pos == region->end() ) { - BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, target, ref->getTargetOffset()); - (*region)[islandTarget] = island; - regionsIslands[i].push_back(island); - ++islandCount; - ref->setTarget(*island, 0); - } - else { - ref->setTarget(*(pos->second), 0); - } - } - } - } - } - } - } - - // insert islands into __text section and adjust section offsets - if ( islandCount > 0 ) { - std::vector newAtomList; - newAtomList.reserve(textSection->fAtoms.size()+islandCount); - uint64_t islandRegionAddr = kBetweenRegions; - int regionIndex = 0; - uint64_t sectionOffset = 0; - for (std::vector::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) { - ObjectFile::Atom* atom = *it; - newAtomList.push_back(atom); - if ( atom->getAddress() > islandRegionAddr ) { - std::vector* regionIslands = ®ionsIslands[regionIndex]; - for (std::vector::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) { - ObjectFile::Atom* islandAtom = *rit; - newAtomList.push_back(islandAtom); - islandAtom->setSection(textSection); - uint64_t alignment = 1 << (islandAtom->getAlignment()); - sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); - islandAtom->setSectionOffset(sectionOffset); - sectionOffset += islandAtom->getSize(); - } - ++regionIndex; - islandRegionAddr += kBetweenRegions; - } - uint64_t alignment = 1 << (atom->getAlignment()); - sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); - atom->setSectionOffset(sectionOffset); - sectionOffset += atom->getSize(); - } - textSection->fAtoms = newAtomList; - textSection->fSize = sectionOffset; - result = true; - } - - } -#endif - return result; -} - - -void Writer::adjustLoadCommandsAndPadding() -{ - fSegmentCommands->computeSize(); - - // recompute load command section offsets - uint64_t offset = 0; - std::vector& loadCommandAtoms = fLoadCommandsSection->fAtoms; - const unsigned int atomCount = loadCommandAtoms.size(); - for (unsigned int i=0; i < atomCount; ++i) { - ObjectFile::Atom* atom = loadCommandAtoms[i]; - uint64_t alignment = 1 << atom->getAlignment(); - offset = ( (offset+alignment-1) & (-alignment) ); - atom->setSectionOffset(offset); - offset += atom->getSize(); - fLoadCommandsSection->fSize = offset; - } - - std::vector& sectionInfos = fLoadCommandsSegment->fSections; - const int sectionCount = sectionInfos.size(); - uint64_t paddingSize = 0; - if ( fOptions.outputKind() == Options::kDyld ) { - // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address - uint32_t totalSizeOfHeaderAndLoadCommands = 0; - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - totalSizeOfHeaderAndLoadCommands += curSection->fSize; - if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) - break; - } - paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096); - } - else { - // calculate max padding to keep segment size same, but all free space at end of load commands - uint64_t totalSize = 0; - uint64_t worstCaseAlignmentPadding = 0; - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - totalSize += curSection->fSize; - if ( j != 0 ) // don't count aligment of mach_header which is page-aligned - worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1; - } - uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096)); - // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints - paddingSize = segmentSize - totalSize; - - // if command line requires more padding than this - if ( paddingSize < fOptions.minimumHeaderPad() ) { - int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096; - paddingSize += extraPages * 4096; - } - } - - // adjust atom size and update section size - fHeaderPadding->setSize(paddingSize); - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) - curSection->fSize = paddingSize; - } -} - -// assign file offsets and logical address to all segments -void Writer::assignFileOffsets() -{ - bool haveFixedSegments = false; - uint64_t fileOffset = 0; - uint64_t nextContiguousAddress = 0; - bool baseAddressUsed = false; - std::vector& segmentInfos = fSegmentInfos; - const int segCount = segmentInfos.size(); - for(int i=0; i < segCount; ++i) { - SegmentInfo* curSegment = segmentInfos[i]; - fileOffset = (fileOffset+4095) & (-4096); - curSegment->fFileOffset = fileOffset; - if ( curSegment->fFixedAddress ) { - // segment has fixed address already set - haveFixedSegments = true; - } - else { - // segment uses next address - if ( !baseAddressUsed ) { - baseAddressUsed = true; - if ( fOptions.baseAddress() != 0 ) - nextContiguousAddress = fOptions.baseAddress(); - } - curSegment->fBaseAddress = nextContiguousAddress; - } - uint64_t address = curSegment->fBaseAddress; - std::vector& sectionInfos = curSegment->fSections; - const int sectionCount = sectionInfos.size(); - for(int j=0; j < sectionCount; ++j) { - SectionInfo* curSection = sectionInfos[j]; - uint64_t alignment = 1 << curSection->fAlignment; - fileOffset = ( (fileOffset+alignment-1) & (-alignment) ); - address = ( (address+alignment-1) & (-alignment) ); - curSection->fFileOffset = fileOffset; - curSection->setBaseAddress(address); - //printf("assignFileOffsets(): setBaseAddress(%s, 0x%08llX)\n", curSection->fSectionName, address); - curSegment->fSize = curSection->getBaseAddress() + curSection->fSize - curSegment->fBaseAddress; - if ( (fOptions.outputKind() != Options::kObjectFile) || ! curSection->fVirtualSection ) - address += curSection->fSize; - if ( !curSection->fAllZeroFill ) { - curSegment->fFileSize = curSegment->fSize; - fileOffset += curSection->fSize; - } - } - // page align segment size - curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096); - curSegment->fSize = (curSegment->fSize+4095) & (-4096); - if ( curSegment->fBaseAddress == nextContiguousAddress ) - nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096); - } - - // check for segment overlaps - if ( haveFixedSegments ) { - for(int i=0; i < segCount; ++i) { - SegmentInfo* segment1 = segmentInfos[i]; - for(int j=0; j < segCount; ++j) { - if ( i != j ) { - SegmentInfo* segment2 = segmentInfos[j]; - if ( segment1->fBaseAddress < segment2->fBaseAddress ) { - if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress ) - throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", - segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize); - } - else if ( segment1->fBaseAddress > segment2->fBaseAddress ) { - if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress ) - throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", - segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize); - } - else { - throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)", - segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize); - } - } - } - } - } -} - -void Writer::adjustLinkEditSections() -{ - // link edit content is always in last segment - SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1]; - unsigned int firstLinkEditSectionIndex = 0; - while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 ) - ++firstLinkEditSectionIndex; - - const unsigned int sectionCount = lastSeg->fSections.size(); - uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset; - uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress(); - for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) { - std::vector& atoms = lastSeg->fSections[i]->fAtoms; - const unsigned int atomCount = atoms.size(); - uint64_t sectionOffset = 0; - lastSeg->fSections[i]->fFileOffset = fileOffset; - lastSeg->fSections[i]->setBaseAddress(address); - for (unsigned int j=0; j < atomCount; ++j) { - ObjectFile::Atom* atom = atoms[j]; - uint64_t alignment = 1 << atom->getAlignment(); - sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) ); - atom->setSectionOffset(sectionOffset); - sectionOffset += atom->getSize(); - } - lastSeg->fSections[i]->fSize = sectionOffset; - fileOffset += sectionOffset; - address += sectionOffset; - } - if ( fOptions.outputKind() == Options::kObjectFile ) { - //lastSeg->fBaseAddress = 0; - //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]-> - //lastSeg->fFileOffset = 0; - //lastSeg->fFileSize = - } - else { - lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset; - lastSeg->fSize = (address - lastSeg->fBaseAddress+4095) & (-4096); - } -} - - -ObjectFile::Atom::Scope MachHeaderAtom::getScope() const -{ - switch ( fWriter.fOptions.outputKind() ) { - case Options::kDynamicExecutable: - case Options::kStaticExecutable: - return ObjectFile::Atom::scopeGlobal; - case Options::kDynamicLibrary: - case Options::kDynamicBundle: - case Options::kDyld: - case Options::kObjectFile: - return ObjectFile::Atom::scopeLinkageUnit; - } - throw "unknown header type"; -} - -bool MachHeaderAtom::dontStripName() const -{ - switch ( fWriter.fOptions.outputKind() ) { - case Options::kDynamicExecutable: - case Options::kStaticExecutable: - return true; - case Options::kDynamicLibrary: - case Options::kDynamicBundle: - case Options::kDyld: - case Options::kObjectFile: - return false; - } - throw "unknown header type"; -} - -const char* MachHeaderAtom::getName() const -{ - switch ( fWriter.fOptions.outputKind() ) { - case Options::kDynamicExecutable: - case Options::kStaticExecutable: - return "__mh_execute_header"; - case Options::kDynamicLibrary: - return "__mh_dylib_header"; - case Options::kDynamicBundle: - return "__mh_bundle_header"; - case Options::kObjectFile: - return NULL; - case Options::kDyld: - return "__mh_dylinker_header"; - } - throw "unknown header type"; -} - -const char* MachHeaderAtom::getDisplayName() const -{ - switch ( fWriter.fOptions.outputKind() ) { - case Options::kDynamicExecutable: - case Options::kStaticExecutable: - case Options::kDynamicLibrary: - case Options::kDynamicBundle: - case Options::kDyld: - return this->getName(); - case Options::kObjectFile: - return "mach header"; - } - throw "unknown header type"; -} - -uint64_t MachHeaderAtom::getSize() const -{ - return macho_header::size; -} - -void MachHeaderAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - macho_header mh; - - // get file type - uint32_t fileType = 0; - switch ( fWriter.fOptions.outputKind() ) { - case Options::kDynamicExecutable: - case Options::kStaticExecutable: - fileType = MH_EXECUTE; - break; - case Options::kDynamicLibrary: - fileType = MH_DYLIB; - break; - case Options::kDynamicBundle: - fileType = MH_BUNDLE; - break; - case Options::kObjectFile: - fileType = MH_OBJECT; - break; - case Options::kDyld: - fileType = MH_DYLINKER; - break; - } - - // get flags - uint32_t flags = 0; - if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) { - flags = MH_SUBSECTIONS_VIA_SYMBOLS; - } - else { - flags = MH_DYLDLINK; - if ( fWriter.fOptions.bindAtLoad() ) - flags |= MH_BINDATLOAD; - switch ( fWriter.fOptions.nameSpace() ) { - case Options::kTwoLevelNameSpace: - flags |= MH_TWOLEVEL | MH_NOUNDEFS; - break; - case Options::kFlatNameSpace: - break; - case Options::kForceFlatNameSpace: - flags |= MH_FORCE_FLAT; - break; - } - if ( fWriter.fHasWeakExports ) - flags |= MH_WEAK_DEFINES; - if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports ) - flags |= MH_BINDS_TO_WEAK; - } - - // get commands info - uint32_t commandsSize = 0; - uint32_t commandsCount = 0; - - std::vector& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms; - const unsigned int atomCount = loadCommandAtoms.size(); - for (unsigned int i=0; i < atomCount; ++i) { - ObjectFile::Atom* atom = loadCommandAtoms[i]; - commandsSize += atom->getSize(); - // segment and symbol table atoms can contain more than one load command - if ( atom == fWriter.fSegmentCommands ) - commandsCount += fWriter.fSegmentCommands->commandCount(); - else if ( atom == fWriter.fSymbolTableCommands ) - commandsCount += 2; - else - ++commandsCount; - } - - // fill out mach_header - mh.set_magic(macho_header::magic_value); - mh.set_cputype(fWriter.fOptions.architecture()); -#if defined(ARCH_PPC) || defined(ARCH_PPC64) - mh.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL); -#elif defined(ARCH_I386) - mh.set_cpusubtype(CPU_SUBTYPE_I386_ALL); -#else - #error unknown architecture -#endif - mh.set_filetype(fileType); - mh.set_ncmds(commandsCount); - mh.set_sizeofcmds(commandsSize); - mh.set_flags(flags); - mh.set_reserved(); - - // write it - writer.write(0, &mh, macho_header::size); -} - - -CustomStackAtom::CustomStackAtom(Writer& writer) - : WriterAtom(writer, fgStackSegment) -{ -#if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386) - // stack grows down for these architectures - fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize()); -#else - #error unknown architecture -#endif -} - - -void SegmentLoadCommandsAtom::computeSize() -{ - uint64_t size = 0; - std::vector& segmentInfos = fWriter.fSegmentInfos; - const int segCount = segmentInfos.size(); - for(int i=0; i < segCount; ++i) { - size += macho_segment_command::size; - std::vector& sectionInfos = segmentInfos[i]->fSections; - const int sectionCount = sectionInfos.size(); - for(int j=0; j < sectionCount; ++j) { - if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection ) - size += macho_section::content_size; - } - } - fSize = size; - fCommandCount = segCount; -} - - - -void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile ); - bzero(buffer, fSize); - uint8_t* p = buffer; - std::vector& segmentInfos = fWriter.fSegmentInfos; - const int segCount = segmentInfos.size(); - for(int i=0; i < segCount; ++i) { - Writer::SegmentInfo* segInfo = segmentInfos[i]; - const int sectionCount = segInfo->fSections.size(); - macho_segment_command* cmd = (macho_segment_command*)p; - cmd->set_cmd(macho_segment_command::command); - cmd->set_segname(segInfo->fName); - cmd->set_vmaddr(segInfo->fBaseAddress); - cmd->set_vmsize(segInfo->fSize); - cmd->set_fileoff(segInfo->fFileOffset); - cmd->set_filesize(segInfo->fFileSize); - cmd->set_maxprot(segInfo->fMaxProtection); - cmd->set_initprot(segInfo->fInitProtection); - // add sections array - macho_section* const sections = (macho_section*)&p[macho_segment_command::size]; - unsigned int sectionsEmitted = 0; - for (int j=0; j < sectionCount; ++j) { - Writer::SectionInfo* sectInfo = segInfo->fSections[j]; - if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) { - macho_section* sect = §ions[sectionsEmitted++]; - if ( oneSegment ) { - // .o files have weird segment range - if ( sectionsEmitted == 1 ) { - cmd->set_vmaddr(sectInfo->getBaseAddress()); - cmd->set_fileoff(sectInfo->fFileOffset); - cmd->set_filesize(segInfo->fFileSize-sectInfo->fFileOffset); - } - cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize); - } - sect->set_sectname(sectInfo->fSectionName); - sect->set_segname(sectInfo->fSegmentName); - sect->set_addr(sectInfo->getBaseAddress()); - sect->set_size(sectInfo->fSize); - sect->set_offset(sectInfo->fFileOffset); - sect->set_align(sectInfo->fAlignment); - if ( sectInfo->fRelocCount != 0 ) { - sect->set_reloff(sectInfo->fRelocOffset * macho_relocation_info::size + fWriter.fLocalRelocationsAtom->getFileOffset()); - sect->set_nreloc(sectInfo->fRelocCount); - } - if ( sectInfo->fAllZeroFill ) { - sect->set_flags(S_ZEROFILL); - } - else if ( sectInfo->fAllLazyPointers ) { - sect->set_flags(S_LAZY_SYMBOL_POINTERS); - sect->set_reserved1(sectInfo->fIndirectSymbolOffset); - } - else if ( sectInfo->fAllNonLazyPointers ) { - sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS); - sect->set_reserved1(sectInfo->fIndirectSymbolOffset); - } - else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) { - sect->set_flags(S_MOD_INIT_FUNC_POINTERS); - } - else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) { - sect->set_flags(S_MOD_TERM_FUNC_POINTERS); - } - else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) { - sect->set_flags(S_COALESCED); - } - } - } - p = &p[macho_segment_command::size + sectionsEmitted*macho_section::content_size]; - cmd->set_cmdsize(macho_segment_command::size + sectionsEmitted*macho_section::content_size); - cmd->set_nsects(sectionsEmitted); - } - writer.write(0, buffer, size); -} - - -SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer& writer) - : WriterAtom(writer, fgTextSegment) -{ - bzero(&fSymbolTable, macho_symtab_command::size); - bzero(&fDynamicSymbolTable, macho_dysymtab_command::size); - writer.fSymbolTableCommands = this; -} - -uint64_t SymbolTableLoadCommandsAtom::getSize() const -{ - return macho_symtab_command::size + macho_dysymtab_command::size; -} - -void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - // build LC_DYSYMTAB command - macho_symtab_command symbolTableCmd; - bzero(&symbolTableCmd, macho_symtab_command::size); - symbolTableCmd.set_cmd(LC_SYMTAB); - symbolTableCmd.set_cmdsize(macho_symtab_command::size); - symbolTableCmd.set_nsyms(fWriter.fSymbolTableCount); - symbolTableCmd.set_symoff(fWriter.fSymbolTableAtom->getFileOffset()); - symbolTableCmd.set_stroff(fWriter.fStringsAtom->getFileOffset()); - symbolTableCmd.set_strsize(fWriter.fStringsAtom->getSize()); - writer.write(0, &symbolTableCmd, macho_symtab_command::size); - - // build LC_DYSYMTAB command - macho_dysymtab_command dynamicSymbolTableCmd; - bzero(&dynamicSymbolTableCmd, macho_dysymtab_command::size); - dynamicSymbolTableCmd.set_cmd(LC_DYSYMTAB); - dynamicSymbolTableCmd.set_cmdsize(macho_dysymtab_command::size); - dynamicSymbolTableCmd.set_ilocalsym(fWriter.fSymbolTableStabsStartIndex); - dynamicSymbolTableCmd.set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount); - dynamicSymbolTableCmd.set_iextdefsym(fWriter.fSymbolTableExportStartIndex); - dynamicSymbolTableCmd.set_nextdefsym(fWriter.fSymbolTableExportCount); - dynamicSymbolTableCmd.set_iundefsym(fWriter.fSymbolTableImportStartIndex); - dynamicSymbolTableCmd.set_nundefsym(fWriter.fSymbolTableImportCount); - dynamicSymbolTableCmd.set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset()); - dynamicSymbolTableCmd.set_nindirectsyms(fWriter.fIndirectSymbolTable.size()); - if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) { - dynamicSymbolTableCmd.set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset()); - dynamicSymbolTableCmd.set_nextrel(fWriter.fExternalRelocs.size()); - dynamicSymbolTableCmd.set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset()); - dynamicSymbolTableCmd.set_nlocrel(fWriter.fInternalRelocs.size()); - } - writer.write(macho_symtab_command::size, &dynamicSymbolTableCmd, macho_dysymtab_command::size); -} - -uint64_t DyldLoadCommandsAtom::getSize() const -{ - uint32_t len = macho_dylinker_command::name_offset + strlen("/usr/lib/dyld"); - len = (len+7) & (-8); // 8-byte align - return len; -} - -void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - bzero(buffer, size); - macho_dylinker_command* cmd = (macho_dylinker_command*)buffer; - if ( fWriter.fOptions.outputKind() == Options::kDyld ) - cmd->set_cmd(LC_ID_DYLINKER); - else - cmd->set_cmd(LC_LOAD_DYLINKER); - cmd->set_cmdsize(this->getSize()); - cmd->set_name_offset(); - strcpy((char*)&buffer[macho_dylinker_command::name_offset], "/usr/lib/dyld"); - writer.write(0, buffer, size); -} - - - -uint64_t DylibLoadCommandsAtom::getSize() const -{ - const char* path = fInfo.reader->getInstallPath(); - if ( fInfo.options.fInstallPathOverride != NULL ) - path = fInfo.options.fInstallPathOverride; - uint32_t len = macho_dylib_command::name_offset + strlen(path); - len = (len+7) & (-8); // 8-byte align - return len; -} - -void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - bzero(buffer, size); - const char* path = fInfo.reader->getInstallPath(); - if ( fInfo.options.fInstallPathOverride != NULL ) - path = fInfo.options.fInstallPathOverride; - macho_dylib_command* cmd = (macho_dylib_command*)buffer; - if ( fInfo.options.fWeakImport ) - cmd->set_cmd(LC_LOAD_WEAK_DYLIB); - else - cmd->set_cmd(LC_LOAD_DYLIB); - cmd->set_cmdsize(this->getSize()); - cmd->set_timestamp(fInfo.reader->getTimestamp()); - cmd->set_current_version(fInfo.reader->getCurrentVersion()); - cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion()); - cmd->set_name_offset(); - strcpy((char*)&buffer[macho_dylib_command::name_offset], path); - writer.write(0, buffer, size); -} - - - -uint64_t DylibIDLoadCommandsAtom::getSize() const -{ - uint32_t len = macho_dylib_command::name_offset + strlen(fWriter.fOptions.installPath()); - len = (len+7) & (-8); // 8-byte align - return len; -} - -void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - struct timeval currentTime = { 0 , 0 }; - gettimeofday(¤tTime, NULL); - time_t timestamp = currentTime.tv_sec; - uint64_t size = this->getSize(); - uint8_t buffer[size]; - bzero(buffer, size); - macho_dylib_command* cmd = (macho_dylib_command*)buffer; - cmd->set_cmd(LC_ID_DYLIB); - cmd->set_cmdsize(this->getSize()); - cmd->set_name_offset(); - cmd->set_timestamp(timestamp); - cmd->set_current_version(fWriter.fOptions.currentVersion()); - cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion()); - strcpy((char*)&buffer[macho_dylib_command::name_offset], fWriter.fOptions.installPath()); - writer.write(0, buffer, size); -} - - -uint64_t RoutinesLoadCommandsAtom::getSize() const -{ - return macho_routines_command::size; -} - -void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); - uint8_t buffer[macho_routines_command::size]; - bzero(buffer, macho_routines_command::size); - macho_routines_command* cmd = (macho_routines_command*)buffer; - cmd->set_cmd(macho_routines_command::command); - cmd->set_cmdsize(this->getSize()); - cmd->set_init_address(initAddr); - writer.write(0, buffer, macho_routines_command::size); -} - - -uint64_t SubUmbrellaLoadCommandsAtom::getSize() const -{ - uint32_t len = macho_sub_umbrella_command::name_offset + strlen(fName); - len = (len+7) & (-8); // 8-byte align - return len; -} - -void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - bzero(buffer, size); - macho_sub_umbrella_command* cmd = (macho_sub_umbrella_command*)buffer; - cmd->set_cmd(LC_SUB_UMBRELLA); - cmd->set_cmdsize(this->getSize()); - cmd->set_name_offset(); - strcpy((char*)&buffer[macho_sub_umbrella_command::name_offset], fName); - writer.write(0, buffer, size); -} - - -uint64_t SubLibraryLoadCommandsAtom::getSize() const -{ - uint32_t len = macho_sub_library_command::name_offset + fNameLength + 1; - len = (len+7) & (-8); // 8-byte align - return len; -} - -void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - bzero(buffer, size); - macho_sub_library_command* cmd = (macho_sub_library_command*)buffer; - cmd->set_cmd(LC_SUB_LIBRARY); - cmd->set_cmdsize(this->getSize()); - cmd->set_name_offset(); - strncpy((char*)&buffer[macho_sub_library_command::name_offset], fNameStart, fNameLength); - buffer[macho_sub_library_command::name_offset+fNameLength] = '\0'; - writer.write(0, buffer, size); -} - -uint64_t UmbrellaLoadCommandsAtom::getSize() const -{ - uint32_t len = macho_sub_framework_command::name_offset + strlen(fName); - len = (len+7) & (-8); // 8-byte align - return len; -} - -void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - bzero(buffer, size); - macho_sub_framework_command* cmd = (macho_sub_framework_command*)buffer; - cmd->set_cmd(LC_SUB_FRAMEWORK); - cmd->set_cmdsize(this->getSize()); - cmd->set_name_offset(); - strcpy((char*)&buffer[macho_sub_framework_command::name_offset], fName); - writer.write(0, buffer, size); -} - -uint64_t ThreadsLoadCommandsAtom::getSize() const -{ -#if defined(ARCH_PPC) - uint32_t stateSize = 40; // PPC_THREAD_STATE_COUNT; -#elif defined(ARCH_PPC64) - uint32_t stateSize = 76; // PPC_THREAD_STATE64_COUNT; -#elif defined(ARCH_I386) - uint32_t stateSize = 16; // i386_THREAD_STATE_COUNT; -#else - #error unknown architecture -#endif - return macho_thread_command::size + stateSize*4; -} - -void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint); - bzero(buffer, size); - macho_thread_command* cmd = (macho_thread_command*)buffer; - cmd->set_cmd(LC_UNIXTHREAD); - cmd->set_cmdsize(size); -#if defined(ARCH_PPC) - cmd->set_flavor(1); // PPC_THREAD_STATE - cmd->set_count(40); // PPC_THREAD_STATE_COUNT; - cmd->set_threadState32(0, start); - if ( fWriter.fOptions.hasCustomStack() ) - cmd->set_threadState32(3, fWriter.fOptions.customStackAddr()); // r1 -#elif defined(ARCH_PPC64) - cmd->set_flavor(5); // PPC_THREAD_STATE64 - cmd->set_count(76); // PPC_THREAD_STATE64_COUNT; - cmd->set_threadState64(0, start); - if ( fWriter.fOptions.hasCustomStack() ) - cmd->set_threadState64(6, fWriter.fOptions.customStackAddr()); // r1 -#elif defined(ARCH_I386) - cmd->set_flavor(0xFFFFFFFF); // i386_THREAD_STATE - cmd->set_count(16); // i386_THREAD_STATE_COUNT; - cmd->set_threadState32(0, start); - if ( fWriter.fOptions.hasCustomStack() ) - cmd->set_threadState32(15, fWriter.fOptions.customStackAddr()); // uesp -#else - #error unknown architecture -#endif - writer.write(0, buffer, size); -} - - - -uint64_t LoadCommandsPaddingAtom::getSize() const -{ - return fSize; -} - -void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint8_t buffer[fSize]; - bzero(buffer, fSize); - writer.write(0, buffer, fSize); -} - - -uint64_t LinkEditAtom::getFileOffset() const -{ - return ((Writer::SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset(); -} - - -uint64_t LocalRelocationsLinkEditAtom::getSize() const -{ - return fWriter.fInternalRelocs.size() * macho_relocation_info::size; -} - -void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - writer.write(0, &fWriter.fInternalRelocs[0], this->getSize()); -} - - - -uint64_t SymbolTableLinkEditAtom::getSize() const -{ - return fWriter.fSymbolTableCount * macho_nlist::size; -} - -void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - writer.write(0, fWriter.fSymbolTable, this->getSize()); -} - -uint64_t ExternalRelocationsLinkEditAtom::getSize() const -{ - return fWriter.fExternalRelocs.size() * macho_relocation_info::size; -} - -void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - writer.write(0, &fWriter.fExternalRelocs[0], this->getSize()); -} - - - -uint64_t IndirectTableLinkEditAtom::getSize() const -{ - return fWriter.fIndirectSymbolTable.size() * sizeof(uint32_t); -} - -void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t size = this->getSize(); - uint8_t buffer[size]; - bzero(buffer, size); - const uint32_t indirectTableSize = fWriter.fIndirectSymbolTable.size(); - uint32_t* indirectTable = (uint32_t*)buffer; - for (uint32_t i=0; i < indirectTableSize; ++i) { - Writer::IndirectEntry& entry = fWriter.fIndirectSymbolTable[i]; - if ( entry.indirectIndex < indirectTableSize ) { - ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex); - } - else { - throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, entry.indirectIndex); - } - } - writer.write(0, buffer, size); -} - - - -StringsLinkEditAtom::StringsLinkEditAtom(Writer& writer) - : LinkEditAtom(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0) -{ - fCurrentBuffer = new char[kBufferSize]; - // burn first byte of string pool (so zero is never a valid string offset) - fCurrentBuffer[fCurrentBufferUsed++] = ' '; - // make offset 1 always point to an empty string - fCurrentBuffer[fCurrentBufferUsed++] = '\0'; -} - -uint64_t StringsLinkEditAtom::getSize() const -{ - return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed; -} - -void StringsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - uint64_t offset = 0; - for (unsigned int i=0; i < fFullBuffers.size(); ++i) { - writer.write(offset, fFullBuffers[i], kBufferSize); - offset += kBufferSize; - } - writer.write(offset, fCurrentBuffer, fCurrentBufferUsed); -} - -int32_t StringsLinkEditAtom::add(const char* name) -{ - int lenNeeded = strlen(name)+1; - while ( lenNeeded + fCurrentBufferUsed >= kBufferSize ) { - // first part of string fits in current buffer - int firstLen = kBufferSize - fCurrentBufferUsed; - memcpy(&fCurrentBuffer[fCurrentBufferUsed], name, firstLen); - // alloc next buffer - fFullBuffers.push_back(fCurrentBuffer); - fCurrentBuffer = new char[kBufferSize]; - fCurrentBufferUsed = 0; - // advance name to second part - name += firstLen; - lenNeeded -= firstLen; - } - //fprintf(stderr, "StringsLinkEditAtom::add(): lenNeeded=%d, fCurrentBuffer=%d, fCurrentBufferUsed=%d\n", lenNeeded, fCurrentBuffer, fCurrentBufferUsed); - // string all fits in current buffer - strcpy(&fCurrentBuffer[fCurrentBufferUsed], name); - int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed; - fCurrentBufferUsed += lenNeeded; - return offset; -} - -// returns the index of an empty string -int32_t StringsLinkEditAtom::emptyString() -{ - return 1; -} - -#if defined(ARCH_PPC) || defined(ARCH_PPC64) -BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset) - : WriterAtom(writer, fgTextSegment), fTarget(target), fTargetOffset(targetOffset) -{ - char* buf = new char[strlen(name)+32]; - if ( targetOffset == 0 ) { - if ( islandRegion == 0 ) - sprintf(buf, "%s$island", name); - else - sprintf(buf, "%s$island_%d", name, islandRegion); - } - else { - sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion); - } - fName = buf; -} - - -void BranchIslandAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const -{ - int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress(); - uint8_t instruction[4]; - int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC); - OSWriteBigInt32(&instruction, 0, branchInstruction); - writer.write(0, &instruction, 4); -} - - -#endif - - -}; - - -