[WinEH] Ensure that funclets obey the x64 ABI

The x64 ABI requires that epilogues do not contain code other than stack
adjustments and some limited control flow.  However, we'd insert code to
initialize the return address after stack adjustments.  Instead, insert
EAX/RAX with the current value before we create the stack adjustments in
the epilogue.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248839 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Majnemer 2015-09-29 22:33:36 +00:00
parent c96f87a892
commit 28c61f88cc
5 changed files with 50 additions and 50 deletions

View File

@ -141,41 +141,6 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
// The EH_RETURN pseudo is really removed during the MC Lowering.
return true;
}
case X86::CLEANUPRET: {
// Replace CATCHRET with the appropriate RET.
unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
BuildMI(MBB, MBBI, DL, TII->get(RetOp));
MBBI->eraseFromParent();
return true;
}
case X86::CATCHRET: {
MachineBasicBlock *TargetMBB = MBBI->getOperand(0).getMBB();
// Fill EAX/RAX with the address of the target block.
unsigned ReturnReg = STI->is64Bit() ? X86::RAX : X86::EAX;
unsigned RetOp = STI->is64Bit() ? X86::RETQ : X86::RETL;
if (STI->is64Bit()) {
// LEA64r TargetMBB(%rip), %rax
BuildMI(MBB, MBBI, DL, TII->get(X86::LEA64r), ReturnReg)
.addReg(X86::RIP)
.addImm(0)
.addReg(0)
.addMBB(TargetMBB)
.addReg(0);
} else {
// MOV32ri $TargetMBB, %eax
BuildMI(MBB, MBBI, DL, TII->get(X86::MOV32ri))
.addReg(ReturnReg)
.addMBB(TargetMBB);
}
// Replace CATCHRET with the appropriate RET.
BuildMI(MBB, MBBI, DL, TII->get(RetOp)).addReg(ReturnReg);
MBBI->eraseFromParent();
return true;
}
}
llvm_unreachable("Previous switch has a fallthrough?");
}

View File

@ -1093,9 +1093,26 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
if (STI.is32Bit()) {
RestoreMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
MF.insert(TargetMBB, RestoreMBB);
MBB.transferSuccessors(RestoreMBB);
MBB.removeSuccessor(TargetMBB);
MBB.addSuccessor(RestoreMBB);
MBBI->getOperand(0).setMBB(RestoreMBB);
RestoreMBB->addSuccessor(TargetMBB);
}
// Fill EAX/RAX with the address of the target block.
unsigned ReturnReg = STI.is64Bit() ? X86::RAX : X86::EAX;
if (STI.is64Bit()) {
// LEA64r RestoreMBB(%rip), %rax
BuildMI(MBB, MBBI, DL, TII.get(X86::LEA64r), ReturnReg)
.addReg(X86::RIP)
.addImm(0)
.addReg(0)
.addMBB(RestoreMBB)
.addReg(0);
} else {
// MOV32ri $RestoreMBB, %eax
BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri))
.addReg(ReturnReg)
.addMBB(RestoreMBB);
}
// Pop EBP.
@ -1111,12 +1128,24 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4))
.addMBB(TargetMBB);
}
} else if (isFuncletReturnInstr(MBBI)) {
// Replace CATCHRET with the appropriate RET.
unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
MachineBasicBlock::iterator NewExit =
BuildMI(MBB, MBBI, DL, TII.get(RetOp)).addReg(ReturnReg);
MBBI->eraseFromParent();
MBBI = NewExit;
} else if (MBBI->getOpcode() == X86::CLEANUPRET) {
NumBytes = MFI->getMaxCallFrameSize();
assert(hasFP(MF) && "EH funclets without FP not yet implemented");
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
MachineFramePtr)
.setMIFlag(MachineInstr::FrameDestroy);
// Replace CLEANUPRET with the appropriate RET.
unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
MachineBasicBlock::iterator NewExit =
BuildMI(MBB, MBBI, DL, TII.get(RetOp));
MBBI->eraseFromParent();
MBBI = NewExit;
} else if (hasFP(MF)) {
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;

View File

@ -80,9 +80,9 @@ catchendblock: ; preds = %catch,
; X86: movl $1, -{{[0-9]+}}(%ebp)
; X86: movl $2, (%esp)
; X86: calll _f
; X86: addl $16, %esp
; X86: movl $[[restorebb]], %eax
; X86-NEXT: addl $16, %esp
; X86-NEXT: popl %ebp
; X86-NEXT: movl $[[restorebb]], %eax
; X86-NEXT: retl
; X86: L__ehtable$try_catch_catch:
@ -125,9 +125,9 @@ catchendblock: ; preds = %catch,
; X64: subq $32, %rsp
; X64: movl $2, %ecx
; X64: callq f
; X64: leaq [[contbb]](%rip), %rax
; X64: addq $32, %rsp
; X64: popq %rbp
; X64: leaq [[contbb]](%rip), %rax
; X64: retq
; X64: $handlerMap$0$try_catch_catch:

View File

@ -73,7 +73,13 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86: [[contbb:LBB0_[0-9]+]]: # %try.cont
; X86: retl
; X86: [[restorebb:LBB0_[0-9]+]]: # %invoke.cont.3
; FIXME: These should be de-duplicated.
; X86: [[restorebb1:LBB0_[0-9]+]]: # %invoke.cont.2
; X86: movl -16(%ebp), %esp
; X86: addl $12, %ebp
; X86: jmp [[contbb]]
; X86: [[restorebb2:LBB0_[0-9]+]]: # %invoke.cont.3
; X86: movl -16(%ebp), %esp
; X86: addl $12, %ebp
; X86: jmp [[contbb]]
@ -89,9 +95,9 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl %[[e_reg]], (%esp)
; X86: calll _f
; X86-NEXT: movl $[[restorebb1]], %eax
; X86-NEXT: addl $8, %esp
; X86-NEXT: popl %ebp
; X86-NEXT: movl $[[restorebb]], %eax
; X86-NEXT: retl
; X86: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
@ -104,9 +110,9 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X86-DAG: movl %[[addr_reg]], 4(%esp)
; X86-DAG: movl $3, (%esp)
; X86: calll _f
; X86-NEXT: movl $[[restorebb2]], %eax
; X86-NEXT: addl $8, %esp
; X86-NEXT: popl %ebp
; X86-NEXT: movl $[[restorebb]], %eax
; X86-NEXT: retl
; X86: L__ehtable$try_catch_catch:
@ -147,9 +153,9 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-DAG: leaq -[[local_offs]](%rbp), %rdx
; X64-DAG: movl [[e_addr:[-0-9]+]](%rbp), %ecx
; X64: callq f
; X64: addq $32, %rsp
; X64: leaq [[contbb]](%rip), %rax
; X64-NEXT: addq $32, %rsp
; X64-NEXT: popq %rbp
; X64-NEXT: leaq [[contbb]](%rip), %rax
; X64-NEXT: retq
; X64: "?catch$[[catch2bb:[0-9]+]]@?0?try_catch_catch@4HA":
@ -162,9 +168,9 @@ catchendblock: ; preds = %catch, %catch.2, %c
; X64-DAG: movl $3, %ecx
; X64: callq f
; X64: .Ltmp3
; X64: addq $32, %rsp
; X64: leaq [[contbb]](%rip), %rax
; X64-NEXT: addq $32, %rsp
; X64-NEXT: popq %rbp
; X64-NEXT: leaq [[contbb]](%rip), %rax
; X64-NEXT: retq
; X64: $cppxdata$try_catch_catch:

View File

@ -89,9 +89,9 @@ declare i32 @__CxxFrameHandler3(...)
; Prologue is done, emit the .seh_endprologue directive.
; CHECK: .seh_endprologue
; Make sure there is a nop after a call if the call precedes the epilogue.
; Make sure there is at least one instruction after a call before the epilogue.
; CHECK: callq g
; CHECK-NEXT: nop
; CHECK-NEXT: leaq .LBB0_{{[0-9]+}}(%rip), %rax
; Emit a reference to the LSDA.
; CHECK: .seh_handlerdata