Skip to content

Commit b3458fd

Browse files
authored
[llvm] Win x64 Unwind V2 1/n: Mark beginning and end of epilogs (#110024)
Windows x64 Unwind V2 adds epilog information to unwind data: specifically, the length of the epilog and the offset of each epilog. The first step to do this is to add markers to the beginning and end of each epilog when generating Windows x64 code. I've modelled this after how LLVM was marking ARM and AArch64 epilogs in Windows (and unified the code between the three).
1 parent fabe747 commit b3458fd

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
@@ -137,12 +137,6 @@ class AArch64TargetELFStreamer : public AArch64TargetStreamer {
137137
};
138138

139139
class AArch64TargetWinCOFFStreamer : public llvm::AArch64TargetStreamer {
140-
private:
141-
// True if we are processing SEH directives in an epilogue.
142-
bool InEpilogCFI = false;
143-
144-
// Symbol of the current epilog for which we are processing SEH directives.
145-
MCSymbol *CurrentEpilog = nullptr;
146140
public:
147141
AArch64TargetWinCOFFStreamer(llvm::MCStreamer &S)
148142
: 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
@@ -2578,14 +2578,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
25782578
--MBBI;
25792579
}
25802580

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

25902584
if (!HasFP && NeedsDwarfCFI) {
25912585
MBBI = FirstCSPop;
@@ -2630,6 +2624,9 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
26302624
// Emit tilerelease for AMX kernel.
26312625
if (X86FI->getAMXProgModel() == AMXProgModelEnum::ManagedRA)
26322626
BuildMI(MBB, Terminator, DL, TII.get(X86::TILERELEASE));
2627+
2628+
if (NeedsWin64CFI && MF.hasWinCFI())
2629+
BuildMI(MBB, Terminator, DL, TII.get(X86::SEH_EndEpilogue));
26332630
}
26342631

26352632
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)