Index: llvm/trunk/include/llvm/CodeGen/MachineModuleInfoImpls.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineModuleInfoImpls.h +++ llvm/trunk/include/llvm/CodeGen/MachineModuleInfoImpls.h @@ -80,6 +80,28 @@ SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); } }; +/// MachineModuleInfoCOFF - This is a MachineModuleInfoImpl implementation +/// for COFF targets. +class MachineModuleInfoCOFF : public MachineModuleInfoImpl { + /// GVStubs - These stubs are used to materialize global addresses in PIC + /// mode. + DenseMap GVStubs; + + virtual void anchor(); // Out of line virtual method. + +public: + MachineModuleInfoCOFF(const MachineModuleInfo &) {} + + StubValueTy &getGVStubEntry(MCSymbol *Sym) { + assert(Sym && "Key cannot be null"); + return GVStubs[Sym]; + } + + /// Accessor methods to return the set of stubs in sorted order. + + SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); } +}; + } // end namespace llvm #endif // LLVM_CODEGEN_MACHINEMODULEINFOIMPLS_H Index: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -32,6 +32,7 @@ #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/GCMetadata.h" @@ -1402,6 +1403,33 @@ } } + if (TM.getTargetTriple().isOSBinFormatCOFF()) { + MachineModuleInfoCOFF &MMICOFF = + MMI->getObjFileInfo(); + + // Output stubs for external and common global variables. + MachineModuleInfoCOFF::SymbolListTy Stubs = MMICOFF.GetGVStubList(); + if (!Stubs.empty()) { + const DataLayout &DL = M.getDataLayout(); + + for (const auto &Stub : Stubs) { + SmallString<256> SectionName = StringRef(".rdata$"); + SectionName += Stub.first->getName(); + OutStreamer->SwitchSection(OutContext.getCOFFSection( + SectionName, + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_LNK_COMDAT, + SectionKind::getReadOnly(), Stub.first->getName(), + COFF::IMAGE_COMDAT_SELECT_ANY)); + EmitAlignment(Log2_32(DL.getPointerSize())); + OutStreamer->EmitSymbolAttribute(Stub.first, MCSA_Global); + OutStreamer->EmitLabel(Stub.first); + OutStreamer->EmitSymbolValue(Stub.second.getPointer(), + DL.getPointerSize()); + } + } + } + // Finalize debug and EH information. for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, Index: llvm/trunk/lib/CodeGen/MachineModuleInfoImpls.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineModuleInfoImpls.cpp +++ llvm/trunk/lib/CodeGen/MachineModuleInfoImpls.cpp @@ -25,6 +25,7 @@ // Out of line virtual method. void MachineModuleInfoMachO::anchor() {} void MachineModuleInfoELF::anchor() {} +void MachineModuleInfoCOFF::anchor() {} using PairTy = std::pair; static int SortSymbolPair(const PairTy *LHS, const PairTy *RHS) { Index: llvm/trunk/lib/Target/X86/MCTargetDesc/X86BaseInfo.h =================================================================== --- llvm/trunk/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -231,6 +231,11 @@ /// to be an absolute symbol in range [0,128), so we can use the @ABS8 /// symbol modifier. MO_ABS8, + + /// MO_COFFSTUB - On a symbol operand "FOO", this indicates that the + /// reference is actually to the ".refptr.FOO" symbol. This is used for + /// stub symbols on windows. + MO_COFFSTUB, }; enum : uint64_t { Index: llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp +++ llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp @@ -129,6 +129,9 @@ if (MO.getTargetFlags() == X86II::MO_DLLIMPORT) GVSym = P.OutContext.getOrCreateSymbol(Twine("__imp_") + GVSym->getName()); + else if (MO.getTargetFlags() == X86II::MO_COFFSTUB) + GVSym = + P.OutContext.getOrCreateSymbol(Twine(".refptr.") + GVSym->getName()); if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) { @@ -161,6 +164,7 @@ break; case X86II::MO_DARWIN_NONLAZY: case X86II::MO_DLLIMPORT: + case X86II::MO_COFFSTUB: // These affect the name of the symbol, not any suffix. break; case X86II::MO_GOT_ABSOLUTE_ADDRESS: Index: llvm/trunk/lib/Target/X86/X86InstrInfo.h =================================================================== --- llvm/trunk/lib/Target/X86/X86InstrInfo.h +++ llvm/trunk/lib/Target/X86/X86InstrInfo.h @@ -117,6 +117,7 @@ case X86II::MO_GOT: // normal GOT reference. case X86II::MO_DARWIN_NONLAZY_PIC_BASE: // Normal $non_lazy_ptr ref. case X86II::MO_DARWIN_NONLAZY: // Normal $non_lazy_ptr ref. + case X86II::MO_COFFSTUB: // COFF .refptr stub. return true; default: return false; Index: llvm/trunk/lib/Target/X86/X86InstrInfo.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86InstrInfo.cpp +++ llvm/trunk/lib/Target/X86/X86InstrInfo.cpp @@ -7402,7 +7402,8 @@ {MO_DARWIN_NONLAZY_PIC_BASE, "x86-darwin-nonlazy-pic-base"}, {MO_TLVP, "x86-tlvp"}, {MO_TLVP_PIC_BASE, "x86-tlvp-pic-base"}, - {MO_SECREL, "x86-secrel"}}; + {MO_SECREL, "x86-secrel"}, + {MO_COFFSTUB, "x86-coffstub"}}; return makeArrayRef(TargetFlags); } Index: llvm/trunk/lib/Target/X86/X86MCInstLower.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86MCInstLower.cpp +++ llvm/trunk/lib/Target/X86/X86MCInstLower.cpp @@ -132,6 +132,9 @@ // Handle dllimport linkage. Name += "__imp_"; break; + case X86II::MO_COFFSTUB: + Name += ".refptr."; + break; case X86II::MO_DARWIN_NONLAZY: case X86II::MO_DARWIN_NONLAZY_PIC_BASE: Suffix = "$non_lazy_ptr"; @@ -160,6 +163,18 @@ switch (MO.getTargetFlags()) { default: break; + case X86II::MO_COFFSTUB: { + MachineModuleInfoCOFF &MMICOFF = + MF.getMMI().getObjFileInfo(); + MachineModuleInfoImpl::StubValueTy &StubSym = MMICOFF.getGVStubEntry(Sym); + if (!StubSym.getPointer()) { + assert(MO.isGlobal() && "Extern symbol not handled yet"); + StubSym = MachineModuleInfoImpl::StubValueTy( + AsmPrinter.getSymbol(MO.getGlobal()), + !MO.getGlobal()->hasInternalLinkage()); + } + break; + } case X86II::MO_DARWIN_NONLAZY: case X86II::MO_DARWIN_NONLAZY_PIC_BASE: { MachineModuleInfoImpl::StubValueTy &StubSym = @@ -191,6 +206,7 @@ // These affect the name of the symbol, not any suffix. case X86II::MO_DARWIN_NONLAZY: case X86II::MO_DLLIMPORT: + case X86II::MO_COFFSTUB: break; case X86II::MO_TLVP: Index: llvm/trunk/lib/Target/X86/X86Subtarget.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.cpp +++ llvm/trunk/lib/Target/X86/X86Subtarget.cpp @@ -138,6 +138,14 @@ } } + // For MinGW, if a data reference isn't marked as DSO local or DLLImport, + // and it's a pure declaration without a definition, it might potentially + // be automatically imported from another DLL, thus route accesses via a stub. + if (isTargetWindowsGNU() && GV && !GV->isDSOLocal() && + !GV->hasDLLImportStorageClass() && GV->isDeclarationForLinker() && + isa(GV)) + return X86II::MO_COFFSTUB; + if (TM.shouldAssumeDSOLocal(M, GV)) return classifyLocalReference(GV); Index: llvm/trunk/test/CodeGen/X86/br-fold.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/br-fold.ll +++ llvm/trunk/test/CodeGen/X86/br-fold.ll @@ -14,7 +14,8 @@ ; X64_WINDOWS: orq %rax, %rcx ; X64_WINDOWS-NEXT: ud2 -; X64_WINDOWS_GNU: orq %rax, %rcx +; X64_WINDOWS_GNU: movq .refptr._ZN11xercesc_2_513SchemaSymbols21fgURI_SCHEMAFORSCHEMAE(%rip), %rax +; X64_WINDOWS_GNU: orq .refptr._ZN11xercesc_2_56XMLUni16fgNotationStringE(%rip), %rax ; X64_WINDOWS_GNU-NEXT: ud2 ; PS4: orq %rax, %rcx Index: llvm/trunk/test/CodeGen/X86/mingw-refptr.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/mingw-refptr.ll +++ llvm/trunk/test/CodeGen/X86/mingw-refptr.ll @@ -0,0 +1,94 @@ +; RUN: llc < %s -mtriple=x86_64-w64-mingw32 | FileCheck %s -check-prefix=CHECK-X64 +; RUN: llc < %s -mtriple=i686-w64-mingw32 | FileCheck %s -check-prefix=CHECK-X86 + +@var = external local_unnamed_addr global i32, align 4 +@dsolocalvar = external dso_local local_unnamed_addr global i32, align 4 +@localvar = dso_local local_unnamed_addr global i32 0, align 4 +@localcommon = common dso_local local_unnamed_addr global i32 0, align 4 +@extvar = external dllimport local_unnamed_addr global i32, align 4 + +define dso_local i32 @getVar() { +; CHECK-X64-LABEL: getVar: +; CHECK-X64: movq .refptr.var(%rip), %rax +; CHECK-X64: movl (%rax), %eax +; CHECK-X64: retq +; CHECK-X86-LABEL: _getVar: +; CHECK-X86: movl .refptr._var, %eax +; CHECK-X86: movl (%eax), %eax +; CHECK-X86: retl +entry: + %0 = load i32, i32* @var, align 4 + ret i32 %0 +} + +define dso_local i32 @getDsoLocalVar() { +; CHECK-X64-LABEL: getDsoLocalVar: +; CHECK-X64: movl dsolocalvar(%rip), %eax +; CHECK-X64: retq +; CHECK-X86-LABEL: _getDsoLocalVar: +; CHECK-X86: movl _dsolocalvar, %eax +; CHECK-X86: retl +entry: + %0 = load i32, i32* @dsolocalvar, align 4 + ret i32 %0 +} + +define dso_local i32 @getLocalVar() { +; CHECK-X64-LABEL: getLocalVar: +; CHECK-X64: movl localvar(%rip), %eax +; CHECK-X64: retq +; CHECK-X86-LABEL: _getLocalVar: +; CHECK-X86: movl _localvar, %eax +; CHECK-X86: retl +entry: + %0 = load i32, i32* @localvar, align 4 + ret i32 %0 +} + +define dso_local i32 @getLocalCommon() { +; CHECK-X64-LABEL: getLocalCommon: +; CHECK-X64: movl localcommon(%rip), %eax +; CHECK-X64: retq +; CHECK-X86-LABEL: _getLocalCommon: +; CHECK-X86: movl _localcommon, %eax +; CHECK-X86: retl +entry: + %0 = load i32, i32* @localcommon, align 4 + ret i32 %0 +} + +define dso_local i32 @getExtVar() { +; CHECK-X64-LABEL: getExtVar: +; CHECK-X64: movq __imp_extvar(%rip), %rax +; CHECK-X64: movl (%rax), %eax +; CHECK-X64: retq +; CHECK-X86-LABEL: _getExtVar: +; CHECK-X86: movl __imp__extvar, %eax +; CHECK-X86: movl (%eax), %eax +; CHECK-X86: retl +entry: + %0 = load i32, i32* @extvar, align 4 + ret i32 %0 +} + +define dso_local void @callFunc() { +; CHECK-X64-LABEL: callFunc: +; CHECK-X64: jmp otherFunc +; CHECK-X86-LABEL: _callFunc: +; CHECK-X86: jmp _otherFunc +entry: + tail call void @otherFunc() + ret void +} + +declare dso_local void @otherFunc() + +; CHECK-X64: .section .rdata$.refptr.var,"dr",discard,.refptr.var +; CHECK-X64: .globl .refptr.var +; CHECK-X64: .refptr.var: +; CHECK-X64: .quad var + +; CHECK-X86: .section .rdata$.refptr._var,"dr",discard,.refptr._var +; CHECK-X86: .globl .refptr._var +; CHECK-X86: .refptr._var: +; CHECK-X86: .long _var Index: llvm/trunk/test/CodeGen/X86/stack-protector.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/stack-protector.ll +++ llvm/trunk/test/CodeGen/X86/stack-protector.ll @@ -94,7 +94,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test1b: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -135,7 +135,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test1c: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -176,7 +176,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test1d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -255,7 +255,7 @@ ; DARWIN-X64: callq ___stack_chk_fail ; MINGW-X64-LABEL: test2b: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -298,7 +298,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test2c: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -341,7 +341,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test2d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -465,7 +465,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test3c: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -506,7 +506,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test3d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -632,7 +632,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test4c: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -675,7 +675,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test4d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -828,7 +828,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test5d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a.addr = alloca i8*, align 8 @@ -946,7 +946,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test6c: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %retval = alloca i32, align 4 @@ -987,7 +987,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test6d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %retval = alloca i32, align 4 @@ -1099,7 +1099,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test7c: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: .seh_endproc %a = alloca i32, align 4 @@ -1135,7 +1135,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test7d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %a = alloca i32, align 4 @@ -1240,7 +1240,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test8c: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %b = alloca i32, align 4 @@ -1275,7 +1275,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test8d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %b = alloca i32, align 4 @@ -2850,7 +2850,7 @@ ; MSVC-I386: calll @__security_check_cookie@4 ; MINGW-X64-LABEL: test19d: -; MINGW-X64: mov{{l|q}} __stack_chk_guard +; MINGW-X64: mov{{l|q}} .refptr.__stack_chk_guard ; MINGW-X64: callq __stack_chk_fail %c = alloca %struct.pair, align 4 Index: llvm/trunk/test/CodeGen/X86/win32-ssp.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/win32-ssp.ll +++ llvm/trunk/test/CodeGen/X86/win32-ssp.ll @@ -9,9 +9,10 @@ define dso_local void @func() sspstrong { entry: ; MINGW-LABEL: func: -; MINGW: mov{{l|q}} __stack_chk_guard +; MINGW: mov{{l|q}} .refptr.__stack_chk_guard(%rip), [[REG:%[a-z]+]] +; MINGW: mov{{l|q}} ([[REG]]) ; MINGW: callq other -; MINGW: mov{{l|q}} __stack_chk_guard +; MINGW: mov{{l|q}} ([[REG]]) ; MINGW: callq __stack_chk_fail ; MINGW: .seh_endproc