x86_64: Fix calls to __morestack under the large code model.

Under the large code model, we cannot assume that __morestack lives within
2^31 bytes of the call site, so we cannot use pc-relative addressing. We
cannot perform the call via a temporary register, as the rax register may
be used to store the static chain, and all other suitable registers may be
either callee-save or used for parameter passing. We cannot use the stack
at this point either because __morestack manipulates the stack directly.

To avoid these issues, perform an indirect call via a read-only memory
location containing the address.

This solution is not perfect, as it assumes that the .rodata section
is laid out within 2^31 bytes of each function body, but this seems to
be sufficient for JIT.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225003 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Peter Collingbourne 2014-12-30 20:05:19 +00:00
parent dd890d5c5e
commit d8ae3e1fee
5 changed files with 78 additions and 7 deletions

View File

@ -161,6 +161,13 @@ class MachineModuleInfo : public ImmutablePass {
/// to _fltused on Windows targets.
bool UsesVAFloatArgument;
/// UsesMorestackAddr - True if the module calls the __morestack function
/// indirectly, as is required under the large code model on x86. This is used
/// to emit a definition of a symbol, __morestack_addr, containing the
/// address. See comments in lib/Target/X86/X86FrameLowering.cpp for more
/// details.
bool UsesMorestackAddr;
public:
static char ID; // Pass identification, replacement for typeid
@ -234,6 +241,14 @@ public:
UsesVAFloatArgument = b;
}
bool usesMorestackAddr() const {
return UsesMorestackAddr;
}
void setUsesMorestackAddr(bool b) {
UsesMorestackAddr = b;
}
/// \brief Returns a reference to a list of cfi instructions in the current
/// function's prologue. Used to construct frame maps for debug and exception
/// handling comsumers.

View File

@ -1011,6 +1011,23 @@ bool AsmPrinter::doFinalization(Module &M) {
// Emit llvm.ident metadata in an '.ident' directive.
EmitModuleIdents(M);
// Emit __morestack address if needed for indirect calls.
if (MMI->usesMorestackAddr()) {
const MCSection *ReadOnlySection =
getObjFileLowering().getSectionForConstant(SectionKind::getReadOnly(),
/*C=*/nullptr);
OutStreamer.SwitchSection(ReadOnlySection);
MCSymbol *AddrSymbol =
OutContext.GetOrCreateSymbol(StringRef("__morestack_addr"));
OutStreamer.EmitLabel(AddrSymbol);
const DataLayout &DL = *TM.getSubtargetImpl()->getDataLayout();
unsigned PtrSize = DL.getPointerSize(0);
OutStreamer.EmitSymbolValue(GetExternalSymbolSymbol("__morestack"),
PtrSize);
}
// If we don't have any trampolines, then we don't require stack memory
// to be executable. Some targets have a directive to declare this.
Function *InitTrampolineIntrinsic = M.getFunction("llvm.init.trampoline");

View File

@ -273,7 +273,7 @@ bool MachineModuleInfo::doInitialization(Module &M) {
CurCallSite = 0;
CallsEHReturn = 0;
CallsUnwindInit = 0;
DbgInfoAvailable = UsesVAFloatArgument = false;
DbgInfoAvailable = UsesVAFloatArgument = UsesMorestackAddr = false;
// Always emit some info, by default "no personality" info.
Personalities.push_back(nullptr);
AddrLabelSymbols = nullptr;

View File

@ -1648,12 +1648,36 @@ X86FrameLowering::adjustForSegmentedStacks(MachineFunction &MF) const {
}
// __morestack is in libgcc
if (Is64Bit)
BuildMI(allocMBB, DL, TII.get(X86::CALL64pcrel32))
.addExternalSymbol("__morestack");
else
BuildMI(allocMBB, DL, TII.get(X86::CALLpcrel32))
.addExternalSymbol("__morestack");
if (Is64Bit && MF.getTarget().getCodeModel() == CodeModel::Large) {
// Under the large code model, we cannot assume that __morestack lives
// within 2^31 bytes of the call site, so we cannot use pc-relative
// addressing. We cannot perform the call via a temporary register,
// as the rax register may be used to store the static chain, and all
// other suitable registers may be either callee-save or used for
// parameter passing. We cannot use the stack at this point either
// because __morestack manipulates the stack directly.
//
// To avoid these issues, perform an indirect call via a read-only memory
// location containing the address.
//
// This solution is not perfect, as it assumes that the .rodata section
// is laid out within 2^31 bytes of each function body, but this seems
// to be sufficient for JIT.
BuildMI(allocMBB, DL, TII.get(X86::CALL64m))
.addReg(X86::RIP)
.addImm(0)
.addReg(0)
.addExternalSymbol("__morestack_addr")
.addReg(0);
MF.getMMI().setUsesMorestackAddr(true);
} else {
if (Is64Bit)
BuildMI(allocMBB, DL, TII.get(X86::CALL64pcrel32))
.addExternalSymbol("__morestack");
else
BuildMI(allocMBB, DL, TII.get(X86::CALLpcrel32))
.addExternalSymbol("__morestack");
}
if (IsNested)
BuildMI(allocMBB, DL, TII.get(X86::MORESTACK_RET_RESTORE_R10));

View File

@ -1,5 +1,6 @@
; RUN: llc < %s -mcpu=generic -mtriple=i686-linux -verify-machineinstrs | FileCheck %s -check-prefix=X32-Linux
; RUN: llc < %s -mcpu=generic -mtriple=x86_64-linux -verify-machineinstrs | FileCheck %s -check-prefix=X64-Linux
; RUN: llc < %s -mcpu=generic -mtriple=x86_64-linux -code-model=large -verify-machineinstrs | FileCheck %s -check-prefix=X64-Linux-Large
; RUN: llc < %s -mcpu=generic -mtriple=x86_64-linux-gnux32 -verify-machineinstrs | FileCheck %s -check-prefix=X32ABI
; RUN: llc < %s -mcpu=generic -mtriple=i686-darwin -verify-machineinstrs | FileCheck %s -check-prefix=X32-Darwin
; RUN: llc < %s -mcpu=generic -mtriple=x86_64-darwin -verify-machineinstrs | FileCheck %s -check-prefix=X64-Darwin
@ -57,6 +58,16 @@ define void @test_basic() #0 {
; X64-Linux-NEXT: callq __morestack
; X64-Linux-NEXT: ret
; X64-Linux-Large-LABEL: test_basic:
; X64-Linux-Large: cmpq %fs:112, %rsp
; X64-Linux-Large-NEXT: ja .LBB0_2
; X64-Linux-Large: movabsq $40, %r10
; X64-Linux-Large-NEXT: movabsq $0, %r11
; X64-Linux-Large-NEXT: callq *__morestack_addr(%rip)
; X64-Linux-Large-NEXT: ret
; X32ABI-LABEL: test_basic:
; X32ABI: cmpl %fs:64, %esp
@ -626,3 +637,7 @@ define void @test_nostack() #0 {
}
attributes #0 = { "split-stack" }
; X64-Linux-Large: .rodata
; X64-Linux-Large-NEXT: __morestack_addr:
; X64-Linux-Large-NEXT: .quad __morestack