Teach LTOModule to emit linker flags for dllexported symbols, plus interface cleanup.

This change unifies how LTOModule and the backend obtain linker flags
for globals: via a new TargetLoweringObjectFile member function named
emitLinkerFlagsForGlobal. A new function LTOModule::getLinkerOpts() returns
the list of linker flags as a single concatenated string.

This change affects the C libLTO API: the function lto_module_get_*deplibs now
exposes an empty list, and lto_module_get_*linkeropts exposes a single element
which combines the contents of all observed flags. libLTO should never have
tried to parse the linker flags; it is the linker's job to do so. Because
linkers will need to be able to parse flags in regular object files, it
makes little sense for libLTO to have a redundant mechanism for doing so.

The new API is compatible with the old one. It is valid for a user to specify
multiple linker flags in a single pragma directive like this:

 #pragma comment(linker, "/defaultlib:foo /defaultlib:bar")

The previous implementation would not have exposed
either flag via lto_module_get_*deplibs (as the test in
TargetLoweringObjectFileCOFF::getDepLibFromLinkerOpt was case sensitive)
and would have exposed "/defaultlib:foo /defaultlib:bar" as a single flag via
lto_module_get_*linkeropts. This may have been a bug in the implementation,
but it does give us a chance to fix the interface.

Differential Revision: http://reviews.llvm.org/D10548

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241010 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Peter Collingbourne 2015-06-29 22:04:09 +00:00
parent b370959788
commit a6367d9136
11 changed files with 155 additions and 197 deletions

View File

@ -282,6 +282,8 @@ lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index);
/**
* Returns the number of dependent libraries in the object module.
*
* Deprecated. Now returns an empty list.
*
* \since LTO_API_VERSION=8
*/
extern unsigned int
@ -291,6 +293,8 @@ lto_module_get_num_deplibs(lto_module_t mod);
/**
* Returns the ith dependent library in the module.
*
* Deprecated. Now always returns null.
*
* \since LTO_API_VERSION=8
*/
extern const char*
@ -300,6 +304,9 @@ lto_module_get_deplib(lto_module_t mod, unsigned int index);
/**
* Returns the number of linker options in the object module.
*
* Each linker option may consist of multiple flags. It is the linker's
* responsibility to split the flags using a platform-specific mechanism.
*
* \since LTO_API_VERSION=8
*/
extern unsigned int
@ -309,6 +316,9 @@ lto_module_get_num_linkeropts(lto_module_t mod);
/**
* Returns the ith linker option in the module.
*
* Each linker option may consist of multiple flags. It is the linker's
* responsibility to split the flags using a platform-specific mechanism.
*
* \since LTO_API_VERSION=8
*/
extern const char*

View File

@ -90,10 +90,6 @@ public:
~TargetLoweringObjectFileMachO() override {}
TargetLoweringObjectFileMachO();
/// Extract the dependent library name from a linker option string. Returns
/// StringRef() if the option does not specify a library.
StringRef getDepLibFromLinkerOpt(StringRef LinkerOption) const override;
/// Emit the module flags that specify the garbage collection information.
void emitModuleFlags(MCStreamer &Streamer,
ArrayRef<Module::ModuleFlagEntry> ModuleFlags,
@ -150,10 +146,6 @@ public:
MCSection *getSectionForJumpTable(const Function &F, Mangler &Mang,
const TargetMachine &TM) const override;
/// Extract the dependent library name from a linker option string. Returns
/// StringRef() if the option does not specify a library.
StringRef getDepLibFromLinkerOpt(StringRef LinkerOption) const override;
/// Emit Obj-C garbage collection and linker options. Only linker option
/// emission is implemented for COFF.
void emitModuleFlags(MCStreamer &Streamer,
@ -164,6 +156,9 @@ public:
const MCSymbol *KeySym) const override;
MCSection *getStaticDtorSection(unsigned Priority,
const MCSymbol *KeySym) const override;
void emitLinkerFlagsForGlobal(raw_ostream &OS, const GlobalValue *GV,
const Mangler &Mang) const override;
};
} // end namespace llvm

View File

@ -47,12 +47,11 @@ private:
std::unique_ptr<LLVMContext> OwnedContext;
std::string LinkerOpts;
std::unique_ptr<object::IRObjectFile> IRFile;
std::unique_ptr<TargetMachine> _target;
StringSet<> _linkeropt_strings;
std::vector<const char *> _deplibs;
std::vector<const char *> _linkeropts;
std::vector<NameAndAttributes> _symbols;
std::vector<NameAndAttributes> _symbols;
// _defines and _undefines only needed to disambiguate tentative definitions
StringSet<> _defines;
@ -149,28 +148,8 @@ public:
return nullptr;
}
/// Get the number of dependent libraries
uint32_t getDependentLibraryCount() {
return _deplibs.size();
}
/// Get the dependent library at the specified index.
const char *getDependentLibrary(uint32_t index) {
if (index < _deplibs.size())
return _deplibs[index];
return nullptr;
}
/// Get the number of linker options
uint32_t getLinkerOptCount() {
return _linkeropts.size();
}
/// Get the linker option at the specified index.
const char *getLinkerOpt(uint32_t index) {
if (index < _linkeropts.size())
return _linkeropts[index];
return nullptr;
const char *getLinkerOpts() {
return LinkerOpts.c_str();
}
const std::vector<const char*> &getAsmUndefinedRefs() {

View File

@ -64,12 +64,6 @@ public:
const TargetMachine &TM,
const MCSymbol *Sym) const;
/// Extract the dependent library name from a linker option string. Returns
/// StringRef() if the option does not specify a library.
virtual StringRef getDepLibFromLinkerOpt(StringRef LinkerOption) const {
return StringRef();
}
/// Emit the module flags that the platform cares about.
virtual void emitModuleFlags(MCStreamer &Streamer,
ArrayRef<Module::ModuleFlagEntry> Flags,
@ -188,6 +182,9 @@ public:
return nullptr;
}
virtual void emitLinkerFlagsForGlobal(raw_ostream &OS, const GlobalValue *GV,
const Mangler &Mang) const {}
protected:
virtual MCSection *SelectSectionForGlobal(const GlobalValue *GV,
SectionKind Kind, Mangler &Mang,

View File

@ -440,16 +440,6 @@ TargetLoweringObjectFileMachO::TargetLoweringObjectFileMachO()
SupportIndirectSymViaGOTPCRel = true;
}
/// getDepLibFromLinkerOpt - Extract the dependent library name from a linker
/// option string. Returns StringRef() if the option does not specify a library.
StringRef TargetLoweringObjectFileMachO::
getDepLibFromLinkerOpt(StringRef LinkerOption) const {
const char *LibCmd = "-l";
if (LinkerOption.startswith(LibCmd))
return LinkerOption.substr(strlen(LibCmd));
return StringRef();
}
/// emitModuleFlags - Perform code emission for module flags.
void TargetLoweringObjectFileMachO::
emitModuleFlags(MCStreamer &Streamer,
@ -990,14 +980,6 @@ MCSection *TargetLoweringObjectFileCOFF::getSectionForJumpTable(
COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE);
}
StringRef TargetLoweringObjectFileCOFF::
getDepLibFromLinkerOpt(StringRef LinkerOption) const {
const char *LibCmd = "/DEFAULTLIB:";
if (LinkerOption.startswith(LibCmd))
return LinkerOption.substr(strlen(LibCmd));
return StringRef();
}
void TargetLoweringObjectFileCOFF::
emitModuleFlags(MCStreamer &Streamer,
ArrayRef<Module::ModuleFlagEntry> ModuleFlags,
@ -1045,3 +1027,36 @@ MCSection *TargetLoweringObjectFileCOFF::getStaticDtorSection(
return getContext().getAssociativeCOFFSection(
cast<MCSectionCOFF>(StaticDtorSection), KeySym);
}
void TargetLoweringObjectFileCOFF::emitLinkerFlagsForGlobal(
raw_ostream &OS, const GlobalValue *GV, const Mangler &Mang) const {
if (!GV->hasDLLExportStorageClass() || GV->isDeclaration())
return;
const Triple &TT = getTargetTriple();
if (TT.isKnownWindowsMSVCEnvironment())
OS << " /EXPORT:";
else
OS << " -export:";
if (TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) {
std::string Flag;
raw_string_ostream FlagOS(Flag);
Mang.getNameWithPrefix(FlagOS, GV, false);
FlagOS.flush();
if (Flag[0] == DL->getGlobalPrefix())
OS << Flag.substr(1);
else
OS << Flag;
} else {
Mang.getNameWithPrefix(OS, GV, false);
}
if (!GV->getValueType()->isFunctionTy()) {
if (TT.isKnownWindowsMSVCEnvironment())
OS << ",DATA";
else
OS << ",data";
}
}

View File

@ -19,6 +19,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DiagnosticPrinter.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"
@ -642,6 +643,8 @@ bool LTOModule::parseSymbols(std::string &errMsg) {
/// parseMetadata - Parse metadata from the module
void LTOModule::parseMetadata() {
raw_string_ostream OS(LinkerOpts);
// Linker Options
if (Metadata *Val = getModule().getModuleFlag("Linker Options")) {
MDNode *LinkerOptions = cast<MDNode>(Val);
@ -649,20 +652,19 @@ void LTOModule::parseMetadata() {
MDNode *MDOptions = cast<MDNode>(LinkerOptions->getOperand(i));
for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) {
MDString *MDOption = cast<MDString>(MDOptions->getOperand(ii));
// FIXME: Make StringSet::insert match Self-Associative Container
// requirements, returning <iter,bool> rather than bool, and use that
// here.
StringRef Op =
_linkeropt_strings.insert(MDOption->getString()).first->first();
StringRef DepLibName =
_target->getObjFileLowering()->getDepLibFromLinkerOpt(Op);
if (!DepLibName.empty())
_deplibs.push_back(DepLibName.data());
else if (!Op.empty())
_linkeropts.push_back(Op.data());
OS << " " << MDOption->getString();
}
}
}
// Globals
Mangler Mang;
for (const NameAndAttributes &Sym : _symbols) {
if (!Sym.symbol)
continue;
_target->getObjFileLowering()->emitLinkerFlagsForGlobal(OS, Sym.symbol,
Mang);
}
// Add other interesting metadata here.
}

View File

@ -581,34 +581,6 @@ MCSymbol *X86AsmPrinter::GetCPISymbol(unsigned CPID) const {
return AsmPrinter::GetCPISymbol(CPID);
}
void X86AsmPrinter::GenerateExportDirective(const MCSymbol *Sym, bool IsData) {
SmallString<128> Directive;
raw_svector_ostream OS(Directive);
StringRef Name = Sym->getName();
const Triple &TT = TM.getTargetTriple();
if (TT.isKnownWindowsMSVCEnvironment())
OS << " /EXPORT:";
else
OS << " -export:";
if ((TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) &&
(Name[0] == getDataLayout().getGlobalPrefix()))
Name = Name.drop_front();
OS << Name;
if (IsData) {
if (TT.isKnownWindowsMSVCEnvironment())
OS << ",DATA";
else
OS << ",data";
}
OS.flush();
OutStreamer->EmitBytes(Directive);
}
void X86AsmPrinter::EmitEndOfAsmFile(Module &M) {
const Triple &TT = TM.getTargetTriple();
@ -692,38 +664,25 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) {
}
if (TT.isOSBinFormatCOFF()) {
// Necessary for dllexport support
std::vector<const MCSymbol*> DLLExportedFns, DLLExportedGlobals;
for (const auto &Function : M)
if (Function.hasDLLExportStorageClass() && !Function.isDeclaration())
DLLExportedFns.push_back(getSymbol(&Function));
for (const auto &Global : M.globals())
if (Global.hasDLLExportStorageClass() && !Global.isDeclaration())
DLLExportedGlobals.push_back(getSymbol(&Global));
for (const auto &Alias : M.aliases()) {
if (!Alias.hasDLLExportStorageClass())
continue;
if (Alias.getType()->getElementType()->isFunctionTy())
DLLExportedFns.push_back(getSymbol(&Alias));
else
DLLExportedGlobals.push_back(getSymbol(&Alias));
}
// Output linker support code for dllexported globals on windows.
if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) {
const TargetLoweringObjectFileCOFF &TLOFCOFF =
const TargetLoweringObjectFileCOFF &TLOFCOFF =
static_cast<const TargetLoweringObjectFileCOFF&>(getObjFileLowering());
OutStreamer->SwitchSection(TLOFCOFF.getDrectveSection());
std::string Flags;
raw_string_ostream FlagsOS(Flags);
for (auto & Symbol : DLLExportedGlobals)
GenerateExportDirective(Symbol, /*IsData=*/true);
for (auto & Symbol : DLLExportedFns)
GenerateExportDirective(Symbol, /*IsData=*/false);
for (const auto &Function : M)
TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Function, *Mang);
for (const auto &Global : M.globals())
TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Global, *Mang);
for (const auto &Alias : M.aliases())
TLOFCOFF.emitLinkerFlagsForGlobal(FlagsOS, &Alias, *Mang);
FlagsOS.flush();
// Output collected flags.
if (!Flags.empty()) {
OutStreamer->SwitchSection(TLOFCOFF.getDrectveSection());
OutStreamer->EmitBytes(Flags);
}
SM.serializeToStackMapSection();

View File

@ -30,8 +30,6 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
StackMaps SM;
FaultMaps FM;
void GenerateExportDirective(const MCSymbol *Sym, bool IsData);
// This utility class tracks the length of a stackmap instruction's 'shadow'.
// It is used by the X86AsmPrinter to ensure that the stackmap shadow
// invariants (i.e. no other stackmaps, patchpoints, or control flow within

View File

@ -71,33 +71,33 @@ define weak_odr dllexport void @weak1() {
@blob_alias = dllexport alias bitcast ([6 x i8]* @blob to i32 ()*)
; CHECK: .section .drectve
; WIN32: " /EXPORT:Var1,DATA"
; WIN32: " /EXPORT:Var2,DATA"
; WIN32: " /EXPORT:Var3,DATA"
; WIN32: " /EXPORT:WeakVar1,DATA"
; WIN32: " /EXPORT:WeakVar2,DATA"
; WIN32: " /EXPORT:f1"
; WIN32: " /EXPORT:f2"
; WIN32: " /EXPORT:lnk1"
; WIN32: " /EXPORT:lnk2"
; WIN32: " /EXPORT:weak1"
; WIN32: " /EXPORT:alias"
; WIN32: " /EXPORT:alias2"
; WIN32: " /EXPORT:alias3"
; WIN32: " /EXPORT:weak_alias"
; WIN32: " /EXPORT:blob_alias"
; MINGW: " -export:Var1,data"
; MINGW: " -export:Var2,data"
; MINGW: " -export:Var3,data"
; MINGW: " -export:WeakVar1,data"
; MINGW: " -export:WeakVar2,data"
; MINGW: " -export:f1"
; MINGW: " -export:f2"
; MINGW: " -export:lnk1"
; MINGW: " -export:lnk2"
; MINGW: " -export:weak1"
; MINGW: " -export:alias"
; MINGW: " -export:alias2"
; MINGW: " -export:alias3"
; MINGW: " -export:weak_alias"
; MINGW: " -export:blob_alias"
; WIN32: /EXPORT:f1
; WIN32-SAME: /EXPORT:f2
; WIN32-SAME: /EXPORT:lnk1
; WIN32-SAME: /EXPORT:lnk2
; WIN32-SAME: /EXPORT:weak1
; WIN32-SAME: /EXPORT:Var1,DATA
; WIN32-SAME: /EXPORT:Var2,DATA
; WIN32-SAME: /EXPORT:Var3,DATA
; WIN32-SAME: /EXPORT:WeakVar1,DATA
; WIN32-SAME: /EXPORT:WeakVar2,DATA
; WIN32-SAME: /EXPORT:alias
; WIN32-SAME: /EXPORT:alias2
; WIN32-SAME: /EXPORT:alias3
; WIN32-SAME: /EXPORT:weak_alias
; WIN32-SAME: /EXPORT:blob_alias
; MINGW: -export:f1
; MINGW-SAME: -export:f2
; MINGW-SAME: -export:lnk1
; MINGW-SAME: -export:lnk2
; MINGW-SAME: -export:weak1
; MINGW-SAME: -export:Var1,data
; MINGW-SAME: -export:Var2,data
; MINGW-SAME: -export:Var3,data
; MINGW-SAME: -export:WeakVar1,data
; MINGW-SAME: -export:WeakVar2,data
; MINGW-SAME: -export:alias
; MINGW-SAME: -export:alias2
; MINGW-SAME: -export:alias3
; MINGW-SAME: -export:weak_alias
; MINGW-SAME: -export:blob_alias"

View File

@ -89,40 +89,41 @@ define weak_odr dllexport void @weak1() {
@weak_alias = weak_odr dllexport alias void()* @f1
; CHECK: .section .drectve
; CHECK-CL: " /EXPORT:_Var1,DATA"
; CHECK-CL: " /EXPORT:_Var2,DATA"
; CHECK-CL: " /EXPORT:_Var3,DATA"
; CHECK-CL: " /EXPORT:_WeakVar1,DATA"
; CHECK-CL: " /EXPORT:_WeakVar2,DATA"
; CHECK-CL: " /EXPORT:_f1"
; CHECK-CL: " /EXPORT:_f2"
; CHECK-CL-NOT: not_exported
; CHECK-CL: " /EXPORT:_stdfun@0"
; CHECK-CL: " /EXPORT:@fastfun@0"
; CHECK-CL: " /EXPORT:_thisfun"
; CHECK-CL: " /EXPORT:_lnk1"
; CHECK-CL: " /EXPORT:_lnk2"
; CHECK-CL: " /EXPORT:_weak1"
; CHECK-CL: " /EXPORT:_alias"
; CHECK-CL: " /EXPORT:_alias2"
; CHECK-CL: " /EXPORT:_alias3"
; CHECK-CL: " /EXPORT:_weak_alias"
; CHECK-GCC: " -export:Var1,data"
; CHECK-GCC: " -export:Var2,data"
; CHECK-GCC: " -export:Var3,data"
; CHECK-GCC: " -export:WeakVar1,data"
; CHECK-GCC: " -export:WeakVar2,data"
; CHECK-GCC: " -export:f1"
; CHECK-GCC: " -export:f2"
; CHECK-CL: /EXPORT:_f1
; CHECK-CL-SAME: /EXPORT:_f2
; CHECK-CL-SAME: /EXPORT:_stdfun@0
; CHECK-CL-SAME: /EXPORT:@fastfun@0
; CHECK-CL-SAME: /EXPORT:_thisfun
; CHECK-CL-SAME: /EXPORT:_lnk1
; CHECK-CL-SAME: /EXPORT:_lnk2
; CHECK-CL-SAME: /EXPORT:_weak1
; CHECK-CL-SAME: /EXPORT:_Var1,DATA
; CHECK-CL-SAME: /EXPORT:_Var2,DATA
; CHECK-CL-SAME: /EXPORT:_Var3,DATA
; CHECK-CL-SAME: /EXPORT:_WeakVar1,DATA
; CHECK-CL-SAME: /EXPORT:_WeakVar2,DATA
; CHECK-CL-SAME: /EXPORT:_alias
; CHECK-CL-SAME: /EXPORT:_alias2
; CHECK-CL-SAME: /EXPORT:_alias3
; CHECK-CL-SAME: /EXPORT:_weak_alias"
; CHECK-CL-NOT: not_exported
; CHECK-GCC: " -export:stdfun@0"
; CHECK-GCC: " -export:@fastfun@0"
; CHECK-GCC: " -export:thisfun"
; CHECK-GCC: " -export:lnk1"
; CHECK-GCC: " -export:lnk2"
; CHECK-GCC: " -export:weak1"
; CHECK-GCC: " -export:alias"
; CHECK-GCC: " -export:alias2"
; CHECK-GCC: " -export:alias3"
; CHECK-GCC: " -export:weak_alias"
; CHECK-GCC-NOT: not_exported
; CHECK-GCC: -export:f1
; CHECK-GCC-SAME: -export:f2
; CHECK-GCC-SAME: -export:stdfun@0
; CHECK-GCC-SAME: -export:@fastfun@0
; CHECK-GCC-SAME: -export:thisfun
; CHECK-GCC-SAME: -export:lnk1
; CHECK-GCC-SAME: -export:lnk2
; CHECK-GCC-SAME: -export:weak1
; CHECK-GCC-SAME: -export:Var1,data
; CHECK-GCC-SAME: -export:Var2,data
; CHECK-GCC-SAME: -export:Var3,data
; CHECK-GCC-SAME: -export:WeakVar1,data
; CHECK-GCC-SAME: -export:WeakVar2,data
; CHECK-GCC-SAME: -export:alias
; CHECK-GCC-SAME: -export:alias2
; CHECK-GCC-SAME: -export:alias3
; CHECK-GCC-SAME: -export:weak_alias"
; CHECK-GCC-NOT: not_exported

View File

@ -224,19 +224,21 @@ lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod,
}
unsigned int lto_module_get_num_deplibs(lto_module_t mod) {
return unwrap(mod)->getDependentLibraryCount();
return 0;
}
const char* lto_module_get_deplib(lto_module_t mod, unsigned int index) {
return unwrap(mod)->getDependentLibrary(index);
return nullptr;
}
unsigned int lto_module_get_num_linkeropts(lto_module_t mod) {
return unwrap(mod)->getLinkerOptCount();
return 1;
}
const char* lto_module_get_linkeropt(lto_module_t mod, unsigned int index) {
return unwrap(mod)->getLinkerOpt(index);
if (index != 0)
return nullptr;
return unwrap(mod)->getLinkerOpts();
}
void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg,