X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/07feaf2cb00322d025073eb8ec22189ada5e4180..a645023da60d22e86be13f7b4d97adeff8bc6665:/src/ld/LTOReader.hpp diff --git a/src/ld/LTOReader.hpp b/src/ld/LTOReader.hpp deleted file mode 100644 index 2e560cc..0000000 --- a/src/ld/LTOReader.hpp +++ /dev/null @@ -1,742 +0,0 @@ -/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- - * - * Copyright (c) 2006-2009 Apple 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@ - */ - -#ifndef __LTO_READER_H__ -#define __LTO_READER_H__ - -#include -#include -#include -#include -#include - -#include "MachOFileAbstraction.hpp" -#include "Architectures.hpp" -#include "ObjectFile.h" -#include "Options.h" - -#include "llvm-c/lto.h" - - -namespace lto { - - -// -// Reference handles Atom references. These references facilitate -// symbol resolution. -// - -class Reference : public ObjectFile::Reference -{ -public: - Reference(const char* name) : fTargetName(name), fTargetAtom(NULL) { } - Reference(ObjectFile::Atom& atom) : fTargetName(NULL), fTargetAtom(&atom) { } - - bool isTargetUnbound() const { return fTargetAtom == NULL; } - bool isFromTargetUnbound() const { return true; } - uint8_t getKind() const { return 0; } - uint64_t getFixUpOffset() const { return 0; } - const char * getTargetName() const { return fTargetName; } - ObjectFile::Atom& getTarget() const { return *fTargetAtom; } - uint64_t getTargetOffset() const { return 0; } - bool hasFromTarget() const { return false; } - ObjectFile::Atom& getFromTarget() const { return *((ObjectFile::Atom*)NULL); } - const char * getFromTargetName() const { return NULL; } - uint64_t getFromTargetOffset() const { return 0; } - TargetBinding getTargetBinding() const; - TargetBinding getFromTargetBinding() const { return kDontBind; } - void setTarget (ObjectFile::Atom& a, uint64_t offset) - { fTargetAtom = &a; } - void setFromTarget(ObjectFile::Atom &a) { } - const char * getDescription() const; - -private: - const char * fTargetName; - ObjectFile::Atom * fTargetAtom; -}; - - -ObjectFile::Reference::TargetBinding Reference::getTargetBinding() const -{ - if ( fTargetAtom == NULL ) - return kUnboundByName; - else if ( fTargetName == NULL ) - return kBoundDirectly; - else - return kBoundByName; -} - -const char* Reference::getDescription() const -{ - static char temp[256]; - strcpy(temp, "reference to "); - if ( fTargetName != NULL ) - strcat(temp, fTargetName); - else - strcat(temp, fTargetAtom->getDisplayName()); - return temp; -} - - -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; } - - static Segment fgBootstrapSegment; - -private: - const char* fName; - const bool fReadable; - const bool fWritable; - const bool fExecutable; - const bool fFixedAddress; -}; - -Segment Segment:: fgBootstrapSegment("__TEMP", true, false, false, false); - - - - -// -// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially, -// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After -// optimization is performed, real Atoms are created for these symobls. However these real Atoms -// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate -// methods to real atom. -// -class Atom : public ObjectFile::Atom -{ -public: - Atom(class Reader& owner, const char* name, Scope, DefinitionKind, uint8_t alignment, ObjectFile::Atom& internalAtom); - - ObjectFile::Reader* getFile() const { return (ObjectFile::Reader*)&fOwner; } - bool getTranslationUnitSource (const char **dir, const char **name) const - { return fRealAtom->getTranslationUnitSource(dir, name); } - const char * getName () const { return fName; } - const char * getDisplayName() const { return this->getName(); } - Scope getScope() const { return (fRealAtom ? fRealAtom->getScope() : fScope); } - DefinitionKind getDefinitionKind() const { return (fRealAtom ? fRealAtom->getDefinitionKind() : fKind); } - SymbolTableInclusion getSymbolTableInclusion() const - { return (fRealAtom ? fRealAtom->getSymbolTableInclusion() : ObjectFile::Atom::kSymbolTableIn); } - bool dontDeadStrip() const { return false; } - bool isZeroFill() const { return (fRealAtom ? fRealAtom->isZeroFill() : false); } - bool isThumb() const { return false; } - uint64_t getSize() const { return (fRealAtom ? fRealAtom->getSize() : 0); } - std::vector& getReferences() const - { return (fRealAtom ? fRealAtom->getReferences() : (std::vector&)fReferences); } - bool mustRemainInSection() const { return fRealAtom->mustRemainInSection(); } - const char * getSectionName() const { return (fRealAtom ? fRealAtom->getSectionName() : NULL); } - // Linker::optimize() sets section for this atom, not fRealAtom. Use this Atom's fSection. - class ObjectFile::Section * getSection() const { return fSection; } - ObjectFile::Segment& getSegment() const { return (fRealAtom ? fRealAtom->getSegment() : Segment::fgBootstrapSegment); } - uint32_t getOrdinal() const { return (fRealAtom ? fRealAtom->getOrdinal() : 0); } - ObjectFile::Atom& getFollowOnAtom() const { return fRealAtom->getFollowOnAtom(); } - std::vector* getLineInfo() const { return (fRealAtom ? fRealAtom->getLineInfo() : NULL); } - ObjectFile::Alignment getAlignment() const { return (fRealAtom ? fRealAtom->getAlignment() : ObjectFile::Alignment(fAlignment)); } - void copyRawContent(uint8_t buffer[]) const - { if (fRealAtom) fRealAtom->copyRawContent(buffer); } - void setScope(Scope s) { if (fRealAtom) fRealAtom->setScope(s); else fScope = s; } - - void setRealAtom (ObjectFile::Atom *atom) - { fRealAtom = atom; } - ObjectFile::Atom * getRealAtom() { return fRealAtom; } - void addReference(ObjectFile::Reference *ref) - { fReferences.push_back(ref); } - - void setSectionOffset(uint64_t offset) { fSectionOffset = offset; if (fRealAtom) fRealAtom->setSectionOffset(offset); } - void setSection(class ObjectFile::Section* sect) { fSection = sect; if (fRealAtom) fRealAtom->setSection(sect); } - -private: - class Reader& fOwner; - const char* fName; - ObjectFile::Atom::Scope fScope; - ObjectFile::Atom::DefinitionKind fKind; - uint8_t fAlignment; - ObjectFile::Atom* fRealAtom; - std::vector fReferences; -}; - - -Atom::Atom(class Reader& owner, const char* name, Scope scope, DefinitionKind kind, uint8_t alignment, ObjectFile::Atom& internalAtom) -: fOwner(owner), fName(name), fScope(scope), fKind(kind), fAlignment(alignment), fRealAtom(NULL) -{ - // every Atom references the InternalAtom for its reader - fReferences.push_back(new Reference(internalAtom)); -} - - -// -// ld64 only tracks non-internal symbols from an llvm bitcode file. -// We model this by having an InternalAtom which represent all internal functions and data. -// All non-interal symbols from a bitcode file are represented by a Atom -// and each Atom has a reference to the InternalAtom. The InternalAtom -// also has references to each symbol external to the bitcode file. -// -class InternalAtom : public ObjectFile::Atom -{ -public: - InternalAtom(class Reader& owner) : fOwner(owner) {} - - ObjectFile::Reader * getFile() const { return (ObjectFile::Reader*)&fOwner; } - bool getTranslationUnitSource (const char **dir, const char **name) const - { return false; } - const char * getName () const { return "__llvm-internal-atom"; } - const char * getDisplayName() const { return "llvm bitcode"; } - Scope getScope() const { return scopeTranslationUnit; } - DefinitionKind getDefinitionKind() const { return kRegularDefinition; } - SymbolTableInclusion getSymbolTableInclusion() const { return kSymbolTableNotIn; } - bool dontDeadStrip() const { return false; } - bool isZeroFill() const { return false; } - bool isThumb() const { return false; } - uint64_t getSize() const { return 0; } - std::vector& getReferences() const { return (std::vector&)fReferences; } - bool mustRemainInSection() const { return false; } - const char * getSectionName() const { return NULL; } - class ObjectFile::Section * getSection() const { return NULL; } - ObjectFile::Segment& getSegment() const { return Segment::fgBootstrapSegment; } - uint32_t getOrdinal() const { return 0; } - ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); } - std::vector* getLineInfo() const { return NULL; } - ObjectFile::Alignment getAlignment() const { return ObjectFile::Alignment(0); } - void copyRawContent(uint8_t buffer[]) const { } - void setScope(Scope s) { } - - void addReference(const char* targetName); - -private: - class Reader& fOwner; - std::vector fReferences; -}; - - -void InternalAtom::addReference(const char* name) -{ - fReferences.push_back(new Reference(name)); -} - - - - -class RemovableAtoms -{ -public: - RemovableAtoms(std::set& iAtoms) : fAtoms(iAtoms) {} - - bool operator()(ObjectFile::Atom*& atom) const { - return ( fAtoms.count(atom) != 0 ); - } - -private: - std::set& fAtoms; -}; - - - -// -// LLVM bitcode file reader -// -class Reader : public ObjectFile::Reader -{ -public: - static bool validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture); - static const char* fileKind(const uint8_t* fileContent); - static bool loaded() { return (::lto_get_version() != NULL); } - Reader(const uint8_t* fileContent, uint64_t fileLength, - const char* path, time_t modTime, - const ObjectFile::ReaderOptions&, cpu_type_t arch); - virtual ~Reader(); - - virtual std::vector& getAtoms() { return (std::vector&)(fAtoms); } - virtual std::vector* getJustInTimeAtomsFor(const char* name) { return NULL; } - virtual const char* getPath() { return fPath; } - virtual time_t getModificationTime() { return fModTime; } - virtual ObjectFile::Reader::DebugInfoKind getDebugInfoKind() { return kDebugInfoNone; } - virtual std::vector* getStabs() { return NULL; } - virtual bool optimize(const std::vector& allAtoms, std::vector& newAtoms, - std::vector& additionalUndefines, const std::set&, - std::vector& newDeadAtoms, - uint32_t nextInputOrdinal, - ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom, - const std::vector& llvmOptions, - bool allGlobalsAReDeadStripRoots, - int outputKind, bool verbose, bool saveTemps, const char* outputFilePath, - bool pie, bool allowTextRelocs); - -private: - - class CStringEquals - { - public: - bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } - }; - typedef __gnu_cxx::hash_set, CStringEquals> CStringSet; - typedef __gnu_cxx::hash_map, CStringEquals> CStringToAtom; - - ObjectFile::Reader* makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal); - static const char* tripletPrefixForArch(cpu_type_t); - - cpu_type_t fArchitecture; - const char* fPath; - time_t fModTime; - lto_module_t fModule; - std::vector fAtoms; - InternalAtom fInternalAtom; - const ObjectFile::ReaderOptions& fReaderOptions; - static std::set fgReaders; - static bool fgOptimized; -}; - -bool Reader::fgOptimized = false; -std::set Reader::fgReaders; - - -Reader::~Reader() -{ - if ( fModule != NULL ) - ::lto_module_dispose(fModule); -} - -Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, - const ObjectFile::ReaderOptions& options, cpu_type_t arch) - : fArchitecture(arch), fPath(strdup(path)), fModTime(modTime), fInternalAtom(*this), fReaderOptions(options) -{ - fgReaders.insert(this); - - fModule = ::lto_module_create_from_memory(fileContent, fileLength); - if ( fModule == NULL ) - throwf("could not parse object file %s: %s", path, lto_get_error_message()); - - fAtoms.push_back(&fInternalAtom); - - uint32_t count = ::lto_module_get_num_symbols(fModule); - for (uint32_t i=0; i < count; ++i) { - const char* name = ::lto_module_get_symbol_name(fModule, i); - lto_symbol_attributes attr = lto_module_get_symbol_attribute(fModule, i); - - // LTO doesn't like dtrace symbols - // ignore dtrace static probes for now - // later when codegen is done and a mach-o file is produces the probes will be processed - if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) ) - continue; - - ObjectFile::Atom::DefinitionKind kind; - switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) { - case LTO_SYMBOL_DEFINITION_REGULAR: - kind = ObjectFile::Atom::kRegularDefinition; - break; - case LTO_SYMBOL_DEFINITION_TENTATIVE: - kind = ObjectFile::Atom::kTentativeDefinition; - break; - case LTO_SYMBOL_DEFINITION_WEAK: - kind = ObjectFile::Atom::kWeakDefinition; - break; - case LTO_SYMBOL_DEFINITION_UNDEFINED: - case LTO_SYMBOL_DEFINITION_WEAKUNDEF: - kind = ObjectFile::Atom::kExternalDefinition; - break; - default: - throwf("unknown definition kind for symbol %s in bitcode file %s", name, path); - } - - // make LLVM atoms for definitions and a reference for undefines - if ( kind != ObjectFile::Atom::kExternalDefinition ) { - ObjectFile::Atom::Scope scope; - switch ( attr & LTO_SYMBOL_SCOPE_MASK) { - case LTO_SYMBOL_SCOPE_INTERNAL: - scope = ObjectFile::Atom::scopeTranslationUnit; - break; - case LTO_SYMBOL_SCOPE_HIDDEN: - scope = ObjectFile::Atom::scopeLinkageUnit; - break; - case LTO_SYMBOL_SCOPE_DEFAULT: - scope = ObjectFile::Atom::scopeGlobal; - break; - default: - throwf("unknown scope for symbol %s in bitcode file %s", name, path); - } - // only make atoms for non-internal symbols - if ( scope == ObjectFile::Atom::scopeTranslationUnit ) - continue; - uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK); - // make Atom - fAtoms.push_back(new Atom(*this, name, scope, kind, alignment, fInternalAtom)); - } - else { - // add to list of external references - fInternalAtom.addReference(name); - } - } -} - -const char* Reader::tripletPrefixForArch(cpu_type_t arch) -{ - switch (arch) { - case CPU_TYPE_POWERPC: - return "powerpc-"; - case CPU_TYPE_POWERPC64: - return "powerpc64-"; - case CPU_TYPE_I386: - return "i386-"; - case CPU_TYPE_X86_64: - return "x86_64-"; - case CPU_TYPE_ARM: - return "arm"; - } - return ""; -} - -bool Reader::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture) -{ - return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture)); -} - -const char* Reader::fileKind(const uint8_t* p) -{ - if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) { - uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16]))); - switch (arch) { - case CPU_TYPE_POWERPC: - return "ppc"; - case CPU_TYPE_I386: - return "i386"; - case CPU_TYPE_X86_64: - return "x86_64"; - case CPU_TYPE_ARM: - return "arm"; - } - return "unknown bitcode architecture"; - } - return NULL; -} - -bool Reader::optimize(const std::vector& allAtoms, std::vector& newAtoms, - std::vector& additionalUndefines, const std::set& deadAtoms, - std::vector& newlyDeadAtoms, - uint32_t nextInputOrdinal, ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom, - const std::vector& llvmOptions, - bool allGlobalsAReDeadStripRoots, - int okind, bool verbose, bool saveTemps, const char* outputFilePath, - bool pie, bool allowTextRelocs) -{ - // this method is call on all Readers. We want the first call to trigger optimization - // across all Readers and the subsequent calls to do nothing. - if ( fgOptimized ) - return false; - fgOptimized = true; - - Options::OutputKind outputKind = (Options::OutputKind)okind; // HACK to work around upward dependency - - // print out LTO version string if -v was used - if ( verbose ) - fprintf(stderr, "%s\n", lto_get_version()); - - // create optimizer and add each Reader - lto_code_gen_t generator = ::lto_codegen_create(); - for (std::set::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) { - if ( ::lto_codegen_add_module(generator, (*it)->fModule) ) - throwf("lto: could not merge in %s because %s", (*it)->fPath, ::lto_get_error_message()); - } - - // add any -mllvm command line options - for (std::vector::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) { - ::lto_codegen_debug_options(generator, *it); - } - - // The atom graph uses directed edges (references). Collect all references where - // originating atom is not part of any LTO Reader. This allows optimizer to optimize an - // external (i.e. not originated from same .o file) reference if all originating atoms are also - // defined in llvm bitcode file. - CStringSet nonLLVMRefs; - CStringToAtom llvmAtoms; - bool hasNonllvmAtoms = false; - for (std::vector::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) { - ObjectFile::Atom* atom = *it; - // only look at references come from an atom that is not an llvm atom - if ( fgReaders.count((Reader*)(atom->getFile())) == 0 ) { - // remember if we've seen any atoms not from an llvm reader and not from the writer - if ( atom->getFile() != writer ) - hasNonllvmAtoms = true; - std::vector& refs = atom->getReferences(); - for (std::vector::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) { - ObjectFile::Reference* ref = *ri; - // add target name to set if target is an llvm atom - if ( (ref->getTargetName() != NULL) && (fgReaders.count((Reader*)(ref->getTarget().getFile())) != 0) ) { - nonLLVMRefs.insert(ref->getTargetName()); - } - } - } - else { - const char* name = atom->getName(); - if ( name != NULL ) - llvmAtoms[name] = (Atom*)atom; - } - } - // if entry point is in a llvm bitcode file, it must be preserved by LTO - if ( entryPointAtom != NULL ) { - if ( fgReaders.count((Reader*)(entryPointAtom->getFile())) != 0 ) - nonLLVMRefs.insert(entryPointAtom->getName()); - } - - // deadAtoms are the atoms that the linker coalesced. For instance weak or tentative definitions - // overriden by another atom. If any of these deadAtoms are llvm atoms and they were replaced - // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead - // atom so that the linker can replace it with the mach-o one later. - CStringToAtom deadllvmAtoms; - for (std::set::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) { - ObjectFile::Atom* atom = *it; - if ( fgReaders.count((Reader*)(atom->getFile())) != 0 ) { - const char* name = atom->getName(); - ::lto_codegen_add_must_preserve_symbol(generator, name); - deadllvmAtoms[name] = (Atom*)atom; - } - } - - - // tell code generator about symbols that must be preserved - for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) { - const char* name = it->first; - Atom* atom = it->second; - // Include llvm Symbol in export list if it meets one of following two conditions - // 1 - atom scope is global (and not linkage unit). - // 2 - included in nonLLVMRefs set. - // If a symbol is not listed in exportList then LTO is free to optimize it away. - if ( (atom->getScope() == ObjectFile::Atom::scopeGlobal) ) - ::lto_codegen_add_must_preserve_symbol(generator, name); - else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) - ::lto_codegen_add_must_preserve_symbol(generator, name); - } - - // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o) - if ( (outputKind == Options::kObjectFile) && !hasNonllvmAtoms ) { - if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) { - // HACK, no good way to tell linker we are all done, so just quit - exit(0); - } - warning("could not produce merged bitcode file"); - } - - // set code-gen model - lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; - switch ( outputKind ) { - case Options::kDynamicExecutable: - case Options::kPreload: - if ( pie ) - model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; - else - model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; - break; - case Options::kDynamicLibrary: - case Options::kDynamicBundle: - case Options::kObjectFile: // ?? Is this appropriate ? - case Options::kDyld: - case Options::kKextBundle: - if ( allowTextRelocs ) - model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; - else - model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; - break; - case Options::kStaticExecutable: - // darwin x86_64 "static" code model is really dynamic code model - if ( fArchitecture == CPU_TYPE_X86_64 ) - model = LTO_CODEGEN_PIC_MODEL_DYNAMIC; - else - model = LTO_CODEGEN_PIC_MODEL_STATIC; - break; - } - if ( ::lto_codegen_set_pic_model(generator, model) ) - throwf("could not create set codegen model: %s", lto_get_error_message()); - - // if requested, save off merged bitcode file - if ( saveTemps ) { - char tempBitcodePath[MAXPATHLEN]; - strcpy(tempBitcodePath, outputFilePath); - strcat(tempBitcodePath, ".lto.bc"); - ::lto_codegen_write_merged_modules(generator, tempBitcodePath); - } - -#if LTO_API_VERSION >= 3 - // find assembler next to linker - char path[PATH_MAX]; - uint32_t bufSize = PATH_MAX; - if ( _NSGetExecutablePath(path, &bufSize) != -1 ) { - char* lastSlash = strrchr(path, '/'); - if ( lastSlash != NULL ) { - strcpy(lastSlash+1, "as"); - struct stat statInfo; - if ( stat(path, &statInfo) == 0 ) - ::lto_codegen_set_assembler_path(generator, path); - } - } -#endif - // run code generator - size_t machOFileLen; - const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen); - if ( machOFile == NULL ) - throwf("could not do LTO codegen: %s", ::lto_get_error_message()); - - // if requested, save off temp mach-o file - if ( saveTemps ) { - char tempMachoPath[MAXPATHLEN]; - strcpy(tempMachoPath, outputFilePath); - strcat(tempMachoPath, ".lto.o"); - int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666); - if ( fd != -1) { - ::write(fd, machOFile, machOFileLen); - ::close(fd); - } - // save off merged bitcode file - char tempOptBitcodePath[MAXPATHLEN]; - strcpy(tempOptBitcodePath, outputFilePath); - strcat(tempOptBitcodePath, ".lto.opt.bc"); - ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath); - } - - // parse generated mach-o file into a MachOReader - ObjectFile::Reader* machoReader = this->makeMachOReader(machOFile, machOFileLen, nextInputOrdinal); - - // sync generated mach-o atoms with existing atoms ld knows about - std::vector machoAtoms = machoReader->getAtoms(); - for (std::vector::iterator it = machoAtoms.begin(); it != machoAtoms.end(); ++it) { - ObjectFile::Atom* atom = *it; - const char* name = atom->getName(); - if ( name != NULL ) { - CStringToAtom::iterator pos = llvmAtoms.find(name); - if ( pos != llvmAtoms.end() ) { - // turn Atom into a proxy for this mach-o atom - pos->second->setRealAtom(atom); - } - else { - // an atom of this name was not in the allAtoms list the linker gave us - if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) { - // this corresponding to an atom that the linker coalesced away. Ignore it - // Make sure there any dependent atoms are also marked dead - std::vector& refs = atom->getReferences(); - for (std::vector::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) { - ObjectFile::Reference* ref = *ri; - if ( ref->getKind() == 2 /*kGroupSubordinate*/ ) { // FIX FIX - ObjectFile::Atom* targ = &ref->getTarget(); - deadllvmAtoms[targ->getName()] = (Atom*)atom; - } - } - } - else - { - // this is something new that lto conjured up, tell ld its new - newAtoms.push_back(atom); - } - } - } - else { - // ld only knew about named atoms, so this one must be new - newAtoms.push_back(atom); - } - std::vector& references = atom->getReferences(); - for (std::vector::iterator rit=references.begin(); rit != references.end(); ++rit) { - ObjectFile::Reference* ref = *rit; - const char* targetName = ref->getTargetName(); - CStringToAtom::iterator pos; - if (targetName != NULL) { - switch ( ref->getTargetBinding() ) { - case ObjectFile::Reference::kUnboundByName: - // accumulate unbounded references so that ld can bound them. - additionalUndefines.push_back(targetName); - break; - case ObjectFile::Reference::kBoundDirectly: - case ObjectFile::Reference::kBoundByName: - // If mach-o atom is referencing another mach-o atom then - // reference is not going through Atom proxy. Fix it here to ensure that all - // llvm symbol references always go through Atom proxy. - pos = llvmAtoms.find(targetName); - if ( pos != llvmAtoms.end() ) - ref->setTarget(*pos->second, ref->getTargetOffset()); - break; - case ObjectFile::Reference::kDontBind: - break; - } - } - } - } - - // Remove InternalAtoms from ld - for (std::set::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) { - newlyDeadAtoms.push_back(&((*it)->fInternalAtom)); - } - // Remove Atoms from ld if code generator optimized them away - for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) { - // check if setRealAtom() called on this Atom - if ( li->second->getRealAtom() == NULL ) - newlyDeadAtoms.push_back(li->second); - } - - return true; -} - - -ObjectFile::Reader* Reader::makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal) -{ - switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: - if ( mach_o::relocatable::Reader::validFile(p) ) - return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); - break; - case CPU_TYPE_POWERPC64: - if ( mach_o::relocatable::Reader::validFile(p) ) - return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); - break; - case CPU_TYPE_I386: - if ( mach_o::relocatable::Reader::validFile(p) ) - return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); - break; - case CPU_TYPE_X86_64: - if ( mach_o::relocatable::Reader::validFile(p) ) - return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); - break; - case CPU_TYPE_ARM: - if ( mach_o::relocatable::Reader::validFile(p) ) - return new mach_o::relocatable::Reader(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal); - break; - } - throw "LLVM LTO, file is not of required architecture"; -} - -}; // namespace lto - -extern void printLTOVersion(Options& opts); - -void printLTOVersion(Options& opts) { - const char* vers = lto_get_version(); - if ( vers != NULL ) - fprintf(stderr, "%s\n", vers); -} - - -#endif -