+++ /dev/null
-/* -*- 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 <stdlib.h>
-#include <mach-o/dyld.h>
-#include <vector>
-#include <ext/hash_set>
-#include <ext/hash_map>
-
-#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<ObjectFile::Reference*>& getReferences() const
- { return (fRealAtom ? fRealAtom->getReferences() : (std::vector<ObjectFile::Reference*>&)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<ObjectFile::LineInfo>* 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<ObjectFile::Reference*> 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<ObjectFile::Reference*>& getReferences() const { return (std::vector<ObjectFile::Reference*>&)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<ObjectFile::LineInfo>* 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<ObjectFile::Reference*> fReferences;
-};
-
-
-void InternalAtom::addReference(const char* name)
-{
- fReferences.push_back(new Reference(name));
-}
-
-
-
-
-class RemovableAtoms
-{
-public:
- RemovableAtoms(std::set<ObjectFile::Atom*>& iAtoms) : fAtoms(iAtoms) {}
-
- bool operator()(ObjectFile::Atom*& atom) const {
- return ( fAtoms.count(atom) != 0 );
- }
-
-private:
- std::set<ObjectFile::Atom*>& 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<class ObjectFile::Atom*>& getAtoms() { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
- virtual std::vector<class ObjectFile::Atom*>* 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<Stab>* getStabs() { return NULL; }
- virtual bool optimize(const std::vector<ObjectFile::Atom*>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms,
- std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>&,
- std::vector<ObjectFile::Atom*>& newDeadAtoms,
- uint32_t nextInputOrdinal,
- ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom,
- const std::vector<const char*>& 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<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
- typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, 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<ObjectFile::Atom*> fAtoms;
- InternalAtom fInternalAtom;
- const ObjectFile::ReaderOptions& fReaderOptions;
- static std::set<Reader*> fgReaders;
- static bool fgOptimized;
-};
-
-bool Reader::fgOptimized = false;
-std::set<Reader*> 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);
-
- // <rdar://problem/6378110> 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<ObjectFile::Atom *>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms,
- std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>& deadAtoms,
- std::vector<ObjectFile::Atom*>& newlyDeadAtoms,
- uint32_t nextInputOrdinal, ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom,
- const std::vector<const char*>& 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<Reader*>::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 char*>::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<ObjectFile::Atom*>::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<ObjectFile::Reference*>& refs = atom->getReferences();
- for (std::vector<ObjectFile::Reference*>::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<ObjectFile::Atom*>::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<ObjectFile::Atom*> machoAtoms = machoReader->getAtoms();
- for (std::vector<ObjectFile::Atom *>::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<ObjectFile::Reference*>& refs = atom->getReferences();
- for (std::vector<ObjectFile::Reference*>::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<class ObjectFile::Reference*>& references = atom->getReferences();
- for (std::vector<ObjectFile::Reference*>::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<Reader*>::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<ppc>::validFile(p) )
- return new mach_o::relocatable::Reader<ppc>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
- break;
- case CPU_TYPE_POWERPC64:
- if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
- return new mach_o::relocatable::Reader<ppc64>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
- break;
- case CPU_TYPE_I386:
- if ( mach_o::relocatable::Reader<x86>::validFile(p) )
- return new mach_o::relocatable::Reader<x86>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
- break;
- case CPU_TYPE_X86_64:
- if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
- return new mach_o::relocatable::Reader<x86_64>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
- break;
- case CPU_TYPE_ARM:
- if ( mach_o::relocatable::Reader<arm>::validFile(p) )
- return new mach_o::relocatable::Reader<arm>(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
-