Index: llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -158,7 +158,7 @@ const MCSymbol *KeySym) const override; void emitLinkerFlagsForGlobal(raw_ostream &OS, - const GlobalValue *GV) const override; + const GlobalValue *GV) const; }; class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { @@ -184,9 +184,6 @@ const TargetMachine &TM) const override; }; -void emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, - const Triple &TT, Mangler &Mangler); - } // end namespace llvm #endif // LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H Index: llvm/include/llvm/IR/Mangler.h =================================================================== --- llvm/include/llvm/IR/Mangler.h +++ llvm/include/llvm/IR/Mangler.h @@ -44,6 +44,10 @@ const DataLayout &DL); static void getNameWithPrefix(SmallVectorImpl &OutName, const Twine &GVName, const DataLayout &DL); + + /// Print an appropriate linker flag for exporting this symbol on COFF + /// targets. + void getCOFFDLLExportLinkerFlag(raw_ostream &OS, const GlobalValue *GV); }; } // End llvm namespace Index: llvm/include/llvm/Target/TargetLoweringObjectFile.h =================================================================== --- llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -180,9 +180,6 @@ return nullptr; } - virtual void emitLinkerFlagsForGlobal(raw_ostream &OS, - const GlobalValue *GV) const {} - protected: virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -967,37 +967,6 @@ return 0; } -void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, - const Triple &TT, Mangler &Mangler) { - if (!GV->hasDLLExportStorageClass() || GV->isDeclaration()) - return; - - if (TT.isKnownWindowsMSVCEnvironment()) - OS << " /EXPORT:"; - else - OS << " -export:"; - - if (TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) { - std::string Flag; - raw_string_ostream FlagOS(Flag); - Mangler.getNameWithPrefix(FlagOS, GV, false); - FlagOS.flush(); - if (Flag[0] == GV->getParent()->getDataLayout().getGlobalPrefix()) - OS << Flag.substr(1); - else - OS << Flag; - } else { - Mangler.getNameWithPrefix(OS, GV, false); - } - - if (!GV->getValueType()->isFunctionTy()) { - if (TT.isKnownWindowsMSVCEnvironment()) - OS << ",DATA"; - else - OS << ",data"; - } -} - MCSection *TargetLoweringObjectFileCOFF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { int Selection = 0; @@ -1194,7 +1163,8 @@ void TargetLoweringObjectFileCOFF::emitLinkerFlagsForGlobal( raw_ostream &OS, const GlobalValue *GV) const { - emitLinkerFlagsForGlobalCOFF(OS, GV, getTargetTriple(), getMangler()); + Mangler Mang; + Mang.getCOFFDLLExportLinkerFlag(OS, GV); } //===----------------------------------------------------------------------===// Index: llvm/lib/IR/Mangler.cpp =================================================================== --- llvm/lib/IR/Mangler.cpp +++ llvm/lib/IR/Mangler.cpp @@ -13,6 +13,7 @@ #include "llvm/IR/Mangler.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" @@ -172,3 +173,35 @@ raw_svector_ostream OS(OutName); getNameWithPrefix(OS, GV, CannotUsePrivateLabel); } + +void Mangler::getCOFFDLLExportLinkerFlag(raw_ostream &OS, + const GlobalValue *GV) { + if (!GV->hasDLLExportStorageClass() || GV->isDeclaration()) + return; + + Triple TT(GV->getParent()->getTargetTriple()); + if (TT.isKnownWindowsMSVCEnvironment()) + OS << " /EXPORT:"; + else + OS << " -export:"; + + if (TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) { + std::string Flag; + raw_string_ostream FlagOS(Flag); + getNameWithPrefix(FlagOS, GV, false); + FlagOS.flush(); + if (Flag[0] == GV->getParent()->getDataLayout().getGlobalPrefix()) + OS << Flag.substr(1); + else + OS << Flag; + } else { + getNameWithPrefix(OS, GV, false); + } + + if (!GV->getValueType()->isFunctionTy()) { + if (TT.isKnownWindowsMSVCEnvironment()) + OS << ",DATA"; + else + OS << ",data"; + } +} Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -395,7 +395,7 @@ Mangler M; for (const ModuleSymbolTable::Symbol &Sym : SymTab.symbols()) if (auto *GV = Sym.dyn_cast()) - emitLinkerFlagsForGlobalCOFF(LOS, GV, TT, M); + M.getCOFFDLLExportLinkerFlag(LOS, GV); LOS.flush(); return LinkerOpts; } Index: llvm/lib/LTO/LTOModule.cpp =================================================================== --- llvm/lib/LTO/LTOModule.cpp +++ llvm/lib/LTO/LTOModule.cpp @@ -656,7 +656,7 @@ for (const NameAndAttributes &Sym : _symbols) { if (!Sym.symbol) continue; - emitLinkerFlagsForGlobalCOFF(OS, Sym.symbol, TT, M); + M.getCOFFDLLExportLinkerFlag(OS, Sym.symbol); } // Add other interesting metadata here. Index: llvm/lib/Linker/IRMover.cpp =================================================================== --- llvm/lib/Linker/IRMover.cpp +++ llvm/lib/Linker/IRMover.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Mangler.h" #include "llvm/IR/TypeFinder.h" #include "llvm/Support/Error.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -486,6 +487,7 @@ /// module. void prepareCompileUnitsForImport(); void linkNamedMDNodes(); + void linkCOFFDLLExportFlags(); public: IRLinker(Module &DstM, MDMapT &SharedMDs, @@ -1087,6 +1089,30 @@ } } +/// COFF-specific: link dropped dllexport flags into DstM using metadata. +void IRLinker::linkCOFFDLLExportFlags() { + auto *MD = DstM.getOrInsertNamedMetadata("llvm.linker.options"); + Mangler Mang; + auto LinkFlag = [&](GlobalValue *GV) { + if (!GV->hasDLLExportStorageClass() || GV->isDeclaration() || + ValuesToLink.count(GV)) + return; + + std::string Flag; + raw_string_ostream OS(Flag); + Mang.getCOFFDLLExportLinkerFlag(OS, GV); + MD->addOperand(MDNode::get(GV->getContext(), + {MDString::get(GV->getContext(), OS.str())})); + }; + + for (auto &F : *SrcM) + LinkFlag(&F); + for (auto &GV : SrcM->globals()) + LinkFlag(&GV); + for (auto &GA : SrcM->aliases()) + LinkFlag(&GA); +} + /// Merge the linker flags in Src into the Dest module. Error IRLinker::linkModuleFlagsMetadata() { // If the source module has no module flags, we are done. @@ -1332,6 +1358,10 @@ // are properly remapped. linkNamedMDNodes(); + // COFF-specific: link dropped dllexport flags into DstM. + if (SrcTriple.isOSBinFormatCOFF()) + linkCOFFDLLExportFlags(); + // Merge the module flags into the DstM module. return linkModuleFlagsMetadata(); } Index: llvm/test/LTO/Resolution/X86/dllexport.ll =================================================================== --- /dev/null +++ llvm/test/LTO/Resolution/X86/dllexport.ll @@ -0,0 +1,23 @@ +; RUN: llvm-as %s -o %t.o +; RUN: llvm-lto2 -o %t2.o %t.o -r %t.o,f,x -r %t.o,g,x -r %t.o,a,x -save-temps +; RUN: llvm-dis < %t2.o.0.0.preopt.bc -o - | FileCheck %s + +; CHECK-NOT: alias +; CHECK-NOT: global +; CHECK-NOT: void + +; CHECK: !llvm.linker.options = !{!0, !1, !2} +; CHECK: !0 = !{!" /EXPORT:f"} +; CHECK: !1 = !{!" /EXPORT:g,DATA"} +; CHECK: !2 = !{!" /EXPORT:a,DATA"} + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +@a = dllexport alias i8, i8* @g + +@g = dllexport global i8 0 + +define dllexport void @f() { + ret void +}