diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index bc2173eab6e65..4f3e1ddc76bf3 100644 --- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -167,12 +167,6 @@ class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { MCSection *getStaticDtorSection(unsigned Priority, const MCSymbol *KeySym) const override; - void emitLinkerFlagsForGlobal(raw_ostream &OS, - const GlobalValue *GV) const override; - - void emitLinkerFlagsForUsed(raw_ostream &OS, - const GlobalValue *GV) const override; - const MCExpr *lowerRelativeReference(const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const override; @@ -182,6 +176,9 @@ class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment) const override; + +private: + void emitLinkerDirectives(MCStreamer &Streamer, Module &M) const; }; class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h index 033b3c9fc4b66..0c8f6835c67a8 100644 --- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -208,12 +208,6 @@ class TargetLoweringObjectFile : public MCObjectFileInfo { return nullptr; } - virtual void emitLinkerFlagsForGlobal(raw_ostream &OS, - const GlobalValue *GV) const {} - - virtual void emitLinkerFlagsForUsed(raw_ostream &OS, - const GlobalValue *GV) const {} - /// If supported, return the section to use for the llvm.commandline /// metadata. Otherwise, return nullptr. virtual MCSection *getSectionForCommandLines() const { diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 7d8355c049693..bd304d7c7b879 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1720,51 +1720,6 @@ bool AsmPrinter::doFinalization(Module &M) { if (MCSection *S = MAI->getNonexecutableStackSection(OutContext)) OutStreamer->SwitchSection(S); - if (TM.getTargetTriple().isOSBinFormatCOFF()) { - // Emit /EXPORT: flags for each exported global as necessary. - const auto &TLOF = getObjFileLowering(); - std::string Flags; - - for (const GlobalValue &GV : M.global_values()) { - raw_string_ostream OS(Flags); - TLOF.emitLinkerFlagsForGlobal(OS, &GV); - OS.flush(); - if (!Flags.empty()) { - OutStreamer->SwitchSection(TLOF.getDrectveSection()); - OutStreamer->emitBytes(Flags); - } - Flags.clear(); - } - - // Emit /INCLUDE: flags for each used global as necessary. - if (const auto *LU = M.getNamedGlobal("llvm.used")) { - assert(LU->hasInitializer() && - "expected llvm.used to have an initializer"); - assert(isa(LU->getValueType()) && - "expected llvm.used to be an array type"); - if (const auto *A = cast(LU->getInitializer())) { - for (const Value *Op : A->operands()) { - const auto *GV = cast(Op->stripPointerCasts()); - // Global symbols with internal or private linkage are not visible to - // the linker, and thus would cause an error when the linker tried to - // preserve the symbol due to the `/include:` directive. - if (GV->hasLocalLinkage()) - continue; - - raw_string_ostream OS(Flags); - TLOF.emitLinkerFlagsForUsed(OS, GV); - OS.flush(); - - if (!Flags.empty()) { - OutStreamer->SwitchSection(TLOF.getDrectveSection()); - OutStreamer->emitBytes(Flags); - } - Flags.clear(); - } - } - } - } - if (TM.Options.EmitAddrsig) { // Emit address-significance attributes for all globals. OutStreamer->emitAddrsig(); diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 08dfbd1671419..0c43ec8423716 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1551,21 +1551,7 @@ MCSection *TargetLoweringObjectFileCOFF::getSectionForJumpTable( void TargetLoweringObjectFileCOFF::emitModuleMetadata(MCStreamer &Streamer, Module &M) const { - if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { - // Emit the linker options to the linker .drectve section. According to the - // spec, this section is a space-separated string containing flags for - // linker. - MCSection *Sec = getDrectveSection(); - Streamer.SwitchSection(Sec); - for (const auto *Option : LinkerOptions->operands()) { - for (const auto &Piece : cast(Option)->operands()) { - // Lead with a space for consistency with our dllexport implementation. - std::string Directive(" "); - Directive.append(std::string(cast(Piece)->getString())); - Streamer.emitBytes(Directive); - } - } - } + emitLinkerDirectives(Streamer, M); unsigned Version = 0; unsigned Flags = 0; @@ -1588,6 +1574,65 @@ void TargetLoweringObjectFileCOFF::emitModuleMetadata(MCStreamer &Streamer, emitCGProfile(Streamer, M); } +void TargetLoweringObjectFileCOFF::emitLinkerDirectives( + MCStreamer &Streamer, Module &M) const { + if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { + // Emit the linker options to the linker .drectve section. According to the + // spec, this section is a space-separated string containing flags for + // linker. + MCSection *Sec = getDrectveSection(); + Streamer.SwitchSection(Sec); + for (const auto *Option : LinkerOptions->operands()) { + for (const auto &Piece : cast(Option)->operands()) { + // Lead with a space for consistency with our dllexport implementation. + std::string Directive(" "); + Directive.append(std::string(cast(Piece)->getString())); + Streamer.emitBytes(Directive); + } + } + } + + // Emit /EXPORT: flags for each exported global as necessary. + std::string Flags; + for (const GlobalValue &GV : M.global_values()) { + raw_string_ostream OS(Flags); + emitLinkerFlagsForGlobalCOFF(OS, &GV, getTargetTriple(), getMangler()); + OS.flush(); + if (!Flags.empty()) { + Streamer.SwitchSection(getDrectveSection()); + Streamer.emitBytes(Flags); + } + Flags.clear(); + } + + // Emit /INCLUDE: flags for each used global as necessary. + if (const auto *LU = M.getNamedGlobal("llvm.used")) { + assert(LU->hasInitializer() && "expected llvm.used to have an initializer"); + assert(isa(LU->getValueType()) && + "expected llvm.used to be an array type"); + if (const auto *A = cast(LU->getInitializer())) { + for (const Value *Op : A->operands()) { + const auto *GV = cast(Op->stripPointerCasts()); + // Global symbols with internal or private linkage are not visible to + // the linker, and thus would cause an error when the linker tried to + // preserve the symbol due to the `/include:` directive. + if (GV->hasLocalLinkage()) + continue; + + raw_string_ostream OS(Flags); + emitLinkerFlagsForUsedCOFF(OS, GV, getTargetTriple(), getMangler()); + OS.flush(); + + if (!Flags.empty()) { + Streamer.SwitchSection(getDrectveSection()); + Streamer.emitBytes(Flags); + } + Flags.clear(); + } + } + } +} + void TargetLoweringObjectFileCOFF::Initialize(MCContext &Ctx, const TargetMachine &TM) { TargetLoweringObjectFile::Initialize(Ctx, TM); @@ -1665,16 +1710,6 @@ MCSection *TargetLoweringObjectFileCOFF::getStaticDtorSection( cast(StaticDtorSection)); } -void TargetLoweringObjectFileCOFF::emitLinkerFlagsForGlobal( - raw_ostream &OS, const GlobalValue *GV) const { - emitLinkerFlagsForGlobalCOFF(OS, GV, getTargetTriple(), getMangler()); -} - -void TargetLoweringObjectFileCOFF::emitLinkerFlagsForUsed( - raw_ostream &OS, const GlobalValue *GV) const { - emitLinkerFlagsForUsedCOFF(OS, GV, getTargetTriple(), getMangler()); -} - const MCExpr *TargetLoweringObjectFileCOFF::lowerRelativeReference( const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const { diff --git a/llvm/test/CodeGen/ARM/global-merge-dllexport.ll b/llvm/test/CodeGen/ARM/global-merge-dllexport.ll index d9bbaf9e0656f..98d75250a3038 100644 --- a/llvm/test/CodeGen/ARM/global-merge-dllexport.ll +++ b/llvm/test/CodeGen/ARM/global-merge-dllexport.ll @@ -13,9 +13,9 @@ define void @f1(i32 %a1, i32 %a2) { } ; CHECK: .lcomm .L_MergedGlobals,8,4 +; CHECK: .section .drectve,"yn" +; CHECK: .ascii " /EXPORT:y,DATA" ; CHECK: .globl x ; CHECK: .set x, .L_MergedGlobals ; CHECK: .globl y ; CHECK: .set y, .L_MergedGlobals+4 -; CHECK: .section .drectve,"yn" -; CHECK: .ascii " /EXPORT:y,DATA" diff --git a/llvm/test/CodeGen/X86/dllexport-x86_64.ll b/llvm/test/CodeGen/X86/dllexport-x86_64.ll index 9f427f60e6230..6205cffc4ba95 100644 --- a/llvm/test/CodeGen/X86/dllexport-x86_64.ll +++ b/llvm/test/CodeGen/X86/dllexport-x86_64.ll @@ -61,45 +61,13 @@ define weak_odr dllexport void @weak1() { @WeakVar3 = weak_odr dllexport global i32 0, align 4 -; CHECK: .globl alias -; CHECK: .set alias, notExported -@alias = dllexport alias void(), void()* @notExported - -; CHECK: .globl aliasNotExported -; CHECK: .set aliasNotExported, f1 -@aliasNotExported = alias void(), void()* @f1 - -; CHECK: .globl alias2 -; CHECK: .set alias2, f1 -@alias2 = dllexport alias void(), void()* @f1 - -; CHECK: .globl alias3 -; CHECK: .set alias3, notExported -@alias3 = dllexport alias void(), void()* @notExported - -; CHECK: .weak weak_alias -; CHECK: .set weak_alias, f1 -@weak_alias = weak_odr dllexport alias void(), void()* @f1 - -@blob = global [6 x i8] c"\B8*\00\00\00\C3", section ".text", align 16 -@blob_alias = dllexport alias i32 (), bitcast ([6 x i8]* @blob to i32 ()*) - -@exportedButNotDefinedVariable = external dllexport global i32 -declare dllexport void @exportedButNotDefinedFunction() -define void @foo() { -entry: - store i32 4, i32* @exportedButNotDefinedVariable, align 4 - call void @exportedButNotDefinedFunction() - ret void -} - ; Verify items that should not be exported do not appear in the export table. ; We use a separate check prefix to avoid confusion between -NOT and -SAME. ; NOTEXPORTED: .section .drectve -; NOTEXPORTED-NOT: notExported -; NOTEXPORTED-NOT: aliasNotExported -; NOTEXPORTED-NOT: exportedButNotDefinedVariable -; NOTEXPORTED-NOT: exportedButNotDefinedFunction +; NOTEXPORTED-NOT: :notExported +; NOTEXPORTED-NOT: :aliasNotExported +; NOTEXPORTED-NOT: :exportedButNotDefinedVariable +; NOTEXPORTED-NOT: :exportedButNotDefinedFunction ; CHECK: .section .drectve ; WIN32: .ascii " /EXPORT:f1" @@ -134,3 +102,35 @@ entry: ; MINGW: .ascii " -export:alias3" ; MINGW: .ascii " -export:weak_alias" ; MINGW: .ascii " -export:blob_alias" + +; CHECK: .globl alias +; CHECK: .set alias, notExported +@alias = dllexport alias void(), void()* @notExported + +; CHECK: .globl aliasNotExported +; CHECK: .set aliasNotExported, f1 +@aliasNotExported = alias void(), void()* @f1 + +; CHECK: .globl alias2 +; CHECK: .set alias2, f1 +@alias2 = dllexport alias void(), void()* @f1 + +; CHECK: .globl alias3 +; CHECK: .set alias3, notExported +@alias3 = dllexport alias void(), void()* @notExported + +; CHECK: .weak weak_alias +; CHECK: .set weak_alias, f1 +@weak_alias = weak_odr dllexport alias void(), void()* @f1 + +@blob = global [6 x i8] c"\B8*\00\00\00\C3", section ".text", align 16 +@blob_alias = dllexport alias i32 (), bitcast ([6 x i8]* @blob to i32 ()*) + +@exportedButNotDefinedVariable = external dllexport global i32 +declare dllexport void @exportedButNotDefinedFunction() +define void @foo() { +entry: + store i32 4, i32* @exportedButNotDefinedVariable, align 4 + call void @exportedButNotDefinedFunction() + ret void +} diff --git a/llvm/test/CodeGen/X86/dllexport.ll b/llvm/test/CodeGen/X86/dllexport.ll index f08395a8d3be7..a54fea136386d 100644 --- a/llvm/test/CodeGen/X86/dllexport.ll +++ b/llvm/test/CodeGen/X86/dllexport.ll @@ -82,27 +82,11 @@ define weak_odr dllexport void @weak1() { @WeakVar2 = weak_odr dllexport unnamed_addr constant i32 1 -; CHECK: .globl _alias -; CHECK: .set _alias, _notExported -@alias = dllexport alias void(), void()* @notExported - -; CHECK: .globl _alias2 -; CHECK: .set _alias2, _f1 -@alias2 = dllexport alias void(), void()* @f1 - -; CHECK: .globl _alias3 -; CHECK: .set _alias3, _notExported -@alias3 = dllexport alias void(), void()* @notExported - -; CHECK: .weak _weak_alias -; CHECK: .set _weak_alias, _f1 -@weak_alias = weak_odr dllexport alias void(), void()* @f1 - ; Verify items that should not be exported do not appear in the export table. ; We use a separate check prefix to avoid confusion between -NOT and -SAME. ; NOTEXPORTED: .section .drectve -; NOTEXPORTED-NOT: notExported -; NOTEXPORTED-NOT: notDefined +; NOTEXPORTED-NOT: :notExported +; NOTEXPORTED-NOT: :notDefined ; CHECK: .section .drectve ; CHECK-CL: .ascii " /EXPORT:_f1" @@ -139,3 +123,19 @@ define weak_odr dllexport void @weak1() { ; CHECK-GCC: .ascii " -export:alias2" ; CHECK-GCC: .ascii " -export:alias3" ; CHECK-GCC: .ascii " -export:weak_alias" + +; CHECK: .globl _alias +; CHECK: .set _alias, _notExported +@alias = dllexport alias void(), void()* @notExported + +; CHECK: .globl _alias2 +; CHECK: .set _alias2, _f1 +@alias2 = dllexport alias void(), void()* @f1 + +; CHECK: .globl _alias3 +; CHECK: .set _alias3, _notExported +@alias3 = dllexport alias void(), void()* @notExported + +; CHECK: .weak _weak_alias +; CHECK: .set _weak_alias, _f1 +@weak_alias = weak_odr dllexport alias void(), void()* @f1