diff options
| author | 2019-01-30 03:08:12 +0000 | |
|---|---|---|
| committer | 2019-01-30 03:08:12 +0000 | |
| commit | 728e23dfc36a7a5f9a19f349b6c8d489de3d3859 (patch) | |
| tree | cd910b6c2a97a90f6de6b76e84d2d74246997cc1 /gnu/llvm/lib/Target/X86/X86FrameLowering.cpp | |
| parent | use MPLS_SHIM2LABEL and MPLS_LABEL2SHIM (diff) | |
| download | wireguard-openbsd-728e23dfc36a7a5f9a19f349b6c8d489de3d3859.tar.xz wireguard-openbsd-728e23dfc36a7a5f9a19f349b6c8d489de3d3859.zip | |
implement -msave-args in clang/llvm, like the sun did for gcc
this is a bit different to gcc as gcc likes to use movs to move
stuff on and off the stack, and directly updates the stack pointers
with add and sub instructions. llvm prefers to use push and pop
instructions, is a lot more careful about keeping track of how
much stuff is currently on the stack, and generally pops the frame
pointer rather than do maths on it.
-msave-args adds a bunch of pushes as the first thing a function
prologue does. to keep the stack aligned, if there's an odd number
of arguments to the function it pushes the first one again to put
the frame back on a 16 byte boundary.
to undo the pushes the frame pointer needs to be updated in function
epilogues. clang emits a series of pops to fix up the registers on
the way out, but popping saved arguments is a waste of time and
harmful to actual data in the function. rather than add an offset
to the stack pointer, -msave-args emits a leaveq operation to fix
up the frame again. leaveq is effectively mov rbp,rsp; pop rbp, and
is a single byte, meaning there's less potential for gadgets compared
to a direct add to rsp, or an explicit mov rbp,rsp.
the only thing missing compared to the gcc implementation is adding
the SUN_amd64_parmdump dwarf flag to affected functions. if someone
can tell me how to add that from the frame lowering code, let me
know.
when enabled in kernel builds again, this will provide useful
arguments in ddb stack traces again.
Diffstat (limited to 'gnu/llvm/lib/Target/X86/X86FrameLowering.cpp')
| -rw-r--r-- | gnu/llvm/lib/Target/X86/X86FrameLowering.cpp | 97 |
1 files changed, 82 insertions, 15 deletions
diff --git a/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp b/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp index ea076e576ef..1a8d3b03836 100644 --- a/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/gnu/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -48,6 +48,7 @@ X86FrameLowering::X86FrameLowering(const X86Subtarget &STI, // standard x86_64 and NaCl use 64-bit frame/stack pointers, x32 - 32-bit. Uses64BitFramePtr = STI.isTarget64BitLP64() || STI.isTargetNaCl64(); StackPtr = TRI->getStackRegister(); + SaveArgs = Is64Bit ? STI.getSaveArgs() : 0; } bool X86FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { @@ -91,7 +92,8 @@ bool X86FrameLowering::hasFP(const MachineFunction &MF) const { MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() || MF.callsUnwindInit() || MF.hasEHFunclets() || MF.callsEHReturn() || MFI.hasStackMap() || MFI.hasPatchPoint() || - MFI.hasCopyImplyingStackAdjustment()); + MFI.hasCopyImplyingStackAdjustment() || + SaveArgs); } static unsigned getSUBriOpcode(unsigned IsLP64, int64_t Imm) { @@ -872,6 +874,24 @@ void X86FrameLowering::BuildStackAlignAND(MachineBasicBlock &MBB, MI->getOperand(3).setIsDead(); } +// FIXME: Get this from tablegen. +static ArrayRef<MCPhysReg> get64BitArgumentGPRs(CallingConv::ID CallConv, + const X86Subtarget &Subtarget) { + assert(Subtarget.is64Bit()); + + if (Subtarget.isCallingConvWin64(CallConv)) { + static const MCPhysReg GPR64ArgRegsWin64[] = { + X86::RCX, X86::RDX, X86::R8, X86::R9 + }; + return makeArrayRef(std::begin(GPR64ArgRegsWin64), std::end(GPR64ArgRegsWin64)); + } + + static const MCPhysReg GPR64ArgRegs64Bit[] = { + X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9 + }; + return makeArrayRef(std::begin(GPR64ArgRegs64Bit), std::end(GPR64ArgRegs64Bit)); +} + /// emitPrologue - Push callee-saved registers onto the stack, which /// automatically adjust the stack pointer. Adjust the stack pointer to allocate /// space for local variables. Also emit labels used by the exception handler to @@ -1154,6 +1174,43 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, nullptr, DwarfFramePtr)); } + if (SaveArgs && !Fn.arg_empty()) { + ArrayRef<MCPhysReg> GPRs = + get64BitArgumentGPRs(Fn.getCallingConv(), STI); + unsigned arg_size = Fn.arg_size(); + unsigned RI = 0; + int64_t SaveSize = 0; + + if (Fn.hasStructRetAttr()) { + GPRs = GPRs.drop_front(1); + arg_size--; + } + + for (MCPhysReg Reg : GPRs) { + if (++RI > arg_size) + break; + + SaveSize += SlotSize; + + BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r)) + .addReg(Reg) + .setMIFlag(MachineInstr::FrameSetup); + } + + // Realign the stack. PUSHes are the most space efficient. + while (SaveSize % getStackAlignment()) { + BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r)) + .addReg(GPRs.front()) + .setMIFlag(MachineInstr::FrameSetup); + + SaveSize += SlotSize; + } + + //dlg StackSize -= SaveSize; + //dlg MFI.setStackSize(StackSize); + X86FI->setSaveArgSize(SaveSize); + } + if (NeedsWinFPO) { // .cv_fpo_setframe $FramePtr HasWinCFI = true; @@ -1619,20 +1676,6 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, } uint64_t SEHStackAllocAmt = NumBytes; - if (HasFP) { - // Pop EBP. - BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), - MachineFramePtr) - .setMIFlag(MachineInstr::FrameDestroy); - if (NeedsDwarfCFI) { - unsigned DwarfStackPtr = - TRI->getDwarfRegNum(Is64Bit ? X86::RSP : X86::ESP, true); - BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfa( - nullptr, DwarfStackPtr, -SlotSize)); - --MBBI; - } - } - MachineBasicBlock::iterator FirstCSPop = MBBI; // Skip the callee-saved pop instructions. while (MBBI != MBB.begin()) { @@ -1702,6 +1745,28 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, --MBBI; } + if (HasFP) { + MBBI = Terminator; + + if (X86FI->getSaveArgSize()) { + // LEAVE is effectively mov rbp,rsp; pop rbp + BuildMI(MBB, MBBI, DL, TII.get(X86::LEAVE64), MachineFramePtr) + .setMIFlag(MachineInstr::FrameDestroy); + } else { + // Pop EBP. + BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), + MachineFramePtr) + .setMIFlag(MachineInstr::FrameDestroy); + } + if (NeedsDwarfCFI) { + unsigned DwarfStackPtr = + TRI->getDwarfRegNum(Is64Bit ? X86::RSP : X86::ESP, true); + BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfa( + nullptr, DwarfStackPtr, -SlotSize)); + --MBBI; + } + } + // Windows unwinder will not invoke function's exception handler if IP is // either in prologue or in epilogue. This behavior causes a problem when a // call immediately precedes an epilogue, because the return address points @@ -1790,6 +1855,8 @@ int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, "FPDelta isn't aligned per the Win64 ABI!"); } + if (FI >= 0) + Offset -= X86FI->getSaveArgSize(); if (TRI->hasBasePointer(MF)) { assert(HasFP && "VLAs and dynamic stack realign, but no FP?!"); |
