Skip to content

Commit cbd8464

Browse files
committed
[MC] [Win64EH] Check that ARM64 prologs and epilogs have the right matching number of instructions
This matches what was done for the ARM implementation (where getting the instruction sizes right is even more tricky, and hence needed tighter testing). This will allow catching any future cases where prologs and epilogs don't match the instructions within them. Differential Revision: https://reviews.llvm.org/D131394
1 parent 24303e3 commit cbd8464

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

llvm/lib/MC/MCWin64EH.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,43 @@ static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
299299
return *MaybeDiff;
300300
}
301301

302+
static void checkARM64Instructions(MCStreamer &Streamer,
303+
ArrayRef<WinEH::Instruction> Insns,
304+
const MCSymbol *Begin, const MCSymbol *End,
305+
StringRef Name, StringRef Type) {
306+
if (!End)
307+
return;
308+
Optional<int64_t> MaybeDistance =
309+
GetOptionalAbsDifference(Streamer, End, Begin);
310+
if (!MaybeDistance)
311+
return;
312+
uint32_t Distance = (uint32_t)*MaybeDistance;
313+
314+
for (const auto &I : Insns) {
315+
switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
316+
default:
317+
break;
318+
case Win64EH::UOP_TrapFrame:
319+
case Win64EH::UOP_PushMachFrame:
320+
case Win64EH::UOP_Context:
321+
case Win64EH::UOP_ClearUnwoundToCall:
322+
// Can't reason about these opcodes and how they map to actual
323+
// instructions.
324+
return;
325+
}
326+
}
327+
// Exclude the end opcode which doesn't map to an instruction.
328+
uint32_t InstructionBytes = 4 * (Insns.size() - 1);
329+
if (Distance != InstructionBytes) {
330+
Streamer.getContext().reportError(
331+
SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
332+
Twine(Distance) +
333+
" bytes of instructions in range, but .seh directives "
334+
"corresponding to " +
335+
Twine(InstructionBytes) + " bytes\n");
336+
}
337+
}
338+
302339
static uint32_t ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
303340
uint32_t Count = 0;
304341
for (const auto &I : Insns) {
@@ -1002,6 +1039,10 @@ static void ARM64ProcessEpilogs(WinEH::FrameInfo *info,
10021039
static void ARM64FindSegmentsInFunction(MCStreamer &streamer,
10031040
WinEH::FrameInfo *info,
10041041
int64_t RawFuncLength) {
1042+
if (info->PrologEnd)
1043+
checkARM64Instructions(streamer, info->Instructions, info->Begin,
1044+
info->PrologEnd, info->Function->getName(),
1045+
"prologue");
10051046
struct EpilogStartEnd {
10061047
MCSymbol *Start;
10071048
int64_t Offset;
@@ -1013,6 +1054,8 @@ static void ARM64FindSegmentsInFunction(MCStreamer &streamer,
10131054
MCSymbol *Start = I.first;
10141055
auto &Instrs = I.second.Instructions;
10151056
int64_t Offset = GetAbsDifference(streamer, Start, info->Begin);
1057+
checkARM64Instructions(streamer, Instrs, Start, I.second.End,
1058+
info->Function->getName(), "epilogue");
10161059
assert((Epilogs.size() == 0 || Offset >= Epilogs.back().End) &&
10171060
"Epilogs should be monotonically ordered");
10181061
// Exclue the end opcode from Instrs.size() when calculating the end of the

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogEnd() {
202202
WinEH::Instruction Inst =
203203
WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
204204
CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
205+
MCSymbol *Label = S.emitCFILabel();
206+
CurFrame->EpilogMap[CurrentEpilog].End = Label;
205207
CurrentEpilog = nullptr;
206208
}
207209

llvm/test/CodeGen/AArch64/wineh5.mir

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
# CHECK-NEXT: Version: 0
99
# CHECK-NEXT: ExceptionData: No
1010
# CHECK-NEXT: EpiloguePacked: Yes
11-
# CHECK-NEXT: EpilogueOffset: 10
12-
# CHECK-NEXT: ByteCodeLength: 20
11+
# CHECK-NEXT: EpilogueOffset: 11
12+
# CHECK-NEXT: ByteCodeLength: 24
1313
# CHECK-NEXT: Prologue [
1414
# CHECK-NEXT: 0xe002dac9 ; sub sp, #2993296
1515
# CHECK-NEXT: 0xe3 ; nop
1616
# CHECK-NEXT: 0xe3 ; nop
17+
# CHECK-NEXT: 0xe3 ; nop
1718
# CHECK-NEXT: 0x42 ; stp x29, x30, [sp, #16]
1819
# CHECK-NEXT: 0xd53f ; str x28, [sp, #-256]!
1920
# CHECK-NEXT: 0xe4 ; end
@@ -158,7 +159,9 @@ body: |
158159
frame-setup SEH_SaveReg_X 28, -256
159160
frame-setup STPXi killed $fp, killed $lr, $sp, 2 :: (store (s64) into %stack.7), (store (s64) into %stack.8)
160161
frame-setup SEH_SaveFPLR 16
161-
$x15 = frame-setup MOVi64imm 187081
162+
$x15 = frame-setup MOVZXi 56009, 0
163+
frame-setup SEH_Nop
164+
$x15 = frame-setup MOVKXi $x15, 2, 16
162165
frame-setup SEH_Nop
163166
frame-setup BL &__chkstk, implicit-def $lr, implicit $sp, implicit $x15
164167
frame-setup SEH_Nop

0 commit comments

Comments
 (0)