mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
2aa2767ebe
This patch implements a limited form of autolinking primarily designed to allow either the --dependent-library compiler option, or "comment lib" pragmas ( https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=vs-2017) in C/C++ e.g. #pragma comment(lib, "foo"), to cause an ELF linker to automatically add the specified library to the link when processing the input file generated by the compiler. Currently this extension is unique to LLVM and LLD. However, care has been taken to design this feature so that it could be supported by other ELF linkers. The design goals were to provide: - A simple linking model for developers to reason about. - The ability to to override autolinking from the linker command line. - Source code compatibility, where possible, with "comment lib" pragmas in other environments (MSVC in particular). Dependent library support is implemented differently for ELF platforms than on the other platforms. Primarily this difference is that on ELF we pass the dependent library specifiers directly to the linker without manipulating them. This is in contrast to other platforms where they are mapped to a specific linker option by the compiler. This difference is a result of the greater variety of ELF linkers and the fact that ELF linkers tend to handle libraries in a more complicated fashion than on other platforms. This forces us to defer handling the specifiers to the linker. In order to achieve a level of source code compatibility with other platforms we have restricted this feature to work with libraries that meet the following "reasonable" requirements: 1. There are no competing defined symbols in a given set of libraries, or if they exist, the program owner doesn't care which is linked to their program. 2. There may be circular dependencies between libraries. The binary representation is a mergeable string section (SHF_MERGE, SHF_STRINGS), called .deplibs, with custom type SHT_LLVM_DEPENDENT_LIBRARIES (0x6fff4c04). The compiler forms this section by concatenating the arguments of the "comment lib" pragmas and --dependent-library options in the order they are encountered. Partial (-r, -Ur) links are handled by concatenating .deplibs sections with the normal mergeable string section rules. As an example, #pragma comment(lib, "foo") would result in: .section ".deplibs","MS",@llvm_dependent_libraries,1 .asciz "foo" For LTO, equivalent information to the contents of a the .deplibs section can be retrieved by the LLD for bitcode input files. LLD processes the dependent library specifiers in the following way: 1. Dependent libraries which are found from the specifiers in .deplibs sections of relocatable object files are added when the linker decides to include that file (which could itself be in a library) in the link. Dependent libraries behave as if they were appended to the command line after all other options. As a consequence the set of dependent libraries are searched last to resolve symbols. 2. It is an error if a file cannot be found for a given specifier. 3. Any command line options in effect at the end of the command line parsing apply to the dependent libraries, e.g. --whole-archive. 4. The linker tries to add a library or relocatable object file from each of the strings in a .deplibs section by; first, handling the string as if it was specified on the command line; second, by looking for the string in each of the library search paths in turn; third, by looking for a lib<string>.a or lib<string>.so (depending on the current mode of the linker) in each of the library search paths. 5. A new command line option --no-dependent-libraries tells LLD to ignore the dependent libraries. Rationale for the above points: 1. Adding the dependent libraries last makes the process simple to understand from a developers perspective. All linkers are able to implement this scheme. 2. Error-ing for libraries that are not found seems like better behavior than failing the link during symbol resolution. 3. It seems useful for the user to be able to apply command line options which will affect all of the dependent libraries. There is a potential problem of surprise for developers, who might not realize that these options would apply to these "invisible" input files; however, despite the potential for surprise, this is easy for developers to reason about and gives developers the control that they may require. 4. This algorithm takes into account all of the different ways that ELF linkers find input files. The different search methods are tried by the linker in most obvious to least obvious order. 5. I considered adding finer grained control over which dependent libraries were ignored (e.g. MSVC has /nodefaultlib:<library>); however, I concluded that this is not necessary: if finer control is required developers can fall back to using the command line directly. RFC thread: http://lists.llvm.org/pipermail/llvm-dev/2019-March/131004.html. Differential Revision: https://reviews.llvm.org/D60274 llvm-svn: 360984
655 lines
22 KiB
C++
655 lines
22 KiB
C++
//===-- LTOModule.cpp - LLVM Link Time Optimizer --------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the Link Time Optimization library. This library is
|
|
// intended to be used by linker to optimize code at link time.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/LTO/legacy/LTOModule.h"
|
|
#include "llvm/ADT/Triple.h"
|
|
#include "llvm/Bitcode/BitcodeReader.h"
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Mangler.h"
|
|
#include "llvm/IR/Metadata.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCParser/MCAsmParser.h"
|
|
#include "llvm/MC/MCSection.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/MC/SubtargetFeature.h"
|
|
#include "llvm/Object/IRObjectFile.h"
|
|
#include "llvm/Object/ObjectFile.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Host.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/Path.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
#include "llvm/Target/TargetLoweringObjectFile.h"
|
|
#include "llvm/Transforms/Utils/GlobalStatus.h"
|
|
#include <system_error>
|
|
using namespace llvm;
|
|
using namespace llvm::object;
|
|
|
|
LTOModule::LTOModule(std::unique_ptr<Module> M, MemoryBufferRef MBRef,
|
|
llvm::TargetMachine *TM)
|
|
: Mod(std::move(M)), MBRef(MBRef), _target(TM) {
|
|
SymTab.addModule(Mod.get());
|
|
}
|
|
|
|
LTOModule::~LTOModule() {}
|
|
|
|
/// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM
|
|
/// bitcode.
|
|
bool LTOModule::isBitcodeFile(const void *Mem, size_t Length) {
|
|
Expected<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInMemBuffer(
|
|
MemoryBufferRef(StringRef((const char *)Mem, Length), "<mem>"));
|
|
return !errorToBool(BCData.takeError());
|
|
}
|
|
|
|
bool LTOModule::isBitcodeFile(StringRef Path) {
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
|
|
MemoryBuffer::getFile(Path);
|
|
if (!BufferOrErr)
|
|
return false;
|
|
|
|
Expected<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInMemBuffer(
|
|
BufferOrErr.get()->getMemBufferRef());
|
|
return !errorToBool(BCData.takeError());
|
|
}
|
|
|
|
bool LTOModule::isThinLTO() {
|
|
Expected<BitcodeLTOInfo> Result = getBitcodeLTOInfo(MBRef);
|
|
if (!Result) {
|
|
logAllUnhandledErrors(Result.takeError(), errs());
|
|
return false;
|
|
}
|
|
return Result->IsThinLTO;
|
|
}
|
|
|
|
bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer,
|
|
StringRef TriplePrefix) {
|
|
Expected<MemoryBufferRef> BCOrErr =
|
|
IRObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef());
|
|
if (errorToBool(BCOrErr.takeError()))
|
|
return false;
|
|
LLVMContext Context;
|
|
ErrorOr<std::string> TripleOrErr =
|
|
expectedToErrorOrAndEmitErrors(Context, getBitcodeTargetTriple(*BCOrErr));
|
|
if (!TripleOrErr)
|
|
return false;
|
|
return StringRef(*TripleOrErr).startswith(TriplePrefix);
|
|
}
|
|
|
|
std::string LTOModule::getProducerString(MemoryBuffer *Buffer) {
|
|
Expected<MemoryBufferRef> BCOrErr =
|
|
IRObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef());
|
|
if (errorToBool(BCOrErr.takeError()))
|
|
return "";
|
|
LLVMContext Context;
|
|
ErrorOr<std::string> ProducerOrErr = expectedToErrorOrAndEmitErrors(
|
|
Context, getBitcodeProducerString(*BCOrErr));
|
|
if (!ProducerOrErr)
|
|
return "";
|
|
return *ProducerOrErr;
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<LTOModule>>
|
|
LTOModule::createFromFile(LLVMContext &Context, StringRef path,
|
|
const TargetOptions &options) {
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
|
|
MemoryBuffer::getFile(path);
|
|
if (std::error_code EC = BufferOrErr.getError()) {
|
|
Context.emitError(EC.message());
|
|
return EC;
|
|
}
|
|
std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrErr.get());
|
|
return makeLTOModule(Buffer->getMemBufferRef(), options, Context,
|
|
/* ShouldBeLazy*/ false);
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<LTOModule>>
|
|
LTOModule::createFromOpenFile(LLVMContext &Context, int fd, StringRef path,
|
|
size_t size, const TargetOptions &options) {
|
|
return createFromOpenFileSlice(Context, fd, path, size, 0, options);
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<LTOModule>>
|
|
LTOModule::createFromOpenFileSlice(LLVMContext &Context, int fd, StringRef path,
|
|
size_t map_size, off_t offset,
|
|
const TargetOptions &options) {
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
|
|
MemoryBuffer::getOpenFileSlice(fd, path, map_size, offset);
|
|
if (std::error_code EC = BufferOrErr.getError()) {
|
|
Context.emitError(EC.message());
|
|
return EC;
|
|
}
|
|
std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrErr.get());
|
|
return makeLTOModule(Buffer->getMemBufferRef(), options, Context,
|
|
/* ShouldBeLazy */ false);
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<LTOModule>>
|
|
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<std::unique_ptr<LTOModule>>
|
|
LTOModule::createInLocalContext(std::unique_ptr<LLVMContext> 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<std::unique_ptr<LTOModule>> Ret =
|
|
makeLTOModule(Buffer, options, *Context, /* ShouldBeLazy */ true);
|
|
if (Ret)
|
|
(*Ret)->OwnedContext = std::move(Context);
|
|
return Ret;
|
|
}
|
|
|
|
static ErrorOr<std::unique_ptr<Module>>
|
|
parseBitcodeFileImpl(MemoryBufferRef Buffer, LLVMContext &Context,
|
|
bool ShouldBeLazy) {
|
|
// Find the buffer.
|
|
Expected<MemoryBufferRef> MBOrErr =
|
|
IRObjectFile::findBitcodeInMemBuffer(Buffer);
|
|
if (Error E = MBOrErr.takeError()) {
|
|
std::error_code EC = errorToErrorCode(std::move(E));
|
|
Context.emitError(EC.message());
|
|
return EC;
|
|
}
|
|
|
|
if (!ShouldBeLazy) {
|
|
// Parse the full file.
|
|
return expectedToErrorOrAndEmitErrors(Context,
|
|
parseBitcodeFile(*MBOrErr, Context));
|
|
}
|
|
|
|
// Parse lazily.
|
|
return expectedToErrorOrAndEmitErrors(
|
|
Context,
|
|
getLazyBitcodeModule(*MBOrErr, Context, true /*ShouldLazyLoadMetadata*/));
|
|
}
|
|
|
|
ErrorOr<std::unique_ptr<LTOModule>>
|
|
LTOModule::makeLTOModule(MemoryBufferRef Buffer, const TargetOptions &options,
|
|
LLVMContext &Context, bool ShouldBeLazy) {
|
|
ErrorOr<std::unique_ptr<Module>> MOrErr =
|
|
parseBitcodeFileImpl(Buffer, Context, ShouldBeLazy);
|
|
if (std::error_code EC = MOrErr.getError())
|
|
return EC;
|
|
std::unique_ptr<Module> &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 make_error_code(object::object_error::arch_not_found);
|
|
|
|
// 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);
|
|
|
|
std::unique_ptr<LTOModule> Ret(new LTOModule(std::move(M), Buffer, target));
|
|
Ret->parseSymbols();
|
|
Ret->parseMetadata();
|
|
|
|
return std::move(Ret);
|
|
}
|
|
|
|
/// Create a MemoryBuffer from a memory range with an optional name.
|
|
std::unique_ptr<MemoryBuffer>
|
|
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<ConstantExpr>(c)) {
|
|
Constant *op = ce->getOperand(0);
|
|
if (GlobalVariable *gvn = dyn_cast<GlobalVariable>(op)) {
|
|
Constant *cn = gvn->getInitializer();
|
|
if (ConstantDataArray *ca = dyn_cast<ConstantDataArray>(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<ConstantStruct>(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();
|
|
info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED;
|
|
info.isFunction = false;
|
|
info.symbol = clgv;
|
|
}
|
|
}
|
|
|
|
// 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();
|
|
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<ConstantStruct>(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();
|
|
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();
|
|
info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED;
|
|
info.isFunction = false;
|
|
info.symbol = clgv;
|
|
}
|
|
|
|
void LTOModule::addDefinedDataSymbol(ModuleSymbolTable::Symbol Sym) {
|
|
SmallString<64> Buffer;
|
|
{
|
|
raw_svector_ostream OS(Buffer);
|
|
SymTab.printSymbolName(OS, Sym);
|
|
Buffer.c_str();
|
|
}
|
|
|
|
const GlobalValue *V = Sym.get<GlobalValue *>();
|
|
addDefinedDataSymbol(Buffer, V);
|
|
}
|
|
|
|
void LTOModule::addDefinedDataSymbol(StringRef 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
|
|
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(v)) {
|
|
StringRef Section = GV->getSection();
|
|
if (Section.startswith("__OBJC,__class,")) {
|
|
addObjCClass(GV);
|
|
}
|
|
|
|
// special case if this data blob is an ObjC category definition
|
|
else if (Section.startswith("__OBJC,__category,")) {
|
|
addObjCCategory(GV);
|
|
}
|
|
|
|
// special case if this data blob is the list of referenced classes
|
|
else if (Section.startswith("__OBJC,__cls_refs,")) {
|
|
addObjCClassRef(GV);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LTOModule::addDefinedFunctionSymbol(ModuleSymbolTable::Symbol Sym) {
|
|
SmallString<64> Buffer;
|
|
{
|
|
raw_svector_ostream OS(Buffer);
|
|
SymTab.printSymbolName(OS, Sym);
|
|
Buffer.c_str();
|
|
}
|
|
|
|
const Function *F = cast<Function>(Sym.get<GlobalValue *>());
|
|
addDefinedFunctionSymbol(Buffer, F);
|
|
}
|
|
|
|
void LTOModule::addDefinedFunctionSymbol(StringRef Name, const Function *F) {
|
|
// add to list of defined symbols
|
|
addDefinedSymbol(Name, F, true);
|
|
}
|
|
|
|
void LTOModule::addDefinedSymbol(StringRef 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;
|
|
|
|
// set permissions part
|
|
if (isFunction) {
|
|
attr |= LTO_SYMBOL_PERMISSIONS_CODE;
|
|
} else {
|
|
const GlobalVariable *gv = dyn_cast<GlobalVariable>(def);
|
|
if (gv && gv->isConstant())
|
|
attr |= LTO_SYMBOL_PERMISSIONS_RODATA;
|
|
else
|
|
attr |= 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;
|
|
else
|
|
attr |= 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 (def->canBeOmittedFromSymbolTable())
|
|
attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN;
|
|
else
|
|
attr |= LTO_SYMBOL_SCOPE_DEFAULT;
|
|
|
|
if (def->hasComdat())
|
|
attr |= LTO_SYMBOL_COMDAT;
|
|
|
|
if (isa<GlobalAlias>(def))
|
|
attr |= LTO_SYMBOL_ALIAS;
|
|
|
|
auto Iter = _defines.insert(Name).first;
|
|
|
|
// fill information structure
|
|
NameAndAttributes info;
|
|
StringRef NameRef = Iter->first();
|
|
info.name = NameRef;
|
|
assert(NameRef.data()[NameRef.size()] == '\0');
|
|
info.attributes = attr;
|
|
info.isFunction = isFunction;
|
|
info.symbol = def;
|
|
|
|
// add to table of symbols
|
|
_symbols.push_back(info);
|
|
}
|
|
|
|
/// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the
|
|
/// defined list.
|
|
void LTOModule::addAsmGlobalSymbol(StringRef 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()];
|
|
|
|
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();
|
|
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<Function>(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(StringRef name) {
|
|
auto IterBool = _undefines.insert(std::make_pair(name, NameAndAttributes()));
|
|
|
|
_asm_undefines.push_back(IterBool.first->first());
|
|
|
|
// 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();
|
|
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(ModuleSymbolTable::Symbol Sym,
|
|
bool isFunc) {
|
|
SmallString<64> name;
|
|
{
|
|
raw_svector_ostream OS(name);
|
|
SymTab.printSymbolName(OS, Sym);
|
|
name.c_str();
|
|
}
|
|
|
|
auto IterBool = _undefines.insert(std::make_pair(name, NameAndAttributes()));
|
|
|
|
// we already have the symbol
|
|
if (!IterBool.second)
|
|
return;
|
|
|
|
NameAndAttributes &info = IterBool.first->second;
|
|
|
|
info.name = IterBool.first->first();
|
|
|
|
const GlobalValue *decl = Sym.dyn_cast<GlobalValue *>();
|
|
|
|
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 : SymTab.symbols()) {
|
|
auto *GV = Sym.dyn_cast<GlobalValue *>();
|
|
uint32_t Flags = SymTab.getSymbolFlags(Sym);
|
|
if (Flags & object::BasicSymbolRef::SF_FormatSpecific)
|
|
continue;
|
|
|
|
bool IsUndefined = Flags & object::BasicSymbolRef::SF_Undefined;
|
|
|
|
if (!GV) {
|
|
SmallString<64> Buffer;
|
|
{
|
|
raw_svector_ostream OS(Buffer);
|
|
SymTab.printSymbolName(OS, Sym);
|
|
Buffer.c_str();
|
|
}
|
|
StringRef Name(Buffer);
|
|
|
|
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<Function>(GV);
|
|
if (IsUndefined) {
|
|
addPotentialUndefinedSymbol(Sym, F != nullptr);
|
|
continue;
|
|
}
|
|
|
|
if (F) {
|
|
addDefinedFunctionSymbol(Sym);
|
|
continue;
|
|
}
|
|
|
|
if (isa<GlobalVariable>(GV)) {
|
|
addDefinedDataSymbol(Sym);
|
|
continue;
|
|
}
|
|
|
|
assert(isa<GlobalAlias>(GV));
|
|
addDefinedDataSymbol(Sym);
|
|
}
|
|
|
|
// make symbols for all undefines
|
|
for (StringMap<NameAndAttributes>::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);
|
|
|
|
// Linker Options
|
|
if (NamedMDNode *LinkerOptions =
|
|
getModule().getNamedMetadata("llvm.linker.options")) {
|
|
for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) {
|
|
MDNode *MDOptions = LinkerOptions->getOperand(i);
|
|
for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) {
|
|
MDString *MDOption = cast<MDString>(MDOptions->getOperand(ii));
|
|
OS << " " << MDOption->getString();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Globals - we only need to do this for COFF.
|
|
const Triple TT(_target->getTargetTriple());
|
|
if (!TT.isOSBinFormatCOFF())
|
|
return;
|
|
Mangler M;
|
|
for (const NameAndAttributes &Sym : _symbols) {
|
|
if (!Sym.symbol)
|
|
continue;
|
|
emitLinkerFlagsForGlobalCOFF(OS, Sym.symbol, TT, M);
|
|
}
|
|
|
|
// Dependent Libraries
|
|
raw_string_ostream OSD(DependentLibraries);
|
|
if (NamedMDNode *DependentLibraries = getModule().getNamedMetadata("llvm.dependent-libraries"))
|
|
for (MDNode *N : DependentLibraries->operands())
|
|
OSD << " " << cast<MDString>(N->getOperand(0))->getString();
|
|
}
|