Skip to content

Commit d4f1d4b

Browse files
committed
Mark the beginning and end of epilogs for Win x64
1 parent 305b25c commit d4f1d4b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+426
-73
lines changed

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,12 @@ class MCStreamer {
252252
bool AllowAutoPadding = false;
253253

254254
protected:
255+
// True if we are processing SEH directives in an epilogue.
256+
bool InEpilogCFI = false;
257+
258+
// Symbol of the current epilog for which we are processing SEH directives.
259+
MCSymbol *CurrentEpilog = nullptr;
260+
255261
MCFragment *CurFrag = nullptr;
256262

257263
MCStreamer(MCContext &Ctx);
@@ -333,6 +339,10 @@ class MCStreamer {
333339
return WinFrameInfos;
334340
}
335341

342+
MCSymbol *getCurrentEpilog() const { return CurrentEpilog; }
343+
344+
bool isInEpilogCFI() const { return InEpilogCFI; }
345+
336346
void generateCompactUnwindEncodings(MCAsmBackend *MAB);
337347

338348
/// \name Assembly File Formatting.
@@ -1056,6 +1066,8 @@ class MCStreamer {
10561066
SMLoc Loc = SMLoc());
10571067
virtual void emitWinCFIPushFrame(bool Code, SMLoc Loc = SMLoc());
10581068
virtual void emitWinCFIEndProlog(SMLoc Loc = SMLoc());
1069+
virtual void emitWinCFIBeginEpilogue(SMLoc Loc = SMLoc());
1070+
virtual void emitWinCFIEndEpilogue(SMLoc Loc = SMLoc());
10591071
virtual void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
10601072
SMLoc Loc = SMLoc());
10611073
virtual void emitWinEHHandlerData(SMLoc Loc = SMLoc());

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ class MCAsmStreamer final : public MCStreamer {
398398
SMLoc Loc) override;
399399
void emitWinCFIPushFrame(bool Code, SMLoc Loc) override;
400400
void emitWinCFIEndProlog(SMLoc Loc) override;
401+
void emitWinCFIBeginEpilogue(SMLoc Loc) override;
402+
void emitWinCFIEndEpilogue(SMLoc Loc) override;
401403

402404
void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
403405
SMLoc Loc) override;
@@ -2348,6 +2350,20 @@ void MCAsmStreamer::emitWinCFIEndProlog(SMLoc Loc) {
23482350
EmitEOL();
23492351
}
23502352

2353+
void MCAsmStreamer::emitWinCFIBeginEpilogue(SMLoc Loc) {
2354+
MCStreamer::emitWinCFIBeginEpilogue(Loc);
2355+
2356+
OS << "\t.seh_startepilogue";
2357+
EmitEOL();
2358+
}
2359+
2360+
void MCAsmStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {
2361+
MCStreamer::emitWinCFIEndEpilogue(Loc);
2362+
2363+
OS << "\t.seh_endepilogue";
2364+
EmitEOL();
2365+
}
2366+
23512367
void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
23522368
const MCSymbolRefExpr *To,
23532369
uint64_t Count) {

llvm/lib/MC/MCParser/COFFAsmParser.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ class COFFAsmParser : public MCAsmParserExtension {
9292
".seh_stackalloc");
9393
addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndProlog>(
9494
".seh_endprologue");
95+
addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveBeginEpilog>(
96+
".seh_startepilogue");
97+
addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndEpilog>(
98+
".seh_endepilogue");
9599
}
96100

97101
bool parseSectionDirectiveText(StringRef, SMLoc) {
@@ -141,6 +145,8 @@ class COFFAsmParser : public MCAsmParserExtension {
141145
bool parseSEHDirectiveHandlerData(StringRef, SMLoc);
142146
bool parseSEHDirectiveAllocStack(StringRef, SMLoc);
143147
bool parseSEHDirectiveEndProlog(StringRef, SMLoc);
148+
bool ParseSEHDirectiveBeginEpilog(StringRef, SMLoc);
149+
bool ParseSEHDirectiveEndEpilog(StringRef, SMLoc);
144150

145151
bool parseAtUnwindOrAtExcept(bool &unwind, bool &except);
146152
bool parseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
@@ -749,6 +755,18 @@ bool COFFAsmParser::parseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
749755
return false;
750756
}
751757

758+
bool COFFAsmParser::ParseSEHDirectiveBeginEpilog(StringRef, SMLoc Loc) {
759+
Lex();
760+
getStreamer().emitWinCFIBeginEpilogue(Loc);
761+
return false;
762+
}
763+
764+
bool COFFAsmParser::ParseSEHDirectiveEndEpilog(StringRef, SMLoc Loc) {
765+
Lex();
766+
getStreamer().emitWinCFIEndEpilogue(Loc);
767+
return false;
768+
}
769+
752770
bool COFFAsmParser::parseAtUnwindOrAtExcept(bool &unwind, bool &except) {
753771
StringRef identifier;
754772
if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent))

llvm/lib/MC/MCStreamer.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,36 @@ void MCStreamer::emitWinCFIEndProlog(SMLoc Loc) {
10131013
CurFrame->PrologEnd = Label;
10141014
}
10151015

1016+
void MCStreamer::emitWinCFIBeginEpilogue(SMLoc Loc) {
1017+
WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
1018+
if (!CurFrame)
1019+
return;
1020+
1021+
if (!CurFrame->PrologEnd)
1022+
return getContext().reportError(
1023+
Loc, "starting epilogue (.seh_startepilogue) before prologue has ended "
1024+
"(.seh_endprologue) in " +
1025+
CurFrame->Function->getName());
1026+
1027+
InEpilogCFI = true;
1028+
CurrentEpilog = emitCFILabel();
1029+
}
1030+
1031+
void MCStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {
1032+
WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
1033+
if (!CurFrame)
1034+
return;
1035+
1036+
if (!InEpilogCFI)
1037+
return getContext().reportError(Loc, "Stray .seh_endepilogue in " +
1038+
CurFrame->Function->getName());
1039+
1040+
InEpilogCFI = false;
1041+
MCSymbol *Label = emitCFILabel();
1042+
CurFrame->EpilogMap[CurrentEpilog].End = Label;
1043+
CurrentEpilog = nullptr;
1044+
}
1045+
10161046
void MCStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {}
10171047

10181048
void MCStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {}

llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,6 @@ class AArch64TargetELFStreamer : public AArch64TargetStreamer {
106106
};
107107

108108
class AArch64TargetWinCOFFStreamer : public llvm::AArch64TargetStreamer {
109-
private:
110-
// True if we are processing SEH directives in an epilogue.
111-
bool InEpilogCFI = false;
112-
113-
// Symbol of the current epilog for which we are processing SEH directives.
114-
MCSymbol *CurrentEpilog = nullptr;
115109
public:
116110
AArch64TargetWinCOFFStreamer(llvm::MCStreamer &S)
117111
: AArch64TargetStreamer(S) {}

llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ void AArch64TargetWinCOFFStreamer::emitARM64WinUnwindCode(unsigned UnwindCode,
7373
if (!CurFrame)
7474
return;
7575
auto Inst = WinEH::Instruction(UnwindCode, /*Label=*/nullptr, Reg, Offset);
76-
if (InEpilogCFI)
77-
CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
76+
if (S.isInEpilogCFI())
77+
CurFrame->EpilogMap[S.getCurrentEpilog()].Instructions.push_back(Inst);
7878
else
7979
CurFrame->Instructions.push_back(Inst);
8080
}
@@ -183,13 +183,7 @@ void AArch64TargetWinCOFFStreamer::emitARM64WinCFIPrologEnd() {
183183
}
184184

185185
void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogStart() {
186-
auto &S = getStreamer();
187-
WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
188-
if (!CurFrame)
189-
return;
190-
191-
InEpilogCFI = true;
192-
CurrentEpilog = S.emitCFILabel();
186+
getStreamer().emitWinCFIBeginEpilogue();
193187
}
194188

195189
void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogEnd() {
@@ -198,13 +192,12 @@ void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogEnd() {
198192
if (!CurFrame)
199193
return;
200194

201-
InEpilogCFI = false;
202-
WinEH::Instruction Inst =
203-
WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
204-
CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
205-
MCSymbol *Label = S.emitCFILabel();
206-
CurFrame->EpilogMap[CurrentEpilog].End = Label;
207-
CurrentEpilog = nullptr;
195+
if (S.isInEpilogCFI()) {
196+
WinEH::Instruction Inst =
197+
WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
198+
CurFrame->EpilogMap[S.getCurrentEpilog()].Instructions.push_back(Inst);
199+
}
200+
S.emitWinCFIEndEpilogue();
208201
}
209202

210203
void AArch64TargetWinCOFFStreamer::emitARM64WinCFITrapFrame() {

llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,6 @@ llvm::createARMWinCOFFStreamer(MCContext &Context,
7777

7878
namespace {
7979
class ARMTargetWinCOFFStreamer : public llvm::ARMTargetStreamer {
80-
private:
81-
// True if we are processing SEH directives in an epilogue.
82-
bool InEpilogCFI = false;
83-
84-
// Symbol of the current epilog for which we are processing SEH directives.
85-
MCSymbol *CurrentEpilog = nullptr;
86-
8780
public:
8881
ARMTargetWinCOFFStreamer(llvm::MCStreamer &S) : ARMTargetStreamer(S) {}
8982

@@ -114,8 +107,8 @@ void ARMTargetWinCOFFStreamer::emitARMWinUnwindCode(unsigned UnwindCode,
114107
return;
115108
MCSymbol *Label = S.emitCFILabel();
116109
auto Inst = WinEH::Instruction(UnwindCode, Label, Reg, Offset);
117-
if (InEpilogCFI)
118-
CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
110+
if (S.isInEpilogCFI())
111+
CurFrame->EpilogMap[S.getCurrentEpilog()].Instructions.push_back(Inst);
119112
else
120113
CurFrame->Instructions.push_back(Inst);
121114
}
@@ -224,9 +217,10 @@ void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogStart(unsigned Condition) {
224217
if (!CurFrame)
225218
return;
226219

227-
InEpilogCFI = true;
228-
CurrentEpilog = S.emitCFILabel();
229-
CurFrame->EpilogMap[CurrentEpilog].Condition = Condition;
220+
S.emitWinCFIBeginEpilogue();
221+
if (S.isInEpilogCFI()) {
222+
CurFrame->EpilogMap[S.getCurrentEpilog()].Condition = Condition;
223+
}
230224
}
231225

232226
void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogEnd() {
@@ -235,33 +229,26 @@ void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogEnd() {
235229
if (!CurFrame)
236230
return;
237231

238-
if (!CurrentEpilog) {
239-
S.getContext().reportError(SMLoc(), "Stray .seh_endepilogue in " +
240-
CurFrame->Function->getName());
241-
return;
242-
}
243-
244-
std::vector<WinEH::Instruction> &Epilog =
245-
CurFrame->EpilogMap[CurrentEpilog].Instructions;
246-
247-
unsigned UnwindCode = Win64EH::UOP_End;
248-
if (!Epilog.empty()) {
249-
WinEH::Instruction EndInstr = Epilog.back();
250-
if (EndInstr.Operation == Win64EH::UOP_Nop) {
251-
UnwindCode = Win64EH::UOP_EndNop;
252-
Epilog.pop_back();
253-
} else if (EndInstr.Operation == Win64EH::UOP_WideNop) {
254-
UnwindCode = Win64EH::UOP_WideEndNop;
255-
Epilog.pop_back();
232+
if (S.isInEpilogCFI()) {
233+
std::vector<WinEH::Instruction> &Epilog =
234+
CurFrame->EpilogMap[S.getCurrentEpilog()].Instructions;
235+
236+
unsigned UnwindCode = Win64EH::UOP_End;
237+
if (!Epilog.empty()) {
238+
WinEH::Instruction EndInstr = Epilog.back();
239+
if (EndInstr.Operation == Win64EH::UOP_Nop) {
240+
UnwindCode = Win64EH::UOP_EndNop;
241+
Epilog.pop_back();
242+
} else if (EndInstr.Operation == Win64EH::UOP_WideNop) {
243+
UnwindCode = Win64EH::UOP_WideEndNop;
244+
Epilog.pop_back();
245+
}
256246
}
257-
}
258247

259-
InEpilogCFI = false;
260-
WinEH::Instruction Inst = WinEH::Instruction(UnwindCode, nullptr, -1, 0);
261-
CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
262-
MCSymbol *Label = S.emitCFILabel();
263-
CurFrame->EpilogMap[CurrentEpilog].End = Label;
264-
CurrentEpilog = nullptr;
248+
WinEH::Instruction Inst = WinEH::Instruction(UnwindCode, nullptr, -1, 0);
249+
CurFrame->EpilogMap[S.getCurrentEpilog()].Instructions.push_back(Inst);
250+
}
251+
S.emitWinCFIEndEpilogue();
265252
}
266253

267254
void ARMTargetWinCOFFStreamer::emitARMWinCFICustom(unsigned Opcode) {

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,14 +2548,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
25482548
--MBBI;
25492549
}
25502550

2551-
// Windows unwinder will not invoke function's exception handler if IP is
2552-
// either in prologue or in epilogue. This behavior causes a problem when a
2553-
// call immediately precedes an epilogue, because the return address points
2554-
// into the epilogue. To cope with that, we insert an epilogue marker here,
2555-
// then replace it with a 'nop' if it ends up immediately after a CALL in the
2556-
// final emitted code.
25572551
if (NeedsWin64CFI && MF.hasWinCFI())
2558-
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_Epilogue));
2552+
BuildMI(MBB, MBBI, DL, TII.get(X86::SEH_BeginEpilogue));
25592553

25602554
if (!HasFP && NeedsDwarfCFI) {
25612555
MBBI = FirstCSPop;
@@ -2600,6 +2594,9 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
26002594
// Emit tilerelease for AMX kernel.
26012595
if (X86FI->getAMXProgModel() == AMXProgModelEnum::ManagedRA)
26022596
BuildMI(MBB, Terminator, DL, TII.get(X86::TILERELEASE));
2597+
2598+
if (NeedsWin64CFI && MF.hasWinCFI())
2599+
BuildMI(MBB, Terminator, DL, TII.get(X86::SEH_EndEpilogue));
26032600
}
26042601

26052602
StackOffset X86FrameLowering::getFrameIndexReference(const MachineFunction &MF,

llvm/lib/Target/X86/X86InstrCompiler.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,10 @@ let isPseudo = 1, isMeta = 1, isNotDuplicable = 1, SchedRW = [WriteSystem] in {
262262

263263
// Epilog instructions:
264264
let isPseudo = 1, isMeta = 1, SchedRW = [WriteSystem] in {
265-
def SEH_Epilogue : I<0, Pseudo, (outs), (ins),
266-
"#SEH_Epilogue", []>;
265+
def SEH_BeginEpilogue : I<0, Pseudo, (outs), (ins),
266+
"#SEH_BeginEpilogue", []>;
267+
def SEH_EndEpilogue : I<0, Pseudo, (outs), (ins),
268+
"#SEH_EndEpilogue", []>;
267269
}
268270

269271
//===----------------------------------------------------------------------===//

llvm/lib/Target/X86/X86MCInstLower.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1779,6 +1779,14 @@ void X86AsmPrinter::EmitSEHInstruction(const MachineInstr *MI) {
17791779
OutStreamer->emitWinCFIEndProlog();
17801780
break;
17811781

1782+
case X86::SEH_BeginEpilogue:
1783+
OutStreamer->emitWinCFIBeginEpilogue();
1784+
break;
1785+
1786+
case X86::SEH_EndEpilogue:
1787+
OutStreamer->emitWinCFIEndEpilogue();
1788+
break;
1789+
17821790
default:
17831791
llvm_unreachable("expected SEH_ instruction");
17841792
}
@@ -2420,11 +2428,17 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) {
24202428
case X86::SEH_SetFrame:
24212429
case X86::SEH_PushFrame:
24222430
case X86::SEH_EndPrologue:
2431+
case X86::SEH_EndEpilogue:
24232432
EmitSEHInstruction(MI);
24242433
return;
24252434

2426-
case X86::SEH_Epilogue: {
2435+
case X86::SEH_BeginEpilogue: {
24272436
assert(MF->hasWinCFI() && "SEH_ instruction in function without WinCFI?");
2437+
// Windows unwinder will not invoke function's exception handler if IP is
2438+
// either in prologue or in epilogue. This behavior causes a problem when a
2439+
// call immediately precedes an epilogue, because the return address points
2440+
// into the epilogue. To cope with that, we insert a 'nop' if it ends up
2441+
// immediately after a CALL in the final emitted code.
24282442
MachineBasicBlock::const_iterator MBBI(MI);
24292443
// Check if preceded by a call and emit nop if so.
24302444
for (MBBI = PrevCrossBBInst(MBBI);
@@ -2439,6 +2453,8 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) {
24392453
break;
24402454
}
24412455
}
2456+
2457+
EmitSEHInstruction(MI);
24422458
return;
24432459
}
24442460
case X86::UBSAN_UD1:

0 commit comments

Comments
 (0)