[MinGW] [AArch64] Add stubs for potential automatic dllimported variables

The runtime pseudo relocations can't handle the AArch64 format PC
relative addressing in adrp+add/ldr pairs. By using stubs, the potentially
dllimported addresses can be touched up by the runtime pseudo relocation
framework.

Differential Revision: https://reviews.llvm.org/D51452

llvm-svn: 341401
This commit is contained in:
Martin Storsjo 2018-09-04 20:56:21 +00:00
parent 792a4f8a21
commit fed420d6b6
6 changed files with 132 additions and 8 deletions

View File

@ -3951,7 +3951,7 @@ SDValue AArch64TargetLowering::LowerGlobalAddress(SDValue Op,
}
EVT PtrVT = getPointerTy(DAG.getDataLayout());
SDLoc DL(GN);
if (GV->hasDLLImportStorageClass())
if (OpFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB))
Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
return Result;

View File

@ -1607,7 +1607,7 @@ bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
if ((OpFlags & AArch64II::MO_GOT) != 0) {
BuildMI(MBB, MI, DL, get(AArch64::LOADgot), Reg)
.addGlobalAddress(GV, 0, AArch64II::MO_GOT);
.addGlobalAddress(GV, 0, OpFlags);
BuildMI(MBB, MI, DL, get(AArch64::LDRXui), Reg)
.addReg(Reg, RegState::Kill)
.addImm(0)
@ -4842,6 +4842,7 @@ AArch64InstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
using namespace AArch64II;
static const std::pair<unsigned, const char *> TargetFlags[] = {
{MO_COFFSTUB, "aarch64-coffstub"},
{MO_GOT, "aarch64-got"}, {MO_NC, "aarch64-nc"},
{MO_TLS, "aarch64-tls"}, {MO_DLLIMPORT, "aarch64-dllimport"}};
return makeArrayRef(TargetFlags);

View File

@ -18,6 +18,7 @@
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
@ -44,16 +45,31 @@ AArch64MCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
assert(TheTriple.isOSWindows() &&
"Windows is the only supported COFF target");
bool IsIndirect = (TargetFlags & AArch64II::MO_DLLIMPORT);
bool IsIndirect = (TargetFlags & (AArch64II::MO_DLLIMPORT | AArch64II::MO_COFFSTUB));
if (!IsIndirect)
return Printer.getSymbol(GV);
SmallString<128> Name;
Name = "__imp_";
if (TargetFlags & AArch64II::MO_DLLIMPORT)
Name = "__imp_";
else if (TargetFlags & AArch64II::MO_COFFSTUB)
Name = ".refptr.";
Printer.TM.getNameWithPrefix(Name, GV,
Printer.getObjFileLowering().getMangler());
return Ctx.getOrCreateSymbol(Name);
MCSymbol *MCSym = Ctx.getOrCreateSymbol(Name);
if (TargetFlags & AArch64II::MO_COFFSTUB) {
MachineModuleInfoCOFF &MMICOFF =
Printer.MMI->getObjFileInfo<MachineModuleInfoCOFF>();
MachineModuleInfoImpl::StubValueTy &StubSym =
MMICOFF.getGVStubEntry(MCSym);
if (!StubSym.getPointer())
StubSym = MachineModuleInfoImpl::StubValueTy(Printer.getSymbol(GV), true);
}
return MCSym;
}
MCSymbol *

View File

@ -196,8 +196,13 @@ AArch64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
if (TM.getCodeModel() == CodeModel::Large && isTargetMachO())
return AArch64II::MO_GOT;
unsigned Flags = GV->hasDLLImportStorageClass() ? AArch64II::MO_DLLIMPORT
: AArch64II::MO_NO_FLAG;
unsigned Flags = AArch64II::MO_NO_FLAG;
if (GV->hasDLLImportStorageClass())
Flags = AArch64II::MO_DLLIMPORT;
else if (getTargetTriple().isWindowsGNUEnvironment() &&
!GV->isDSOLocal() && GV->isDeclarationForLinker() &&
isa<GlobalVariable>(GV))
Flags = AArch64II::MO_COFFSTUB | AArch64II::MO_GOT;
if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return AArch64II::MO_GOT | Flags;

View File

@ -507,7 +507,7 @@ namespace AArch64II {
MO_NO_FLAG,
MO_FRAGMENT = 0xf,
MO_FRAGMENT = 0x7,
/// MO_PAGE - A symbol operand with this flag represents the pc-relative
/// offset of the 4K page containing the symbol. This is used with the
@ -540,6 +540,11 @@ namespace AArch64II {
/// by-12-bits instruction.
MO_HI12 = 7,
/// MO_COFFSTUB - On a symbol operand "FOO", this indicates that the
/// reference is actually to the ".refptrp.FOO" symbol. This is used for
/// stub symbols on windows.
MO_COFFSTUB = 0x8,
/// MO_GOT - This flag indicates that a symbol operand represents the
/// address of the GOT entry for the symbol, rather than the address of
/// the symbol itself.

View File

@ -0,0 +1,97 @@
; RUN: llc < %s -mtriple=aarch64-w64-mingw32 | FileCheck %s
@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-LABEL: getVar:
; CHECK: adrp x8, .refptr.var
; CHECK: ldr x8, [x8, .refptr.var]
; CHECK: ldr w0, [x8]
; CHECK: ret
entry:
%0 = load i32, i32* @var, align 4
ret i32 %0
}
define dso_local i32 @getDsoLocalVar() {
; CHECK-LABEL: getDsoLocalVar:
; CHECK: adrp x8, dsolocalvar
; CHECK: ldr w0, [x8, dsolocalvar]
; CHECK: ret
entry:
%0 = load i32, i32* @dsolocalvar, align 4
ret i32 %0
}
define dso_local i32 @getLocalVar() {
; CHECK-LABEL: getLocalVar:
; CHECK: adrp x8, localvar
; CHECK: ldr w0, [x8, localvar]
; CHECK: ret
entry:
%0 = load i32, i32* @localvar, align 4
ret i32 %0
}
define dso_local i32 @getLocalCommon() {
; CHECK-LABEL: getLocalCommon:
; CHECK: adrp x8, localcommon
; CHECK: ldr w0, [x8, localcommon]
; CHECK: ret
entry:
%0 = load i32, i32* @localcommon, align 4
ret i32 %0
}
define dso_local i32 @getExtVar() {
; CHECK-LABEL: getExtVar:
; CHECK: adrp x8, __imp_extvar
; CHECK: ldr x8, [x8, __imp_extvar]
; CHECK: ldr w0, [x8]
; CHECK: ret
entry:
%0 = load i32, i32* @extvar, align 4
ret i32 %0
}
define dso_local void @callFunc() {
; CHECK-LABEL: callFunc:
; CHECK: b otherFunc
entry:
tail call void @otherFunc()
ret void
}
declare dso_local void @otherFunc()
define dso_local void @sspFunc() #0 {
; CHECK-LABEL: sspFunc:
; CHECK: adrp x8, .refptr.__stack_chk_guard
; CHECK: ldr x8, [x8, .refptr.__stack_chk_guard]
; CHECK: ldr x8, [x8]
entry:
%c = alloca i8, align 1
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %c)
call void @ptrUser(i8* nonnull %c)
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %c)
ret void
}
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
declare dso_local void @ptrUser(i8*) local_unnamed_addr #2
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
attributes #0 = { sspstrong }
; CHECK: .section .rdata$.refptr.__stack_chk_guard,"dr",discard,.refptr.__stack_chk_guard
; CHECK: .globl .refptr.__stack_chk_guard
; CHECK: .refptr.__stack_chk_guard:
; CHECK: .xword __stack_chk_guard
; CHECK: .section .rdata$.refptr.var,"dr",discard,.refptr.var
; CHECK: .globl .refptr.var
; CHECK: .refptr.var:
; CHECK: .xword var