Index: include/llvm/Bitcode/ReaderWriter.h =================================================================== --- include/llvm/Bitcode/ReaderWriter.h +++ include/llvm/Bitcode/ReaderWriter.h @@ -23,12 +23,120 @@ #include namespace llvm { - class BitstreamWriter; - class DataStreamer; - class LLVMContext; - class Module; - class ModulePass; - class raw_ostream; +class BitstreamWriter; +class DataStreamer; +class LLVMContext; +class Module; +class ModulePass; +class raw_ostream; + +struct BitcodeSymbolFlags { + int IsAsm : 1; // Symbol is defined in (or referenced from) inline asm + int IsUndefined : 1; // Symbol is defined in another object file + int IsGlobal : 1; + int IsWeak : 1; + int IsPrivate : 1; // Private linkage (incompatible with IsGlobal) + int IsAlias : 1; + int IsFunction : 1; + int IsAbsolute : 1; + int IsCommon : 1; + int IsUnnamedAddress : 1; + int IsLocalUnnamedAddress : 1; + int IsFormatSpecific : 1; // Symbol with llvm.metadata section for instance + int IsHidden : 1; + int IsProtected : 1; + int IsConst : 1; + int IsDLLImportStorageClass : 1; + int CanBeOmittedFromSymbolTable : 1; +}; + +/// Abstraction of "Symbol" defined in a bitcode file +class BitcodeSymbol { +public: + StringRef getName() const { return Name; } + void setName(std::string NewName) { Name = std::move(NewName); } + + StringRef getSection() const { return Section; } + void setSection(std::string NewSection) { Section = std::move(NewSection); } + + StringRef getComdat() const { return Comdat; } + void setComdat(std::string NewComdat) { Comdat = std::move(NewComdat); } + + BitcodeSymbolFlags getFlags() const { return Flags; } + void setFlags(BitcodeSymbolFlags NewFlags) { Flags = NewFlags; } + +#define BITCODE_SYMBOL_GETTER_SETTER(FIELD) \ + LLVM_ATTRIBUTE_UNUSED_RESULT bool is##FIELD() const { \ + return Flags.Is##FIELD; \ + } \ + void set##FIELD(bool Val = true) { Flags.Is##FIELD = Val; } + + BITCODE_SYMBOL_GETTER_SETTER(Asm) + BITCODE_SYMBOL_GETTER_SETTER(Undefined) + BITCODE_SYMBOL_GETTER_SETTER(Global) + BITCODE_SYMBOL_GETTER_SETTER(Weak) + BITCODE_SYMBOL_GETTER_SETTER(Private) + BITCODE_SYMBOL_GETTER_SETTER(Alias) + BITCODE_SYMBOL_GETTER_SETTER(Function) + BITCODE_SYMBOL_GETTER_SETTER(Absolute) + BITCODE_SYMBOL_GETTER_SETTER(Common) + BITCODE_SYMBOL_GETTER_SETTER(UnnamedAddress) + BITCODE_SYMBOL_GETTER_SETTER(LocalUnnamedAddress) + BITCODE_SYMBOL_GETTER_SETTER(FormatSpecific) + BITCODE_SYMBOL_GETTER_SETTER(Hidden) + BITCODE_SYMBOL_GETTER_SETTER(Protected) + BITCODE_SYMBOL_GETTER_SETTER(Const) + BITCODE_SYMBOL_GETTER_SETTER(DLLImportStorageClass) +#undef BITCODE_SYMBOL_GETTER_SETTER + + LLVM_ATTRIBUTE_UNUSED_RESULT + bool canBeOmittedFromSymbolTable() { + return Flags.CanBeOmittedFromSymbolTable; + } + void setCanBeOmittedFromSymbolTable(bool Val = true) { + Flags.CanBeOmittedFromSymbolTable = Val; + } + +private: + std::string Name; + std::string Section; + std::string Comdat; + BitcodeSymbolFlags Flags = {}; +}; + +/// Symbol table for a bitcode file: it is holding the list of symbols defined +/// by a bitcode file, and a few other informations (triple, datalayout, ...). +class BitcodeSymbolTable { + using SymbolsTy = std::vector; + SymbolsTy Symbols; + std::string Triple; + std::string Datalayout; + std::string ModuleAsm; + std::string SourceFilename; + +public: + SymbolsTy::const_iterator begin() const { return Symbols.begin(); } + SymbolsTy::const_iterator end() const { return Symbols.end(); } + size_t size() const { return Symbols.size(); } + bool empty() const { return Symbols.empty(); } + const SymbolsTy &getSymbols() const { return Symbols; } + void addSymbol(BitcodeSymbol Sym) { Symbols.push_back(Sym); } + SymbolsTy &getSymbols() { return Symbols; } + + StringRef getTriple() const { return Triple; } + void setTriple(StringRef T) { Triple = T; } + + StringRef getDataLayout() const { return Datalayout; } + void setDataLayout(std::string DL) { Datalayout = std::move(DL); } + + StringRef getModuleInlineAsm() const { return ModuleAsm; } + void setModuleInlineAsm(std::string Asm) { ModuleAsm = std::move(Asm); } + + StringRef getSourceFileName() const { return SourceFilename; } + void setSourceFileName(std::string Filename) { + SourceFilename = std::move(Filename); + } +}; /// Offsets of the 32-bit fields of bitcode wrapper header. static const unsigned BWH_MagicField = 0*4; @@ -75,6 +183,9 @@ ErrorOr> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); + /// Read the specified bitcode file, returning the symbol table only. + ErrorOr parseBitcodeSymbolTable(MemoryBufferRef Buffer); + /// Check if the given bitcode buffer contains a summary block. bool hasGlobalValueSummary(MemoryBufferRef Buffer, Index: include/llvm/IR/Mangler.h =================================================================== --- include/llvm/IR/Mangler.h +++ include/llvm/IR/Mangler.h @@ -33,6 +33,12 @@ mutable unsigned NextAnonGlobalID; public: + enum ManglerPrefixTy { + Default, ///< Emit default string before each symbol. + Private, ///< Emit "private" prefix before each symbol. + LinkerPrivate ///< Emit "linker private" prefix before each symbol. + }; + Mangler() : NextAnonGlobalID(1) {} /// Print the appropriate prefix and the specified global variable's name. @@ -46,9 +52,11 @@ /// Print the appropriate prefix and the specified name as the global variable /// name. GVName must not be empty. static void getNameWithPrefix(raw_ostream &OS, const Twine &GVName, - const DataLayout &DL); + const DataLayout &DL, + ManglerPrefixTy Prefix = Default); static void getNameWithPrefix(SmallVectorImpl &OutName, - const Twine &GVName, const DataLayout &DL); + const Twine &GVName, const DataLayout &DL, + ManglerPrefixTy Prefix = Default); }; } // End llvm namespace Index: include/llvm/LTO/legacy/LTOModule.h =================================================================== --- include/llvm/LTO/legacy/LTOModule.h +++ include/llvm/LTO/legacy/LTOModule.h @@ -17,19 +17,14 @@ #include "llvm-c/lto.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Module.h" -#include "llvm/Object/IRObjectFile.h" #include "llvm/Target/TargetMachine.h" #include #include // Forward references to llvm classes. namespace llvm { - class Function; - class GlobalValue; - class MemoryBuffer; - class TargetOptions; - class Value; //===----------------------------------------------------------------------===// /// C++ class which implements the opaque lto_module_t type. @@ -43,24 +38,22 @@ const GlobalValue *symbol; }; - std::unique_ptr OwnedContext; + // Buffer this LTOModule was initialized with. + std::unique_ptr RawBuffer; - std::string LinkerOpts; + // Reference to the bitcode inside the RawBuffer. + MemoryBufferRef Buffer; - std::unique_ptr IRFile; - std::unique_ptr _target; - std::vector _symbols; + // Linker options parsed out of the bitcode (Windows only). + std::string LinkerOpts; - // _defines and _undefines only needed to disambiguate tentative definitions - StringSet<> _defines; - StringMap _undefines; - std::vector _asm_undefines; + // Symbol table extracted from the bitcode. + BitcodeSymbolTable Table; - LTOModule(std::unique_ptr Obj, TargetMachine *TM); + // Private constructor, client is expected to use one of the factory methods. + LTOModule(std::unique_ptr RawBuffer, MemoryBufferRef Buffer); public: - ~LTOModule(); - /// Returns 'true' if the file or memory contents is LLVM bitcode. static bool isBitcodeFile(const void *mem, size_t length); static bool isBitcodeFile(const char *path); @@ -73,140 +66,69 @@ static bool isBitcodeForTarget(MemoryBuffer *memBuffer, StringRef triplePrefix); + /// Returns a reference to the memory that contains the bitcode. + MemoryBufferRef getBuffer() { return Buffer; } + /// Returns a string representing the producer identification stored in the /// bitcode, or "" if the bitcode does not contains any. - /// static std::string getProducerString(MemoryBuffer *Buffer); /// Create a MemoryBuffer from a memory range with an optional name. static std::unique_ptr makeBuffer(const void *mem, size_t length, StringRef name = ""); - /// Create an LTOModule. N.B. These methods take ownership of the buffer. The - /// caller must have initialized the Targets, the TargetMCs, the AsmPrinters, - /// and the AsmParsers by calling: + /// Create an LTOModule. + /// The caller must have initialized the Targets, the TargetMCs, the + /// AsmPrinters, and the AsmParsers by calling: /// /// InitializeAllTargets(); /// InitializeAllTargetMCs(); /// InitializeAllAsmPrinters(); /// InitializeAllAsmParsers(); + static ErrorOr> createFromFile(const char *path); static ErrorOr> - createFromFile(LLVMContext &Context, const char *path, - const TargetOptions &options); - static ErrorOr> - createFromOpenFile(LLVMContext &Context, int fd, const char *path, - size_t size, const TargetOptions &options); - static ErrorOr> - createFromOpenFileSlice(LLVMContext &Context, int fd, const char *path, - size_t map_size, off_t offset, - const TargetOptions &options); - static ErrorOr> - createFromBuffer(LLVMContext &Context, const void *mem, size_t length, - const TargetOptions &options, StringRef path = ""); + createFromOpenFile(int fd, const char *path, size_t size); static ErrorOr> - createInLocalContext(std::unique_ptr Context, const void *mem, - size_t length, const TargetOptions &options, - StringRef path); + createFromOpenFileSlice(int fd, const char *path, size_t map_size, + off_t offset); - const Module &getModule() const { - return const_cast(this)->getModule(); - } - Module &getModule() { - return IRFile->getModule(); - } - - std::unique_ptr takeModule() { return IRFile->takeModule(); } + /// Create from a buffer: the buffer must survive the LTOModule. + static ErrorOr> + createFromBuffer(const void *mem, size_t length, StringRef path = ""); /// Return the Module's target triple. - const std::string &getTargetTriple() { - return getModule().getTargetTriple(); - } - - /// Set the Module's target triple. - void setTargetTriple(StringRef Triple) { - getModule().setTargetTriple(Triple); - } + const StringRef getTargetTriple() { return Table.getTriple(); } /// Get the number of symbols - uint32_t getSymbolCount() { - return _symbols.size(); - } + uint32_t getSymbolCount() { return Table.size(); } /// Get the attributes for a symbol at the specified index. - lto_symbol_attributes getSymbolAttributes(uint32_t index) { - if (index < _symbols.size()) - return lto_symbol_attributes(_symbols[index].attributes); - return lto_symbol_attributes(0); - } + lto_symbol_attributes getSymbolAttributes(uint32_t Index); /// Get the name of the symbol at the specified index. - const char *getSymbolName(uint32_t index) { - if (index < _symbols.size()) - return _symbols[index].name; - return nullptr; - } - - const GlobalValue *getSymbolGV(uint32_t index) { - if (index < _symbols.size()) - return _symbols[index].symbol; + const char *getSymbolName(uint32_t Index) { + if (Index < Table.size()) + return Table.getSymbols()[Index].getName().data(); return nullptr; } + /// Return the Linker options for this module as a string. const char *getLinkerOpts() { return LinkerOpts.c_str(); } - const std::vector &getAsmUndefinedRefs() { - return _asm_undefines; + /// Return the list of symbols defined in this module. + const std::vector &getSymbols() const { + return Table.getSymbols(); } private: - /// Parse metadata from the module - // FIXME: it only parses "Linker Options" metadata at the moment - void parseMetadata(); - - /// Parse the symbols from the module and model-level ASM and add them to - /// either the defined or undefined lists. - void parseSymbols(); - - /// Add a symbol which isn't defined just yet to a list to be resolved later. - void addPotentialUndefinedSymbol(const object::BasicSymbolRef &Sym, - bool isFunc); - - /// Add a defined symbol to the list. - void addDefinedSymbol(const char *Name, const GlobalValue *def, - bool isFunction); - - /// Add a data symbol as defined to the list. - void addDefinedDataSymbol(const object::BasicSymbolRef &Sym); - void addDefinedDataSymbol(const char*Name, const GlobalValue *v); - - /// Add a function symbol as defined to the list. - void addDefinedFunctionSymbol(const object::BasicSymbolRef &Sym); - void addDefinedFunctionSymbol(const char *Name, const Function *F); - - /// Add a global symbol from module-level ASM to the defined list. - void addAsmGlobalSymbol(const char *, lto_symbol_attributes scope); - - /// Add a global symbol from module-level ASM to the undefined list. - void addAsmGlobalSymbolUndef(const char *); - - /// Parse i386/ppc ObjC class data structure. - void addObjCClass(const GlobalVariable *clgv); - - /// Parse i386/ppc ObjC category data structure. - void addObjCCategory(const GlobalVariable *clgv); - - /// Parse i386/ppc ObjC class list data structure. - void addObjCClassRef(const GlobalVariable *clgv); - - /// Get string that the data pointer points to. - bool objcClassNameFromExpression(const Constant *c, std::string &name); + /// Parse "Linker Options" + void parseLinkerOptions(); /// Create an LTOModule (private version). static ErrorOr> - makeLTOModule(MemoryBufferRef Buffer, const TargetOptions &options, - LLVMContext &Context, bool ShouldBeLazy); + makeLTOModule(std::unique_ptr Buffer); }; } #endif Index: include/llvm/Object/BitcodeObjectFile.h =================================================================== --- /dev/null +++ include/llvm/Object/BitcodeObjectFile.h @@ -0,0 +1,75 @@ +//===- BitcodeObjectFile.h - LLVM IR object file implementation --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the BitcodeObjectFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_BitcodeObjectFile_H +#define LLVM_OBJECT_BitcodeObjectFile_H + +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Object/SymbolicFile.h" + +namespace llvm { +class Mangler; +class Module; +class GlobalValue; +class Triple; + +namespace object { +class ObjectFile; + +class BitcodeObjectFile : public SymbolicFile { + std::vector> AsmSymbols; + BitcodeSymbolTable SymbolTable; + +public: + BitcodeObjectFile(MemoryBufferRef Object); + void moveSymbolNext(DataRefImpl &Symb) const override; + std::error_code printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const override; + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + basic_symbol_iterator symbol_begin_impl() const override; + basic_symbol_iterator symbol_end_impl() const override; + + static inline bool classof(const Binary *v) { return v->isIR(); } + + BitcodeSymbol &getSymbol(DataRefImpl Symb); + const BitcodeSymbolTable &getSymbolTable() const { return SymbolTable; } + BitcodeSymbolTable takeSymbolTable() { return std::move(SymbolTable); } + + StringRef getTargetTriple(); + + /// \brief Finds and returns bitcode embedded in the given object file, or an + /// error code if not found. + static ErrorOr findBitcodeInObject(const ObjectFile &Obj); + + /// Parse inline ASM and collect the symbols that are not defined in + /// the current module. + /// + /// For each found symbol, call \p AsmUndefinedRefs with the name of the + /// symbol found and the associated flags. + static void CollectAsmUndefinedRefs( + const Triple &TheTriple, StringRef InlineAsm, + function_ref AsmUndefinedRefs); + + /// \brief Finds and returns bitcode in the given memory buffer (which may + /// be either a bitcode file or a native object file with embedded bitcode), + /// or an error code if not found. + static ErrorOr + findBitcodeInMemBuffer(MemoryBufferRef Object); + + static ErrorOr> + create(MemoryBufferRef Object); +}; +} +} + +#endif Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/IR/OperandTraits.h" @@ -6508,6 +6509,548 @@ return std::error_code(); } +//==-----------------------------------------------------------------------===// +// Symbol Table Reader +//==-----------------------------------------------------------------------===// + +namespace { + +/// Heavily stripped down Bitcode Reader that will not create any IR but only +/// extracts a symbol table for a bitcode buffer. +class SymbolTableReader { + MemoryBufferRef Buffer; + std::unique_ptr StreamFile; + BitstreamCursor Stream; + // Contains an arbitrary and optional string identifying the bitcode producer + std::string ProducerIdentification; + + std::function + ErrorHandler; + +public: + SymbolTableReader( + MemoryBufferRef Buffer, + std::function + ErrorHandler) + : Buffer(Buffer), ErrorHandler(std::move(ErrorHandler)) {} + + /// Read only the symbol table out of the bitcode, without loading anything + /// in the context. This is a cheap way to produce the informations needed by + /// llvm-nm, and other clients like LTO. + ErrorOr parseBitcodeSymbolTable(); + +private: + std::error_code error(BitcodeError E, const Twine &Message); + std::error_code error(const Twine &Message); + std::error_code parseModule(BitcodeSymbolTable &Table); + std::error_code initStreamFromBuffer(); + + /// Parse the "IDENTIFICATION_BLOCK_ID" block, populate the + // ProducerIdentification data member, and do some basic enforcement on the + // "epoch" encoded in the bitcode. + std::error_code parseBitcodeVersion(); + + std::error_code parseValueSymbolTable(BitcodeSymbolTable &Table, + const DataLayout &DL); + + std::error_code parseAlignmentValue(uint64_t Exponent, unsigned &Alignment); + + std::error_code updateSymbolName(SmallVectorImpl &Record, + unsigned NameIndex, + SmallString<128> &ValueName, + BitcodeSymbolTable &Table, + const DataLayout &DL); +}; + +} // end anonymous namespace + +std::error_code SymbolTableReader::error(BitcodeError E, const Twine &Message) { + if (!ProducerIdentification.empty()) { + return ErrorHandler(make_error_code(E), + Message + " (Producer: '" + ProducerIdentification + + "' Reader: 'LLVM " + LLVM_VERSION_STRING "')"); + } + return ErrorHandler(make_error_code(E), Message); +} + +std::error_code SymbolTableReader::error(const Twine &Message) { + return error(BitcodeError::CorruptedBitcode, Message); +} + +std::error_code SymbolTableReader::initStreamFromBuffer() { + const unsigned char *BufPtr = (const unsigned char *)Buffer.getBufferStart(); + const unsigned char *BufEnd = BufPtr + Buffer.getBufferSize(); + + if (Buffer.getBufferSize() & 3) + return error("Invalid bitcode signature"); + + // If we have a wrapper header, parse it and ignore the non-bc file contents. + // The magic number is 0x0B17C0DE stored in little endian. + if (isBitcodeWrapper(BufPtr, BufEnd)) + if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) + return error("Invalid bitcode wrapper header"); + + StreamFile.reset(new BitstreamReader(BufPtr, BufEnd)); + Stream.init(&*StreamFile); + + return std::error_code(); +} + +ErrorOr SymbolTableReader::parseBitcodeSymbolTable() { + if (std::error_code EC = initStreamFromBuffer()) + return EC; + + // Sniff for the signature. + if (!hasValidBitcodeHeader(Stream)) + return error("Invalid bitcode signature"); + + BitcodeSymbolTable Table; + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (1) { + if (Stream.AtEndOfStream()) { + // We didn't really read a proper Module. + return error("Malformed IR file"); + } + + BitstreamEntry Entry = + Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); + + if (Entry.Kind != BitstreamEntry::SubBlock) + return error("Malformed block"); + + if (Entry.ID == bitc::IDENTIFICATION_BLOCK_ID) { + if (auto EC = parseBitcodeVersion()) + return EC; + continue; + } + + if (Entry.ID == bitc::MODULE_BLOCK_ID) { + if (auto EC = parseModule(Table)) + return EC; + return Table; + } + + if (Stream.SkipBlock()) + return error("Invalid record"); + } +} + +std::error_code SymbolTableReader::parseAlignmentValue(uint64_t Exponent, + unsigned &Alignment) { + // Note: Alignment in bitcode files is incremented by 1, so that zero + // can be used for default alignment. + if (Exponent > Value::MaxAlignmentExponent + 1) + return error("Invalid alignment value"); + Alignment = (1 << static_cast(Exponent)) >> 1; + return std::error_code(); +} + + +/// Parse the value symbol table at either the current parsing location or +/// at the given bit offset if provided. +std::error_code +SymbolTableReader::parseValueSymbolTable(BitcodeSymbolTable &Table, + const DataLayout &DL) { + if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) + return error("Invalid record"); + + + // Read all the records for this value table. + SmallString<128> ValueName; + SmallString<128> TmpValueName; + SmallVector Record; + + /// Associate a value with its name from the given index in the provided record. + auto updateSymbolName = [&] (unsigned NameIndex) { + TmpValueName.clear(); + if (convertToString(Record, NameIndex, TmpValueName)) + return error("Invalid record"); + unsigned ValueID = Record[0]; + auto &Sym = Table.getSymbols()[ValueID]; + + StringRef NameStr(TmpValueName.data(), TmpValueName.size()); + if (NameStr.find_first_of(0) != StringRef::npos) + return error("Invalid value name"); + auto PrefixTy = Mangler::Default; + if (Sym.isPrivate()) + PrefixTy = Mangler::Private; + + if (NameStr.startswith("llvm.")) + Sym.setFormatSpecific(); + + ValueName.clear(); + if (Sym.isDLLImportStorageClass()) + ValueName = "__imp_"; + Mangler::getNameWithPrefix(ValueName, NameStr, DL, PrefixTy); + Sym.setName(StringRef(ValueName)); + return std::error_code(); + }; + + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: unknown type. + break; + case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] + ErrorOr ValOrErr = + updateSymbolName(1); + if (std::error_code EC = ValOrErr.getError()) + return EC; + break; + } + case bitc::VST_CODE_FNENTRY: { + // VST_CODE_FNENTRY: [valueid, offset, namechar x N] + ErrorOr ValOrErr = + updateSymbolName(2); + if (std::error_code EC = ValOrErr.getError()) + return EC; + break; + } + } + } +} + +std::error_code SymbolTableReader::parseBitcodeVersion() { + if (Stream.EnterSubBlock(bitc::IDENTIFICATION_BLOCK_ID)) + return error("Invalid record"); + + // Read all the records. + SmallVector Record; + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + default: + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + unsigned BitCode = Stream.readRecord(Entry.ID, Record); + switch (BitCode) { + default: // Default behavior: reject + return error("Invalid value"); + case bitc::IDENTIFICATION_CODE_STRING: { // IDENTIFICATION: [strchr x + // N] + convertToString(Record, 0, ProducerIdentification); + break; + } + case bitc::IDENTIFICATION_CODE_EPOCH: { // EPOCH: [epoch#] + unsigned epoch = (unsigned)Record[0]; + if (epoch != bitc::BITCODE_CURRENT_EPOCH) { + return error(Twine("Incompatible epoch: Bitcode '") + Twine(epoch) + + "' vs current: '" + Twine(bitc::BITCODE_CURRENT_EPOCH) + + "'"); + } + } + } + } +} + +static void updateSymbolFlags(BitcodeSymbol &Sym, GlobalValue::LinkageTypes Linkage, + GlobalValue::VisibilityTypes Visibility, + GlobalValue::UnnamedAddr UnnamedAddr) { + if (Visibility == GlobalValue::HiddenVisibility) + Sym.setHidden(); + else if (Visibility == GlobalValue::ProtectedVisibility) + Sym.setProtected(); + + if (UnnamedAddr == GlobalValue::UnnamedAddr::Global) + Sym.setUnnamedAddress(); + if (UnnamedAddr == GlobalValue::UnnamedAddr::Local) + Sym.setLocalUnnamedAddress(); + if (!GlobalValue::isLocalLinkage(Linkage)) + Sym.setGlobal(); + if (GlobalValue::isCommonLinkage(Linkage)) + Sym.setCommon(); + if (GlobalValue::isWeakLinkage(Linkage) || + GlobalValue::isLinkOnceLinkage(Linkage) || + GlobalValue::isExternalWeakLinkage(Linkage)) + Sym.setWeak(); + + if (GlobalValue::isLinkOnceODRLinkage(Linkage) && + (UnnamedAddr == GlobalValue::UnnamedAddr::Global || + ((Sym.isConst() || Sym.isFunction()) && + UnnamedAddr != GlobalValue::UnnamedAddr::None))) + Sym.setCanBeOmittedFromSymbolTable(); + + if (GlobalValue::isPrivateLinkage(Linkage) || + Sym.getSection() == "llvm.metadata") { + Sym.setFormatSpecific(); + Sym.setPrivate(); + } +} + +// FIXME error handling +std::error_code SymbolTableReader::parseModule(BitcodeSymbolTable &Table) { + if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return error("Invalid record"); + + SmallVector Record; + std::vector SectionTable; + std::vector> ComdatList; + std::vector> Aliasing; + std::unique_ptr DL; // mangling + // Read all the records for this module. + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return error("Malformed block"); + case BitstreamEntry::EndBlock: + if (Table.empty()) + return std::error_code(); + return error("Missing VST"); + + case BitstreamEntry::SubBlock: + switch (Entry.ID) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return error("Invalid record"); + break; + case bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) + return error("Malformed block"); + break; + case bitc::VALUE_SYMTAB_BLOCK_ID: + if (!DL) + DL.reset(new DataLayout("")); + for (auto &AliasInfo : Aliasing) { + auto Alias = AliasInfo.first; + auto Aliasee = AliasInfo.second; + if (Alias > (int)Table.size() || Aliasee > (int)Table.size()) + return error("Invalid Alias information"); + Table.getSymbols()[Alias].setFunction( + Table.getSymbols()[Aliasee].isFunction()); + } + if (std::error_code EC = parseValueSymbolTable(Table, *DL)) + return EC; + return std::error_code(); + } + continue; + + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + auto BitCode = Stream.readRecord(Entry.ID, Record); + switch (BitCode) { + default: + break; // Default behavior, ignore unknown content. + case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] + std::string S; + if (convertToString(Record, 0, S)) + return error("Invalid record"); + Table.setTriple(S); + break; + } + case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] + std::string S; + if (convertToString(Record, 0, S)) + return error("Invalid record"); + Table.setDataLayout(S); + DL.reset(new DataLayout(S)); + break; + } + case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] + std::string S; + if (convertToString(Record, 0, S)) + return error("Invalid record"); + Table.setModuleInlineAsm(S); + break; + } + case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] + std::string S; + if (convertToString(Record, 0, S)) + return error("Invalid record"); + SectionTable.push_back(S); + break; + } + case bitc::MODULE_CODE_COMDAT: { // COMDAT: [selection_kind, name] + if (Record.size() < 2) + return error("Invalid record"); + Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]); + unsigned ComdatNameSize = Record[1]; + std::string ComdatName; + ComdatName.reserve(ComdatNameSize); + for (unsigned i = 0; i != ComdatNameSize; ++i) + ComdatName += (char)Record[2 + i]; + ComdatList.push_back(std::make_pair(ComdatName, SK)); + break; + } + // GLOBALVAR: [pointer type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr, externally_initialized, dllstorageclass, + // comdat] + case bitc::MODULE_CODE_GLOBALVAR: { + if (Record.size() < 6) + return error("Invalid record"); + + BitcodeSymbol Sym; + + // Check if there is a global initializer. + unsigned InitID = Record[2]; + if (!InitID) + Sym.setUndefined(); + + bool isConstant = Record[1] & 1; + Sym.setConst(isConstant); + + if (Record[5]) { + if (Record[5] - 1 >= SectionTable.size()) + return error("Invalid ID"); + Sym.setSection(SectionTable[Record[5] - 1]); + } + + uint64_t RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; + // Local linkage must have default visibility. + if (Record.size() > 6 && !GlobalValue::isLocalLinkage(Linkage)) + Visibility = getDecodedVisibility(Record[6]); + + GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; + if (Record.size() > 8) + UnnamedAddr = getDecodedUnnamedAddrType(Record[8]); + + updateSymbolFlags(Sym, Linkage, Visibility, UnnamedAddr); + + if (Record.size() > 10 && + getDecodedDLLStorageClass(Record[10]) == + GlobalValue::DLLImportStorageClass) + Sym.setDLLImportStorageClass(); + + if (Record.size() > 11) { + if (unsigned ComdatID = Record[11]) { + if (ComdatID > ComdatList.size()) + return error("Invalid global variable comdat ID"); + Sym.setComdat(ComdatList[ComdatID - 1].first); + } + } else if (hasImplicitComdat(RawLinkage)) + Sym.setComdat("implicit"); // FIXME? + + Table.addSymbol(std::move(Sym)); + break; + } + // FUNCTION: [type, callingconv, isproto, linkage, paramattr, + // alignment, section, visibility, gc, unnamed_addr, + // prologuedata, dllstorageclass, comdat, prefixdata] + case bitc::MODULE_CODE_FUNCTION: { + if (Record.size() < 8) + return error("Invalid record"); + + BitcodeSymbol Sym; + Sym.setFunction(); + + // Check if there is a global initializer. + unsigned IsProto = Record[2]; + if (IsProto) + Sym.setUndefined(); + + uint64_t RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + + StringRef Section; + if (Record[6]) { + if (Record[6] - 1 >= SectionTable.size()) + return error("Invalid ID"); + Sym.setSection(SectionTable[Record[6] - 1]); + } + GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; + // Local linkage must have default visibility. + if (Record.size() > 7 && !GlobalValue::isLocalLinkage(Linkage)) + Visibility = getDecodedVisibility(Record[7]); + + GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; + if (Record.size() > 9) + UnnamedAddr = getDecodedUnnamedAddrType(Record[9]); + + updateSymbolFlags(Sym, Linkage, Visibility, UnnamedAddr); + + if (Record.size() > 11 && + getDecodedDLLStorageClass(Record[11]) == + GlobalValue::DLLImportStorageClass) + Sym.setDLLImportStorageClass(); + + if (Record.size() > 12) { + if (unsigned ComdatID = Record[12]) { + if (ComdatID > ComdatList.size()) + return error("Invalid global variable comdat ID"); + Sym.setComdat(ComdatList[ComdatID - 1].first); + } + } else if (hasImplicitComdat(RawLinkage)) + Sym.setComdat("implicit"); // FIXME? + + Table.addSymbol(std::move(Sym)); + break; + } + // ALIAS: [alias type, addrspace, aliasee val#, linkage] + // ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, + // dllstorageclass] + // IFUNC: [alias type, addrspace, aliasee val#, linkage, visibility, + // dllstorageclass] + case bitc::MODULE_CODE_IFUNC: + case bitc::MODULE_CODE_ALIAS: + case bitc::MODULE_CODE_ALIAS_OLD: { + bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; + if (Record.size() < (3 + (unsigned)NewRecord)) + return error("Invalid record"); + + BitcodeSymbol Sym; + Sym.setAlias(); + + auto Aliasee = Record[2]; + auto RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + updateSymbolFlags(Sym, Linkage, GlobalValue::DefaultVisibility, + GlobalValue::UnnamedAddr::None); + + if (Record.size() > 5 && + getDecodedDLLStorageClass(Record[5]) == + GlobalValue::DLLImportStorageClass) + Sym.setDLLImportStorageClass(); + + Aliasing.push_back(std::make_pair(Table.size(), Aliasee)); + Table.addSymbol(std::move(Sym)); + break; + } + /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] + case bitc::MODULE_CODE_SOURCE_FILENAME: + SmallString<128> ValueName; + if (convertToString(Record, 0, ValueName)) + return error("Invalid record"); + Table.setSourceFileName(ValueName.str()); + break; + } + Record.clear(); + } +} + namespace { // FIXME: This class is only here to support the transition to llvm::Error. It // will be removed once this transition is complete. Clients should prefer to @@ -6687,3 +7230,13 @@ Buf.release(); // The ModuleSummaryIndexBitcodeReader owns it now. return R.foundGlobalValSummary(); } + +ErrorOr +llvm::parseBitcodeSymbolTable(MemoryBufferRef Buffer) { + std::unique_ptr Buf = MemoryBuffer::getMemBuffer(Buffer, false); + SymbolTableReader R(Buffer, [](std::error_code EC, const Twine &Message) { + errs() << Message; + return EC; + }); + return R.parseBitcodeSymbolTable(); +} Index: lib/IR/Mangler.cpp =================================================================== --- lib/IR/Mangler.cpp +++ lib/IR/Mangler.cpp @@ -21,16 +21,8 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; -namespace { -enum ManglerPrefixTy { - Default, ///< Emit default string before each symbol. - Private, ///< Emit "private" prefix before each symbol. - LinkerPrivate ///< Emit "linker private" prefix before each symbol. -}; -} - static void getNameWithPrefixImpl(raw_ostream &OS, const Twine &GVName, - ManglerPrefixTy PrefixTy, + Mangler::ManglerPrefixTy PrefixTy, const DataLayout &DL, char Prefix) { SmallString<256> TmpData; StringRef Name = GVName.toStringRef(TmpData); @@ -43,9 +35,9 @@ return; } - if (PrefixTy == Private) + if (PrefixTy == Mangler::Private) OS << DL.getPrivateGlobalPrefix(); - else if (PrefixTy == LinkerPrivate) + else if (PrefixTy == Mangler::LinkerPrivate) OS << DL.getLinkerPrivateGlobalPrefix(); if (Prefix != '\0') @@ -57,21 +49,23 @@ static void getNameWithPrefixImpl(raw_ostream &OS, const Twine &GVName, const DataLayout &DL, - ManglerPrefixTy PrefixTy) { + Mangler::ManglerPrefixTy PrefixTy) { char Prefix = DL.getGlobalPrefix(); return getNameWithPrefixImpl(OS, GVName, PrefixTy, DL, Prefix); } void Mangler::getNameWithPrefix(raw_ostream &OS, const Twine &GVName, - const DataLayout &DL) { - return getNameWithPrefixImpl(OS, GVName, DL, Default); + const DataLayout &DL, + ManglerPrefixTy PrefixTy) { + return getNameWithPrefixImpl(OS, GVName, DL, PrefixTy); } void Mangler::getNameWithPrefix(SmallVectorImpl &OutName, - const Twine &GVName, const DataLayout &DL) { + const Twine &GVName, const DataLayout &DL, + ManglerPrefixTy PrefixTy) { raw_svector_ostream OS(OutName); char Prefix = DL.getGlobalPrefix(); - return getNameWithPrefixImpl(OS, GVName, Default, DL, Prefix); + return getNameWithPrefixImpl(OS, GVName, PrefixTy, DL, Prefix); } static bool hasByteCountSuffix(CallingConv::ID CC) { Index: lib/LTO/LTOCodeGenerator.cpp =================================================================== --- lib/LTO/LTOCodeGenerator.cpp +++ lib/LTO/LTOCodeGenerator.cpp @@ -131,14 +131,15 @@ } bool LTOCodeGenerator::addModule(LTOModule *Mod) { - assert(&Mod->getModule().getContext() == &Context && - "Expected module in same context"); - - bool ret = TheLinker->linkInModule(Mod->takeModule()); + auto Buffer = Mod->getBuffer(); + ErrorOr> ErrOrMod = parseBitcodeFile(Buffer, Context); + if (ErrOrMod.getError()) + return false; + bool ret = TheLinker->linkInModule(std::move(ErrOrMod.get())); - const std::vector &undefs = Mod->getAsmUndefinedRefs(); - for (int i = 0, e = undefs.size(); i != e; ++i) - AsmUndefinedRefs[undefs[i]] = 1; + for (auto &Sym : Mod->getSymbols()) + if (Sym.isAsm() && Sym.isUndefined()) + AsmUndefinedRefs[Sym.getName()] = 1; // We've just changed the input, so let's make sure we verify it. HasVerifiedInput = false; @@ -147,17 +148,18 @@ } void LTOCodeGenerator::setModule(std::unique_ptr Mod) { - assert(&Mod->getModule().getContext() == &Context && - "Expected module in same context"); - AsmUndefinedRefs.clear(); + auto Buffer = Mod->getBuffer(); + ErrorOr> ErrOrMod = parseBitcodeFile(Buffer, Context); + if (ErrOrMod.getError()) + return; - MergedModule = Mod->takeModule(); + MergedModule = std::move(ErrOrMod.get()); TheLinker = make_unique(*MergedModule); - const std::vector &Undefs = Mod->getAsmUndefinedRefs(); - for (int I = 0, E = Undefs.size(); I != E; ++I) - AsmUndefinedRefs[Undefs[I]] = 1; + for (auto &Sym : Mod->getSymbols()) + if (Sym.isAsm() && Sym.isUndefined()) + AsmUndefinedRefs[Sym.getName()] = 1; // We've just changed the input, so let's make sure we verify it. HasVerifiedInput = false; @@ -517,6 +519,9 @@ if (!this->determineTarget()) return false; + // Add an appropriate DataLayout instance for this module... + MergedModule->setDataLayout(TargetMach->createDataLayout()); + // We always run the verifier once on the merged module, the `DisableVerify` // parameter only applies to subsequent verify. verifyMergedModuleOnce(); @@ -527,9 +532,6 @@ // Instantiate the pass manager to organize the passes. legacy::PassManager passes; - // Add an appropriate DataLayout instance for this module... - MergedModule->setDataLayout(TargetMach->createDataLayout()); - passes.add( createTargetTransformInfoWrapperPass(TargetMach->getTargetIRAnalysis())); Index: lib/LTO/LTOModule.cpp =================================================================== --- lib/LTO/LTOModule.cpp +++ lib/LTO/LTOModule.cpp @@ -31,7 +31,7 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/BitcodeObjectFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -49,16 +49,28 @@ using namespace llvm; using namespace llvm::object; -LTOModule::LTOModule(std::unique_ptr Obj, - llvm::TargetMachine *TM) - : IRFile(std::move(Obj)), _target(TM) {} +LTOModule::LTOModule(std::unique_ptr RawBuffer, + MemoryBufferRef Buffer) + : RawBuffer(std::move(RawBuffer)), Buffer(Buffer) { -LTOModule::~LTOModule() {} + // Get a bitcode object file and keep only the symbol table + auto Object = BitcodeObjectFile::create(Buffer); + if (!Object) + return; + Table = Object.get()->takeSymbolTable(); + auto &Syms = Table.getSymbols(); + // Filter out "format specific" symbols, they are not to be exposed to the + // linker + Syms.erase(std::remove_if(Syms.begin(), Syms.end(), + [](const BitcodeSymbol &Sym) { + return Sym.isFormatSpecific(); + }), + Syms.end()); +} -/// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM -/// bitcode. +/// Returns 'true' if the file (or memory contents) is LLVM bitcode. bool LTOModule::isBitcodeFile(const void *Mem, size_t Length) { - ErrorOr BCData = IRObjectFile::findBitcodeInMemBuffer( + ErrorOr BCData = BitcodeObjectFile::findBitcodeInMemBuffer( MemoryBufferRef(StringRef((const char *)Mem, Length), "")); return bool(BCData); } @@ -69,7 +81,7 @@ if (!BufferOrErr) return false; - ErrorOr BCData = IRObjectFile::findBitcodeInMemBuffer( + ErrorOr BCData = BitcodeObjectFile::findBitcodeInMemBuffer( BufferOrErr.get()->getMemBufferRef()); return bool(BCData); } @@ -77,19 +89,18 @@ bool LTOModule::isThinLTO() { // Right now the detection is only based on the summary presence. We may want // to add a dedicated flag at some point. - return hasGlobalValueSummary(IRFile->getMemoryBufferRef(), - [](const DiagnosticInfo &DI) { - DiagnosticPrinterRawOStream DP(errs()); - DI.print(DP); - errs() << '\n'; - return; - }); + return hasGlobalValueSummary(getBuffer(), [](const DiagnosticInfo &DI) { + DiagnosticPrinterRawOStream DP(errs()); + DI.print(DP); + errs() << '\n'; + return; + }); } bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer, StringRef TriplePrefix) { ErrorOr BCOrErr = - IRObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef()); + BitcodeObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef()); if (!BCOrErr) return false; LLVMContext Context; @@ -99,7 +110,7 @@ std::string LTOModule::getProducerString(MemoryBuffer *Buffer) { ErrorOr BCOrErr = - IRObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef()); + BitcodeObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef()); if (!BCOrErr) return ""; LLVMContext Context; @@ -107,536 +118,119 @@ } ErrorOr> -LTOModule::createFromFile(LLVMContext &Context, const char *path, - const TargetOptions &options) { +LTOModule::createFromFile(const char *path) { ErrorOr> BufferOrErr = MemoryBuffer::getFile(path); - if (std::error_code EC = BufferOrErr.getError()) { - Context.emitError(EC.message()); + if (std::error_code EC = BufferOrErr.getError()) return EC; - } std::unique_ptr Buffer = std::move(BufferOrErr.get()); - return makeLTOModule(Buffer->getMemBufferRef(), options, Context, - /* ShouldBeLazy*/ false); + return makeLTOModule(std::move(Buffer)); } ErrorOr> -LTOModule::createFromOpenFile(LLVMContext &Context, int fd, const char *path, - size_t size, const TargetOptions &options) { - return createFromOpenFileSlice(Context, fd, path, size, 0, options); +LTOModule::createFromOpenFile(int fd, const char *path, size_t size) { + return createFromOpenFileSlice(fd, path, size, 0); } ErrorOr> -LTOModule::createFromOpenFileSlice(LLVMContext &Context, int fd, - const char *path, size_t map_size, - off_t offset, const TargetOptions &options) { +LTOModule::createFromOpenFileSlice(int fd, const char *path, size_t map_size, + off_t offset) { ErrorOr> BufferOrErr = MemoryBuffer::getOpenFileSlice(fd, path, map_size, offset); - if (std::error_code EC = BufferOrErr.getError()) { - Context.emitError(EC.message()); + if (std::error_code EC = BufferOrErr.getError()) return EC; - } std::unique_ptr Buffer = std::move(BufferOrErr.get()); - return makeLTOModule(Buffer->getMemBufferRef(), options, Context, - /* ShouldBeLazy */ false); + return makeLTOModule(std::move(Buffer)); } ErrorOr> -LTOModule::createFromBuffer(LLVMContext &Context, const void *mem, - size_t length, const TargetOptions &options, - StringRef path) { - StringRef Data((const char *)mem, length); - MemoryBufferRef Buffer(Data, path); - return makeLTOModule(Buffer, options, Context, /* ShouldBeLazy */ false); -} - -ErrorOr> -LTOModule::createInLocalContext(std::unique_ptr Context, - const void *mem, size_t length, - const TargetOptions &options, StringRef path) { - StringRef Data((const char *)mem, length); - MemoryBufferRef Buffer(Data, path); - // If we own a context, we know this is being used only for symbol extraction, - // not linking. Be lazy in that case. - ErrorOr> Ret = - makeLTOModule(Buffer, options, *Context, /* ShouldBeLazy */ true); - if (Ret) - (*Ret)->OwnedContext = std::move(Context); - return Ret; -} - -static ErrorOr> -parseBitcodeFileImpl(MemoryBufferRef Buffer, LLVMContext &Context, - bool ShouldBeLazy) { - - // Find the buffer. - ErrorOr MBOrErr = - IRObjectFile::findBitcodeInMemBuffer(Buffer); - if (std::error_code EC = MBOrErr.getError()) { - Context.emitError(EC.message()); - return EC; - } - - if (!ShouldBeLazy) { - // Parse the full file. - ErrorOr> M = parseBitcodeFile(*MBOrErr, Context); - if (std::error_code EC = M.getError()) - return EC; - return std::move(*M); - } - - // Parse lazily. - std::unique_ptr LightweightBuf = - MemoryBuffer::getMemBuffer(*MBOrErr, false); - ErrorOr> M = getLazyBitcodeModule( - std::move(LightweightBuf), Context, true /*ShouldLazyLoadMetadata*/); - if (std::error_code EC = M.getError()) - return EC; - return std::move(*M); +LTOModule::createFromBuffer(const void *mem, size_t length, StringRef path) { + return makeLTOModule(makeBuffer(mem, length, path)); } ErrorOr> -LTOModule::makeLTOModule(MemoryBufferRef Buffer, const TargetOptions &options, - LLVMContext &Context, bool ShouldBeLazy) { - ErrorOr> MOrErr = - parseBitcodeFileImpl(Buffer, Context, ShouldBeLazy); - if (std::error_code EC = MOrErr.getError()) - return EC; - std::unique_ptr &M = *MOrErr; - - std::string TripleStr = M->getTargetTriple(); - if (TripleStr.empty()) - TripleStr = sys::getDefaultTargetTriple(); - llvm::Triple Triple(TripleStr); - - // find machine architecture for this module - std::string errMsg; - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (!march) - return std::unique_ptr(nullptr); - - // construct LTOModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); - // Set a default CPU for Darwin triples. - std::string CPU; - if (Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::x86_64) - CPU = "core2"; - else if (Triple.getArch() == llvm::Triple::x86) - CPU = "yonah"; - else if (Triple.getArch() == llvm::Triple::aarch64) - CPU = "cyclone"; - } - - TargetMachine *target = - march->createTargetMachine(TripleStr, CPU, FeatureStr, options, None); - M->setDataLayout(target->createDataLayout()); - - std::unique_ptr IRObj( - new object::IRObjectFile(Buffer, std::move(M))); +LTOModule::makeLTOModule(std::unique_ptr Buffer) { + ErrorOr BCData = + BitcodeObjectFile::findBitcodeInMemBuffer(*Buffer); + if (!BCData) + return BCData.getError(); - std::unique_ptr Ret(new LTOModule(std::move(IRObj), target)); - Ret->parseSymbols(); - Ret->parseMetadata(); + std::unique_ptr Ret( + new LTOModule(std::move(Buffer), BCData.get())); + Ret->parseLinkerOptions(); return std::move(Ret); } -/// Create a MemoryBuffer from a memory range with an optional name. +// Create a MemoryBuffer from a memory range with an optional name. std::unique_ptr LTOModule::makeBuffer(const void *mem, size_t length, StringRef name) { const char *startPtr = (const char*)mem; return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), name, false); } -/// objcClassNameFromExpression - Get string that the data pointer points to. -bool -LTOModule::objcClassNameFromExpression(const Constant *c, std::string &name) { - if (const ConstantExpr *ce = dyn_cast(c)) { - Constant *op = ce->getOperand(0); - if (GlobalVariable *gvn = dyn_cast(op)) { - Constant *cn = gvn->getInitializer(); - if (ConstantDataArray *ca = dyn_cast(cn)) { - if (ca->isCString()) { - name = (".objc_class_name_" + ca->getAsCString()).str(); - return true; - } - } - } - } - return false; -} - -/// addObjCClass - Parse i386/ppc ObjC class data structure. -void LTOModule::addObjCClass(const GlobalVariable *clgv) { - const ConstantStruct *c = dyn_cast(clgv->getInitializer()); - if (!c) return; - - // second slot in __OBJC,__class is pointer to superclass name - std::string superclassName; - if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { - auto IterBool = - _undefines.insert(std::make_pair(superclassName, NameAndAttributes())); - if (IterBool.second) { - NameAndAttributes &info = IterBool.first->second; - info.name = IterBool.first->first().data(); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - } - } +/// Generates LTO attributes from a BitcodeSymbol +lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t Index) { + uint32_t Attrs = 0; + if (Index >= Table.size()) + return (lto_symbol_attributes)Attrs; + auto Sym = Table.getSymbols()[Index]; - // third slot in __OBJC,__class is pointer to class name - std::string className; - if (objcClassNameFromExpression(c->getOperand(2), className)) { - auto Iter = _defines.insert(className).first; - - NameAndAttributes info; - info.name = Iter->first().data(); - info.attributes = LTO_SYMBOL_PERMISSIONS_DATA | - LTO_SYMBOL_DEFINITION_REGULAR | LTO_SYMBOL_SCOPE_DEFAULT; - info.isFunction = false; - info.symbol = clgv; - _symbols.push_back(info); - } -} - -/// addObjCCategory - Parse i386/ppc ObjC category data structure. -void LTOModule::addObjCCategory(const GlobalVariable *clgv) { - const ConstantStruct *c = dyn_cast(clgv->getInitializer()); - if (!c) return; - - // second slot in __OBJC,__category is pointer to target class name - std::string targetclassName; - if (!objcClassNameFromExpression(c->getOperand(1), targetclassName)) - return; - - auto IterBool = - _undefines.insert(std::make_pair(targetclassName, NameAndAttributes())); - - if (!IterBool.second) - return; - - NameAndAttributes &info = IterBool.first->second; - info.name = IterBool.first->first().data(); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; -} - -/// addObjCClassRef - Parse i386/ppc ObjC class list data structure. -void LTOModule::addObjCClassRef(const GlobalVariable *clgv) { - std::string targetclassName; - if (!objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) - return; - - auto IterBool = - _undefines.insert(std::make_pair(targetclassName, NameAndAttributes())); - - if (!IterBool.second) - return; - - NameAndAttributes &info = IterBool.first->second; - info.name = IterBool.first->first().data(); - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; -} - -void LTOModule::addDefinedDataSymbol(const object::BasicSymbolRef &Sym) { - SmallString<64> Buffer; - { - raw_svector_ostream OS(Buffer); - Sym.printName(OS); - } - - const GlobalValue *V = IRFile->getSymbolGV(Sym.getRawDataRefImpl()); - addDefinedDataSymbol(Buffer.c_str(), V); -} - -void LTOModule::addDefinedDataSymbol(const char *Name, const GlobalValue *v) { - // Add to list of defined symbols. - addDefinedSymbol(Name, v, false); - - if (!v->hasSection() /* || !isTargetDarwin */) - return; - - // Special case i386/ppc ObjC data structures in magic sections: - // The issue is that the old ObjC object format did some strange - // contortions to avoid real linker symbols. For instance, the - // ObjC class data structure is allocated statically in the executable - // that defines that class. That data structures contains a pointer to - // its superclass. But instead of just initializing that part of the - // struct to the address of its superclass, and letting the static and - // dynamic linkers do the rest, the runtime works by having that field - // instead point to a C-string that is the name of the superclass. - // At runtime the objc initialization updates that pointer and sets - // it to point to the actual super class. As far as the linker - // knows it is just a pointer to a string. But then someone wanted the - // linker to issue errors at build time if the superclass was not found. - // So they figured out a way in mach-o object format to use an absolute - // symbols (.objc_class_name_Foo = 0) and a floating reference - // (.reference .objc_class_name_Bar) to cause the linker into erroring when - // a class was missing. - // The following synthesizes the implicit .objc_* symbols for the linker - // from the ObjC data structures generated by the front end. - - // special case if this data blob is an ObjC class definition - std::string Section = v->getSection(); - if (Section.compare(0, 15, "__OBJC,__class,") == 0) { - if (const GlobalVariable *gv = dyn_cast(v)) { - addObjCClass(gv); - } - } - - // special case if this data blob is an ObjC category definition - else if (Section.compare(0, 18, "__OBJC,__category,") == 0) { - if (const GlobalVariable *gv = dyn_cast(v)) { - addObjCCategory(gv); - } - } - - // special case if this data blob is the list of referenced classes - else if (Section.compare(0, 18, "__OBJC,__cls_refs,") == 0) { - if (const GlobalVariable *gv = dyn_cast(v)) { - addObjCClassRef(gv); - } - } -} - -void LTOModule::addDefinedFunctionSymbol(const object::BasicSymbolRef &Sym) { - SmallString<64> Buffer; - { - raw_svector_ostream OS(Buffer); - Sym.printName(OS); - } - - const Function *F = - cast(IRFile->getSymbolGV(Sym.getRawDataRefImpl())); - addDefinedFunctionSymbol(Buffer.c_str(), F); -} - -void LTOModule::addDefinedFunctionSymbol(const char *Name, const Function *F) { - // add to list of defined symbols - addDefinedSymbol(Name, F, true); -} - -void LTOModule::addDefinedSymbol(const char *Name, const GlobalValue *def, - bool isFunction) { - // set alignment part log2() can have rounding errors - uint32_t align = def->getAlignment(); - uint32_t attr = align ? countTrailingZeros(align) : 0; + if (Sym.isUndefined()) + return LTO_SYMBOL_DEFINITION_UNDEFINED; // set permissions part - if (isFunction) { - attr |= LTO_SYMBOL_PERMISSIONS_CODE; + if (Sym.isFunction()) { + Attrs |= LTO_SYMBOL_PERMISSIONS_CODE; } else { - const GlobalVariable *gv = dyn_cast(def); - if (gv && gv->isConstant()) - attr |= LTO_SYMBOL_PERMISSIONS_RODATA; + if (Sym.isConst()) + Attrs |= LTO_SYMBOL_PERMISSIONS_RODATA; else - attr |= LTO_SYMBOL_PERMISSIONS_DATA; + Attrs |= LTO_SYMBOL_PERMISSIONS_DATA; } // set definition part - if (def->hasWeakLinkage() || def->hasLinkOnceLinkage()) - attr |= LTO_SYMBOL_DEFINITION_WEAK; - else if (def->hasCommonLinkage()) - attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; + if (Sym.isWeak()) + Attrs |= LTO_SYMBOL_DEFINITION_WEAK; + else if (Sym.isCommon()) + Attrs |= LTO_SYMBOL_DEFINITION_TENTATIVE; else - attr |= LTO_SYMBOL_DEFINITION_REGULAR; + Attrs |= LTO_SYMBOL_DEFINITION_REGULAR; // set scope part - if (def->hasLocalLinkage()) - // Ignore visibility if linkage is local. - attr |= LTO_SYMBOL_SCOPE_INTERNAL; - else if (def->hasHiddenVisibility()) - attr |= LTO_SYMBOL_SCOPE_HIDDEN; - else if (def->hasProtectedVisibility()) - attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if (canBeOmittedFromSymbolTable(def)) - attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; + if (!(Sym.isGlobal())) + Attrs |= LTO_SYMBOL_SCOPE_INTERNAL; + else if (Sym.isHidden()) + Attrs |= LTO_SYMBOL_SCOPE_HIDDEN; + else if (Sym.isProtected()) + Attrs |= LTO_SYMBOL_SCOPE_PROTECTED; + else if (Sym.canBeOmittedFromSymbolTable()) + Attrs |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; else - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - - if (def->hasComdat()) - attr |= LTO_SYMBOL_COMDAT; + Attrs |= LTO_SYMBOL_SCOPE_DEFAULT; - if (isa(def)) - attr |= LTO_SYMBOL_ALIAS; + if (!Sym.getComdat().empty()) + Attrs |= LTO_SYMBOL_COMDAT; - auto Iter = _defines.insert(Name).first; + if (Sym.isAlias()) + Attrs |= LTO_SYMBOL_ALIAS; - // fill information structure - NameAndAttributes info; - StringRef NameRef = Iter->first(); - info.name = NameRef.data(); - assert(info.name[NameRef.size()] == '\0'); - info.attributes = attr; - info.isFunction = isFunction; - info.symbol = def; - - // add to table of symbols - _symbols.push_back(info); + return (lto_symbol_attributes)Attrs; } -/// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the -/// defined list. -void LTOModule::addAsmGlobalSymbol(const char *name, - lto_symbol_attributes scope) { - auto IterBool = _defines.insert(name); - - // only add new define if not already defined - if (!IterBool.second) - return; - - NameAndAttributes &info = _undefines[IterBool.first->first().data()]; - - if (info.symbol == nullptr) { - // FIXME: This is trying to take care of module ASM like this: - // - // module asm ".zerofill __FOO, __foo, _bar_baz_qux, 0" - // - // but is gross and its mother dresses it funny. Have the ASM parser give us - // more details for this type of situation so that we're not guessing so - // much. - - // fill information structure - info.name = IterBool.first->first().data(); - info.attributes = - LTO_SYMBOL_PERMISSIONS_DATA | LTO_SYMBOL_DEFINITION_REGULAR | scope; - info.isFunction = false; - info.symbol = nullptr; - - // add to table of symbols - _symbols.push_back(info); - return; - } - - if (info.isFunction) - addDefinedFunctionSymbol(info.name, cast(info.symbol)); - else - addDefinedDataSymbol(info.name, info.symbol); - - _symbols.back().attributes &= ~LTO_SYMBOL_SCOPE_MASK; - _symbols.back().attributes |= scope; -} - -/// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to the -/// undefined list. -void LTOModule::addAsmGlobalSymbolUndef(const char *name) { - auto IterBool = _undefines.insert(std::make_pair(name, NameAndAttributes())); - - _asm_undefines.push_back(IterBool.first->first().data()); - - // we already have the symbol - if (!IterBool.second) - return; - - uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - NameAndAttributes &info = IterBool.first->second; - info.name = IterBool.first->first().data(); - info.attributes = attr; - info.isFunction = false; - info.symbol = nullptr; -} - -/// Add a symbol which isn't defined just yet to a list to be resolved later. -void LTOModule::addPotentialUndefinedSymbol(const object::BasicSymbolRef &Sym, - bool isFunc) { - SmallString<64> name; - { - raw_svector_ostream OS(name); - Sym.printName(OS); - } - - auto IterBool = _undefines.insert(std::make_pair(name, NameAndAttributes())); - - // we already have the symbol - if (!IterBool.second) +/// Parse metadata from the module if the target is COFF +void LTOModule::parseLinkerOptions() { + if (!Triple(Table.getTriple()).isOSBinFormatCOFF()) return; - - NameAndAttributes &info = IterBool.first->second; - - info.name = IterBool.first->first().data(); - - const GlobalValue *decl = IRFile->getSymbolGV(Sym.getRawDataRefImpl()); - - if (decl->hasExternalWeakLinkage()) - info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; - else - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - - info.isFunction = isFunc; - info.symbol = decl; -} - -void LTOModule::parseSymbols() { - for (auto &Sym : IRFile->symbols()) { - const GlobalValue *GV = IRFile->getSymbolGV(Sym.getRawDataRefImpl()); - uint32_t Flags = Sym.getFlags(); - if (Flags & object::BasicSymbolRef::SF_FormatSpecific) - continue; - - bool IsUndefined = Flags & object::BasicSymbolRef::SF_Undefined; - - if (!GV) { - SmallString<64> Buffer; - { - raw_svector_ostream OS(Buffer); - Sym.printName(OS); - } - const char *Name = Buffer.c_str(); - - if (IsUndefined) - addAsmGlobalSymbolUndef(Name); - else if (Flags & object::BasicSymbolRef::SF_Global) - addAsmGlobalSymbol(Name, LTO_SYMBOL_SCOPE_DEFAULT); - else - addAsmGlobalSymbol(Name, LTO_SYMBOL_SCOPE_INTERNAL); - continue; - } - - auto *F = dyn_cast(GV); - if (IsUndefined) { - addPotentialUndefinedSymbol(Sym, F != nullptr); - continue; - } - - if (F) { - addDefinedFunctionSymbol(Sym); - continue; - } - - if (isa(GV)) { - addDefinedDataSymbol(Sym); - continue; - } - - assert(isa(GV)); - addDefinedDataSymbol(Sym); - } - - // make symbols for all undefines - for (StringMap::iterator u =_undefines.begin(), - e = _undefines.end(); u != e; ++u) { - // If this symbol also has a definition, then don't make an undefine because - // it is a tentative definition. - if (_defines.count(u->getKey())) continue; - NameAndAttributes info = u->getValue(); - _symbols.push_back(info); - } -} - -/// parseMetadata - Parse metadata from the module -void LTOModule::parseMetadata() { raw_string_ostream OS(LinkerOpts); + LLVMContext Context; + auto ErrOrMod = parseBitcodeFile(getBuffer(), Context); + if (!ErrOrMod) + return; + auto Mod = std::move(ErrOrMod.get()); // Linker Options - if (Metadata *Val = getModule().getModuleFlag("Linker Options")) { + if (Metadata *Val = Mod->getModuleFlag("Linker Options")) { MDNode *LinkerOptions = cast(Val); for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { MDNode *MDOptions = cast(LinkerOptions->getOperand(i)); @@ -647,14 +241,23 @@ } } - // Globals + // find machine architecture for this module + std::string errMsg; + const Target *Target = + TargetRegistry::lookupTarget(Table.getTriple(), errMsg); + if (!Target) + return; + + TargetOptions Options; + TargetMachine *TM = + Target->createTargetMachine(Table.getTriple(), "", "", Options, None); Mangler Mang; - for (const NameAndAttributes &Sym : _symbols) { - if (!Sym.symbol) - continue; - _target->getObjFileLowering()->emitLinkerFlagsForGlobal(OS, Sym.symbol, - Mang); - } + for (auto &GV : *Mod) + TM->getObjFileLowering()->emitLinkerFlagsForGlobal(OS, &GV, Mang); + for (auto &GV : Mod->globals()) + TM->getObjFileLowering()->emitLinkerFlagsForGlobal(OS, &GV, Mang); + for (auto &GV : Mod->aliases()) + TM->getObjFileLowering()->emitLinkerFlagsForGlobal(OS, &GV, Mang); // Add other interesting metadata here. } Index: lib/Object/BitcodeObjectFile.cpp =================================================================== --- /dev/null +++ lib/Object/BitcodeObjectFile.cpp @@ -0,0 +1,232 @@ +//=-- BitcodeObjectFile.cpp - IR object file implementation ------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Part of the BitcodeObjectFile class implementation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/BitcodeObjectFile.h" +#include "RecordStreamer.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/GVMaterializer.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; +using namespace object; + +BitcodeObjectFile::BitcodeObjectFile(MemoryBufferRef Object) + : SymbolicFile(Binary::ID_IR, Object) { + + auto ErrOrTable = parseBitcodeSymbolTable(Object); + if (ErrOrTable.getError()) + return; + SymbolTable = std::move(ErrOrTable.get()); + + CollectAsmUndefinedRefs(Triple(SymbolTable.getTriple()), + SymbolTable.getModuleInlineAsm(), + [this](StringRef Name, BitcodeSymbolFlags Flags) { + BitcodeSymbol Sym; + Sym.setAsm(); + Sym.setFlags(Flags); + Sym.setName(Name); + SymbolTable.addSymbol(std::move(Sym)); + }); +} + +// Parse inline ASM and collect the list of symbols that are not defined in +// the current module. This is inspired from BitcodeObjectFile. +void BitcodeObjectFile::CollectAsmUndefinedRefs( + const Triple &TT, StringRef InlineAsm, + function_ref AsmUndefinedRefs) { + if (InlineAsm.empty()) + return; + + std::string Err; + const Target *T = TargetRegistry::lookupTarget(TT.str(), Err); + if (!T) + return; + + std::unique_ptr MRI(T->createMCRegInfo(TT.str())); + if (!MRI) + return; + + std::unique_ptr MAI(T->createMCAsmInfo(*MRI, TT.str())); + if (!MAI) + return; + + std::unique_ptr STI( + T->createMCSubtargetInfo(TT.str(), "", "")); + if (!STI) + return; + + std::unique_ptr MCII(T->createMCInstrInfo()); + if (!MCII) + return; + + MCObjectFileInfo MOFI; + MCContext MCCtx(MAI.get(), MRI.get(), &MOFI); + MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, CodeModel::Default, MCCtx); + std::unique_ptr Streamer(new RecordStreamer(MCCtx)); + T->createNullTargetStreamer(*Streamer); + + std::unique_ptr Buffer(MemoryBuffer::getMemBuffer(InlineAsm)); + SourceMgr SrcMgr; + SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc()); + std::unique_ptr Parser( + createMCAsmParser(SrcMgr, MCCtx, *Streamer, *MAI)); + + MCTargetOptions MCOptions; + std::unique_ptr TAP( + T->createMCAsmParser(*STI, *Parser, *MCII, MCOptions)); + if (!TAP) + return; + + Parser->setTargetParser(*TAP); + if (Parser->Run(false)) + return; + + for (auto &KV : *Streamer) { + StringRef Key = KV.first(); + RecordStreamer::State Value = KV.second; + BitcodeSymbolFlags Flags = {}; + Flags.IsAsm = true; + Flags.IsFunction = true; // FIXME... + switch (Value) { + case RecordStreamer::NeverSeen: + llvm_unreachable("foo"); + case RecordStreamer::DefinedGlobal: + Flags.IsGlobal = true; + break; + case RecordStreamer::Defined: + break; + case RecordStreamer::Global: + case RecordStreamer::Used: + Flags.IsUndefined = true; + Flags.IsGlobal = true; + break; + case RecordStreamer::GlobalWeak: + Flags.IsWeak = true; + Flags.IsGlobal = true; + break; + } + AsmUndefinedRefs(Key, Flags); + } +} + +StringRef BitcodeObjectFile::getTargetTriple() { + return SymbolTable.getTriple(); +} + +void BitcodeObjectFile::moveSymbolNext(DataRefImpl &Symb) const { + auto *It = (BitcodeSymbol *)Symb.p; + assert(Symb.p >= (uintptr_t) & *SymbolTable.begin() && + Symb.p < (uintptr_t) & *SymbolTable.end() && "Out-of-bounds"); + Symb.p = (uintptr_t)(++It); +} + +BitcodeSymbol &BitcodeObjectFile::getSymbol(DataRefImpl Symb) { + return *(BitcodeSymbol *)Symb.p; +} + +std::error_code BitcodeObjectFile::printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const { + OS << ((BitcodeSymbol *)Symb.p)->getName(); + return std::error_code(); +} + +uint32_t BitcodeObjectFile::getSymbolFlags(DataRefImpl Symb) const { + uint32_t Flags = 0; + auto &Sym = *(BitcodeSymbol *)Symb.p; + if (Sym.isUndefined()) + Flags |= SymbolRef::SF_Undefined; + if (Sym.isGlobal()) + Flags |= SymbolRef::SF_Global; + if (Sym.isWeak()) + Flags |= SymbolRef::SF_Weak; + if (Sym.isCommon()) + Flags |= SymbolRef::SF_Common; + if (Sym.isFormatSpecific()) + Flags |= SymbolRef::SF_FormatSpecific; + if (Sym.isHidden()) + Flags |= SymbolRef::SF_Hidden; + if (Sym.isConst()) + Flags |= SymbolRef::SF_Const; + return Flags; +} + +basic_symbol_iterator BitcodeObjectFile::symbol_begin_impl() const { + // Module::const_iterator I = M->begin(); + DataRefImpl Ret; + Ret.p = (uintptr_t) & *SymbolTable.begin(); + return basic_symbol_iterator(BasicSymbolRef(Ret, this)); +} + +basic_symbol_iterator BitcodeObjectFile::symbol_end_impl() const { + DataRefImpl Ret; + Ret.p = (uintptr_t) & *SymbolTable.end(); + return basic_symbol_iterator(BasicSymbolRef(Ret, this)); +} + +ErrorOr +BitcodeObjectFile::findBitcodeInObject(const ObjectFile &Obj) { + for (const SectionRef &Sec : Obj.sections()) { + if (Sec.isBitcode()) { + StringRef SecContents; + if (std::error_code EC = Sec.getContents(SecContents)) + return EC; + return MemoryBufferRef(SecContents, Obj.getFileName()); + } + } + + return object_error::bitcode_section_not_found; +} + +ErrorOr +BitcodeObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { + sys::fs::file_magic Type = sys::fs::identify_magic(Object.getBuffer()); + switch (Type) { + case sys::fs::file_magic::bitcode: + return Object; + case sys::fs::file_magic::elf_relocatable: + case sys::fs::file_magic::macho_object: + case sys::fs::file_magic::coff_object: { + Expected> ObjFile = + ObjectFile::createObjectFile(Object, Type); + if (!ObjFile) + return errorToErrorCode(ObjFile.takeError()); + return findBitcodeInObject(*ObjFile->get()); + } + default: + return object_error::invalid_file_type; + } +} + +ErrorOr> +llvm::object::BitcodeObjectFile::create(MemoryBufferRef Object) { + ErrorOr BCOrErr = findBitcodeInMemBuffer(Object); + if (!BCOrErr) + return BCOrErr.getError(); + + return llvm::make_unique(BCOrErr.get()); +} Index: lib/Object/CMakeLists.txt =================================================================== --- lib/Object/CMakeLists.txt +++ lib/Object/CMakeLists.txt @@ -2,6 +2,7 @@ Archive.cpp ArchiveWriter.cpp Binary.cpp + BitcodeObjectFile.cpp COFFObjectFile.cpp ELF.cpp ELFObjectFile.cpp Index: lib/Object/SymbolicFile.cpp =================================================================== --- lib/Object/SymbolicFile.cpp +++ lib/Object/SymbolicFile.cpp @@ -11,11 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Object/BitcodeObjectFile.h" #include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" -#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/SymbolicFile.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; @@ -34,9 +34,7 @@ switch (Type) { case sys::fs::file_magic::bitcode: - if (Context) - return errorOrToExpected(IRObjectFile::create(Object, *Context)); - // Fallthrough + return errorOrToExpected(BitcodeObjectFile::create(Object)); case sys::fs::file_magic::unknown: case sys::fs::file_magic::archive: case sys::fs::file_magic::macho_universal_binary: @@ -65,17 +63,16 @@ case sys::fs::file_magic::coff_object: { Expected> Obj = ObjectFile::createObjectFile(Object, Type); - if (!Obj || !Context) + if (!Obj) return std::move(Obj); ErrorOr BCData = - IRObjectFile::findBitcodeInObject(*Obj->get()); + BitcodeObjectFile::findBitcodeInObject(*Obj->get()); if (!BCData) return std::move(Obj); - return errorOrToExpected(IRObjectFile::create( - MemoryBufferRef(BCData->getBuffer(), - Object.getBufferIdentifier()), *Context)); + return errorOrToExpected(BitcodeObjectFile::create( + MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()))); } } llvm_unreachable("Unexpected Binary File Type"); Index: test/tools/lto/hide-linkonce-odr.ll =================================================================== --- test/tools/lto/hide-linkonce-odr.ll +++ test/tools/lto/hide-linkonce-odr.ll @@ -16,6 +16,7 @@ target triple = "x86_64-apple-macosx10.10.0" +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" declare void @external() Index: test/tools/lto/opt-level.ll =================================================================== --- test/tools/lto/opt-level.ll +++ test/tools/lto/opt-level.ll @@ -5,6 +5,7 @@ ; RUN: llvm-nm -no-llvm-bc %t.dylib | FileCheck --check-prefix=CHECK-O2 %s target triple = "x86_64-apple-macosx10.8.0" +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" ; CHECK-O0: t _f1 ; CHECK-O2-NOT: _f1 Index: tools/llvm-lto/llvm-lto.cpp =================================================================== --- tools/llvm-lto/llvm-lto.cpp +++ tools/llvm-lto/llvm-lto.cpp @@ -251,11 +251,10 @@ CurrentActivity = ("loading file '" + Path + "'").str(); std::unique_ptr Context = llvm::make_unique(); Context->setDiagnosticHandler(diagnosticHandlerWithContext, nullptr, true); - ErrorOr> Ret = LTOModule::createInLocalContext( - std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(), - Options, Path); + ErrorOr> Ret = LTOModule::createFromBuffer( + Buffer->getBufferStart(), Buffer->getBufferSize(), Path); CurrentActivity = ""; - maybeVerifyModule((*Ret)->getModule()); + error(Ret, "error loading file '" + Path + "'"); return std::move(*Ret); } @@ -771,9 +770,9 @@ for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { CurrentActivity = "loading file '" + InputFilenames[i] + "'"; ErrorOr> ModuleOrErr = - LTOModule::createFromFile(Context, InputFilenames[i].c_str(), Options); + LTOModule::createFromFile(InputFilenames[i].c_str()); + error(ModuleOrErr, "error " + CurrentActivity); std::unique_ptr &Module = *ModuleOrErr; - CurrentActivity = ""; unsigned NumSyms = Module->getSymbolCount(); for (unsigned I = 0; I < NumSyms; ++I) { @@ -795,6 +794,7 @@ // Print a message here so that we know addModule() did not abort. error("error adding file '" + InputFilenames[i] + "'"); } + CurrentActivity = ""; } // Add all the exported symbols to the table of symbols to preserve. Index: tools/llvm-nm/llvm-nm.cpp =================================================================== --- tools/llvm-nm/llvm-nm.cpp +++ tools/llvm-nm/llvm-nm.cpp @@ -23,9 +23,9 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/BitcodeObjectFile.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" @@ -265,12 +265,8 @@ } static char isSymbolList64Bit(SymbolicFile &Obj) { - if (isa(Obj)) { - IRObjectFile *IRobj = dyn_cast(&Obj); - Module &M = IRobj->getModule(); - if (M.getTargetTriple().empty()) - return false; - Triple T(M.getTargetTriple()); + if (BitcodeObjectFile *IRObj = dyn_cast(&Obj)) { + Triple T(IRObj->getTargetTriple()); return T.isArch64Bit(); } if (isa(Obj)) @@ -284,7 +280,8 @@ typedef std::vector SymbolListT; static SymbolListT SymbolList; -static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I); +static char getSymbolNMTypeChar(BitcodeObjectFile &Obj, + basic_symbol_iterator I); // darwinPrintSymbol() is used to print a symbol from a Mach-O file when the // the OutputFormat is darwin or we are printing Mach-O symbols in hex. For @@ -320,7 +317,7 @@ if (SymFlags & SymbolRef::SF_Const) NSect = 3; else { - IRObjectFile *IRobj = dyn_cast(&Obj); + BitcodeObjectFile *IRobj = dyn_cast(&Obj); NSect = (getSymbolNMTypeChar(*IRobj, I->Sym) == 't') ? 1 : 2; } } @@ -877,15 +874,10 @@ return '?'; } -static char getSymbolNMTypeChar(const GlobalValue &GV) { - // FIXME: should we print 'b'? At the IR level we cannot be sure if this - // will be in bss or not, but we could approximate. - return GV.getValueType()->isFunctionTy() ? 't' : 'd'; -} - -static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) { - const GlobalValue *GV = Obj.getSymbolGV(I->getRawDataRefImpl()); - return !GV ? 't' : getSymbolNMTypeChar(*GV); +static char getSymbolNMTypeChar(BitcodeObjectFile &Obj, + basic_symbol_iterator I) { + auto Symb = Obj.getSymbol(I->getRawDataRefImpl()); + return (Symb.isFunction()) ? 't' : 'd'; } static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) { @@ -910,7 +902,7 @@ char Ret = '?'; if (Symflags & object::SymbolRef::SF_Absolute) Ret = 'a'; - else if (IRObjectFile *IR = dyn_cast(&Obj)) { + else if (BitcodeObjectFile *IR = dyn_cast(&Obj)) { Ret = getSymbolNMTypeChar(*IR, I); Triple Host(sys::getDefaultTargetTriple()); if (Ret == 'd' && Host.isOSDarwin() && Symflags & SymbolRef::SF_Const) @@ -996,9 +988,9 @@ if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific)) continue; if (WithoutAliases) { - if (IRObjectFile *IR = dyn_cast(&Obj)) { - const GlobalValue *GV = IR->getSymbolGV(Sym.getRawDataRefImpl()); - if (GV && isa(GV)) + if (BitcodeObjectFile *IR = dyn_cast(&Obj)) { + auto Symb = IR->getSymbol(Sym.getRawDataRefImpl()); + if (Symb.isAlias()) continue; } } Index: tools/lto/lto.cpp =================================================================== --- tools/lto/lto.cpp +++ tools/lto/lto.cpp @@ -206,8 +206,7 @@ lto_module_t lto_module_create(const char* path) { lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - ErrorOr> M = - LTOModule::createFromFile(*LTOContext, path, Options); + ErrorOr> M = LTOModule::createFromFile(path); if (!M) return nullptr; return wrap(M->release()); @@ -217,7 +216,7 @@ lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); ErrorOr> M = - LTOModule::createFromOpenFile(*LTOContext, fd, path, size, Options); + LTOModule::createFromOpenFile(fd, path, size); if (!M) return nullptr; return wrap(M->release()); @@ -229,8 +228,8 @@ off_t offset) { lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - ErrorOr> M = LTOModule::createFromOpenFileSlice( - *LTOContext, fd, path, map_size, offset, Options); + ErrorOr> M = + LTOModule::createFromOpenFileSlice(fd, path, map_size, offset); if (!M) return nullptr; return wrap(M->release()); @@ -240,7 +239,7 @@ lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); ErrorOr> M = - LTOModule::createFromBuffer(*LTOContext, mem, length, Options); + LTOModule::createFromBuffer(mem, length); if (!M) return nullptr; return wrap(M->release()); @@ -252,7 +251,7 @@ lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); ErrorOr> M = - LTOModule::createFromBuffer(*LTOContext, mem, length, Options, path); + LTOModule::createFromBuffer(mem, length, path); if (!M) return nullptr; return wrap(M->release()); @@ -268,8 +267,7 @@ Context->setDiagnosticHandler(diagnosticHandler, nullptr, true); ErrorOr> M = - LTOModule::createInLocalContext(std::move(Context), mem, length, Options, - path); + LTOModule::createFromBuffer(mem, length, path); if (!M) return nullptr; return wrap(M->release()); @@ -281,20 +279,18 @@ lto_code_gen_t cg) { lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - ErrorOr> M = LTOModule::createFromBuffer( - unwrap(cg)->getContext(), mem, length, Options, path); + ErrorOr> M = + LTOModule::createFromBuffer(mem, length, path); return wrap(M->release()); } void lto_module_dispose(lto_module_t mod) { delete unwrap(mod); } const char* lto_module_get_target_triple(lto_module_t mod) { - return unwrap(mod)->getTargetTriple().c_str(); + return unwrap(mod)->getTargetTriple().data(); } -void lto_module_set_target_triple(lto_module_t mod, const char *triple) { - return unwrap(mod)->setTargetTriple(triple); -} +void lto_module_set_target_triple(lto_module_t mod, const char *) {} unsigned int lto_module_get_num_symbols(lto_module_t mod) { return unwrap(mod)->getSymbolCount();