Skip to content

Commit f5e2ea9

Browse files
committed
[AArch64] Add asm directives for the remaining SEH unwind codes
Add support in llvm-readobj for displaying them and support in the asm parsser, AArch64TargetStreamer and MCWin64EH for emitting them. The directives for the remaining basic opcodes have names that match the opcode in the documentation. The directives for custom stack cases, that are named MSFT_OP_TRAP_FRAME, MSFT_OP_MACHINE_FRAME, MSFT_OP_CONTEXT and MSFT_OP_CLEAR_UNWOUND_TO_CALL, are given matching assembler directive names that fit into the rest of the opcode naming; .seh_trap_frame, .seh_context, .seh_clear_unwound_to_call The opcode MSFT_OP_MACHINE_FRAME is mapped to the existing opecode enum UOP_PushMachFrame that is used on x86_64, and also uses the corresponding existing x86_64 directive name .seh_pushframe. Differential Revision: https://reviews.llvm.org/D86889
1 parent e123959 commit f5e2ea9

File tree

9 files changed

+282
-6
lines changed

9 files changed

+282
-6
lines changed

llvm/include/llvm/Support/Win64EH.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,26 @@ enum UnwindOpcodes {
3838
// The following set of unwind opcodes is for ARM64. They are documented at
3939
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
4040
UOP_AllocMedium,
41+
UOP_SaveR19R20X,
4142
UOP_SaveFPLRX,
4243
UOP_SaveFPLR,
4344
UOP_SaveReg,
4445
UOP_SaveRegX,
4546
UOP_SaveRegP,
4647
UOP_SaveRegPX,
48+
UOP_SaveLRPair,
4749
UOP_SaveFReg,
4850
UOP_SaveFRegX,
4951
UOP_SaveFRegP,
5052
UOP_SaveFRegPX,
5153
UOP_SetFP,
5254
UOP_AddFP,
5355
UOP_Nop,
54-
UOP_End
56+
UOP_End,
57+
UOP_SaveNext,
58+
UOP_TrapFrame,
59+
UOP_Context,
60+
UOP_ClearUnwoundToCall
5561
};
5662

5763
/// UnwindCode - This union describes a single operation in a function prolog,

llvm/lib/MC/MCWin64EH.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) {
280280
case Win64EH::UOP_AllocLarge:
281281
Count += 4;
282282
break;
283+
case Win64EH::UOP_SaveR19R20X:
284+
Count += 1;
285+
break;
283286
case Win64EH::UOP_SaveFPLRX:
284287
Count += 1;
285288
break;
@@ -298,6 +301,9 @@ ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) {
298301
case Win64EH::UOP_SaveRegX:
299302
Count += 2;
300303
break;
304+
case Win64EH::UOP_SaveLRPair:
305+
Count += 2;
306+
break;
301307
case Win64EH::UOP_SaveFReg:
302308
Count += 2;
303309
break;
@@ -322,6 +328,21 @@ ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) {
322328
case Win64EH::UOP_End:
323329
Count += 1;
324330
break;
331+
case Win64EH::UOP_SaveNext:
332+
Count += 1;
333+
break;
334+
case Win64EH::UOP_TrapFrame:
335+
Count += 1;
336+
break;
337+
case Win64EH::UOP_PushMachFrame:
338+
Count += 1;
339+
break;
340+
case Win64EH::UOP_Context:
341+
Count += 1;
342+
break;
343+
case Win64EH::UOP_ClearUnwoundToCall:
344+
Count += 1;
345+
break;
325346
}
326347
}
327348
return Count;
@@ -375,6 +396,11 @@ static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
375396
b = 0xE3;
376397
streamer.emitInt8(b);
377398
break;
399+
case Win64EH::UOP_SaveR19R20X:
400+
b = 0x20;
401+
b |= (inst.Offset >> 3) & 0x1F;
402+
streamer.emitInt8(b);
403+
break;
378404
case Win64EH::UOP_SaveFPLRX:
379405
b = 0x80;
380406
b |= ((inst.Offset - 1) >> 3) & 0x3F;
@@ -417,6 +443,16 @@ static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
417443
b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
418444
streamer.emitInt8(b);
419445
break;
446+
case Win64EH::UOP_SaveLRPair:
447+
assert(inst.Register >= 19 && "Saved reg must be >= 19");
448+
reg = inst.Register - 19;
449+
assert((reg % 2) == 0 && "Saved reg must be 19+2*X");
450+
reg /= 2;
451+
b = 0xD6 | ((reg & 0x7) >> 2);
452+
streamer.emitInt8(b);
453+
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
454+
streamer.emitInt8(b);
455+
break;
420456
case Win64EH::UOP_SaveFReg:
421457
assert(inst.Register >= 8 && "Saved dreg must be >= 8");
422458
reg = inst.Register - 8;
@@ -453,6 +489,26 @@ static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
453489
b = 0xE4;
454490
streamer.emitInt8(b);
455491
break;
492+
case Win64EH::UOP_SaveNext:
493+
b = 0xE6;
494+
streamer.emitInt8(b);
495+
break;
496+
case Win64EH::UOP_TrapFrame:
497+
b = 0xE8;
498+
streamer.emitInt8(b);
499+
break;
500+
case Win64EH::UOP_PushMachFrame:
501+
b = 0xE9;
502+
streamer.emitInt8(b);
503+
break;
504+
case Win64EH::UOP_Context:
505+
b = 0xEA;
506+
streamer.emitInt8(b);
507+
break;
508+
case Win64EH::UOP_ClearUnwoundToCall:
509+
b = 0xEC;
510+
streamer.emitInt8(b);
511+
break;
456512
}
457513
}
458514

llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,21 +186,28 @@ class AArch64AsmParser : public MCTargetAsmParser {
186186

187187
bool parseDirectiveSEHAllocStack(SMLoc L);
188188
bool parseDirectiveSEHPrologEnd(SMLoc L);
189+
bool parseDirectiveSEHSaveR19R20X(SMLoc L);
189190
bool parseDirectiveSEHSaveFPLR(SMLoc L);
190191
bool parseDirectiveSEHSaveFPLRX(SMLoc L);
191192
bool parseDirectiveSEHSaveReg(SMLoc L);
192193
bool parseDirectiveSEHSaveRegX(SMLoc L);
193194
bool parseDirectiveSEHSaveRegP(SMLoc L);
194195
bool parseDirectiveSEHSaveRegPX(SMLoc L);
196+
bool parseDirectiveSEHSaveLRPair(SMLoc L);
195197
bool parseDirectiveSEHSaveFReg(SMLoc L);
196198
bool parseDirectiveSEHSaveFRegX(SMLoc L);
197199
bool parseDirectiveSEHSaveFRegP(SMLoc L);
198200
bool parseDirectiveSEHSaveFRegPX(SMLoc L);
199201
bool parseDirectiveSEHSetFP(SMLoc L);
200202
bool parseDirectiveSEHAddFP(SMLoc L);
201203
bool parseDirectiveSEHNop(SMLoc L);
204+
bool parseDirectiveSEHSaveNext(SMLoc L);
202205
bool parseDirectiveSEHEpilogStart(SMLoc L);
203206
bool parseDirectiveSEHEpilogEnd(SMLoc L);
207+
bool parseDirectiveSEHTrapFrame(SMLoc L);
208+
bool parseDirectiveSEHMachineFrame(SMLoc L);
209+
bool parseDirectiveSEHContext(SMLoc L);
210+
bool parseDirectiveSEHClearUnwoundToCall(SMLoc L);
204211

205212
bool validateInstruction(MCInst &Inst, SMLoc &IDLoc,
206213
SmallVectorImpl<SMLoc> &Loc);
@@ -5174,6 +5181,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
51745181
parseDirectiveSEHAllocStack(Loc);
51755182
else if (IDVal == ".seh_endprologue")
51765183
parseDirectiveSEHPrologEnd(Loc);
5184+
else if (IDVal == ".seh_save_r19r20_x")
5185+
parseDirectiveSEHSaveR19R20X(Loc);
51775186
else if (IDVal == ".seh_save_fplr")
51785187
parseDirectiveSEHSaveFPLR(Loc);
51795188
else if (IDVal == ".seh_save_fplr_x")
@@ -5186,6 +5195,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
51865195
parseDirectiveSEHSaveRegP(Loc);
51875196
else if (IDVal == ".seh_save_regp_x")
51885197
parseDirectiveSEHSaveRegPX(Loc);
5198+
else if (IDVal == ".seh_save_lrpair")
5199+
parseDirectiveSEHSaveLRPair(Loc);
51895200
else if (IDVal == ".seh_save_freg")
51905201
parseDirectiveSEHSaveFReg(Loc);
51915202
else if (IDVal == ".seh_save_freg_x")
@@ -5200,10 +5211,20 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
52005211
parseDirectiveSEHAddFP(Loc);
52015212
else if (IDVal == ".seh_nop")
52025213
parseDirectiveSEHNop(Loc);
5214+
else if (IDVal == ".seh_save_next")
5215+
parseDirectiveSEHSaveNext(Loc);
52035216
else if (IDVal == ".seh_startepilogue")
52045217
parseDirectiveSEHEpilogStart(Loc);
52055218
else if (IDVal == ".seh_endepilogue")
52065219
parseDirectiveSEHEpilogEnd(Loc);
5220+
else if (IDVal == ".seh_trap_frame")
5221+
parseDirectiveSEHTrapFrame(Loc);
5222+
else if (IDVal == ".seh_pushframe")
5223+
parseDirectiveSEHMachineFrame(Loc);
5224+
else if (IDVal == ".seh_context")
5225+
parseDirectiveSEHContext(Loc);
5226+
else if (IDVal == ".seh_clear_unwound_to_call")
5227+
parseDirectiveSEHClearUnwoundToCall(Loc);
52075228
else
52085229
return true;
52095230
} else
@@ -5645,6 +5666,16 @@ bool AArch64AsmParser::parseDirectiveSEHPrologEnd(SMLoc L) {
56455666
return false;
56465667
}
56475668

5669+
/// parseDirectiveSEHSaveR19R20X
5670+
/// ::= .seh_save_r19r20_x
5671+
bool AArch64AsmParser::parseDirectiveSEHSaveR19R20X(SMLoc L) {
5672+
int64_t Offset;
5673+
if (parseImmExpr(Offset))
5674+
return true;
5675+
getTargetStreamer().EmitARM64WinCFISaveR19R20X(Offset);
5676+
return false;
5677+
}
5678+
56485679
/// parseDirectiveSEHSaveFPLR
56495680
/// ::= .seh_save_fplr
56505681
bool AArch64AsmParser::parseDirectiveSEHSaveFPLR(SMLoc L) {
@@ -5713,6 +5744,22 @@ bool AArch64AsmParser::parseDirectiveSEHSaveRegPX(SMLoc L) {
57135744
return false;
57145745
}
57155746

5747+
/// parseDirectiveSEHSaveLRPair
5748+
/// ::= .seh_save_lrpair
5749+
bool AArch64AsmParser::parseDirectiveSEHSaveLRPair(SMLoc L) {
5750+
unsigned Reg;
5751+
int64_t Offset;
5752+
L = getLoc();
5753+
if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) ||
5754+
parseComma() || parseImmExpr(Offset))
5755+
return true;
5756+
if (check(((Reg - 19) % 2 != 0), L,
5757+
"expected register with even offset from x19"))
5758+
return true;
5759+
getTargetStreamer().EmitARM64WinCFISaveLRPair(Reg, Offset);
5760+
return false;
5761+
}
5762+
57165763
/// parseDirectiveSEHSaveFReg
57175764
/// ::= .seh_save_freg
57185765
bool AArch64AsmParser::parseDirectiveSEHSaveFReg(SMLoc L) {
@@ -5785,6 +5832,13 @@ bool AArch64AsmParser::parseDirectiveSEHNop(SMLoc L) {
57855832
return false;
57865833
}
57875834

5835+
/// parseDirectiveSEHSaveNext
5836+
/// ::= .seh_save_next
5837+
bool AArch64AsmParser::parseDirectiveSEHSaveNext(SMLoc L) {
5838+
getTargetStreamer().EmitARM64WinCFISaveNext();
5839+
return false;
5840+
}
5841+
57885842
/// parseDirectiveSEHEpilogStart
57895843
/// ::= .seh_startepilogue
57905844
bool AArch64AsmParser::parseDirectiveSEHEpilogStart(SMLoc L) {
@@ -5799,6 +5853,34 @@ bool AArch64AsmParser::parseDirectiveSEHEpilogEnd(SMLoc L) {
57995853
return false;
58005854
}
58015855

5856+
/// parseDirectiveSEHTrapFrame
5857+
/// ::= .seh_trap_frame
5858+
bool AArch64AsmParser::parseDirectiveSEHTrapFrame(SMLoc L) {
5859+
getTargetStreamer().EmitARM64WinCFITrapFrame();
5860+
return false;
5861+
}
5862+
5863+
/// parseDirectiveSEHMachineFrame
5864+
/// ::= .seh_pushframe
5865+
bool AArch64AsmParser::parseDirectiveSEHMachineFrame(SMLoc L) {
5866+
getTargetStreamer().EmitARM64WinCFIMachineFrame();
5867+
return false;
5868+
}
5869+
5870+
/// parseDirectiveSEHContext
5871+
/// ::= .seh_context
5872+
bool AArch64AsmParser::parseDirectiveSEHContext(SMLoc L) {
5873+
getTargetStreamer().EmitARM64WinCFIContext();
5874+
return false;
5875+
}
5876+
5877+
/// parseDirectiveSEHClearUnwoundToCall
5878+
/// ::= .seh_clear_unwound_to_call
5879+
bool AArch64AsmParser::parseDirectiveSEHClearUnwoundToCall(SMLoc L) {
5880+
getTargetStreamer().EmitARM64WinCFIClearUnwoundToCall();
5881+
return false;
5882+
}
5883+
58025884
bool
58035885
AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
58045886
AArch64MCExpr::VariantKind &ELFRefKind,

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
5050
void EmitARM64WinCFIAllocStack(unsigned Size) override {
5151
OS << "\t.seh_stackalloc " << Size << "\n";
5252
}
53+
void EmitARM64WinCFISaveR19R20X(int Offset) override {
54+
OS << "\t.seh_save_r19r20_x " << Offset << "\n";
55+
}
5356
void EmitARM64WinCFISaveFPLR(int Offset) override {
5457
OS << "\t.seh_save_fplr " << Offset << "\n";
5558
}
@@ -68,6 +71,9 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
6871
void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override {
6972
OS << "\t.seh_save_regp_x x" << Reg << ", " << Offset << "\n";
7073
}
74+
void EmitARM64WinCFISaveLRPair(unsigned Reg, int Offset) override {
75+
OS << "\t.seh_save_lrpair x" << Reg << ", " << Offset << "\n";
76+
}
7177
void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) override {
7278
OS << "\t.seh_save_freg d" << Reg << ", " << Offset << "\n";
7379
}
@@ -85,9 +91,16 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
8591
OS << "\t.seh_add_fp " << Size << "\n";
8692
}
8793
void EmitARM64WinCFINop() override { OS << "\t.seh_nop\n"; }
94+
void EmitARM64WinCFISaveNext() override { OS << "\t.seh_save_next\n"; }
8895
void EmitARM64WinCFIPrologEnd() override { OS << "\t.seh_endprologue\n"; }
8996
void EmitARM64WinCFIEpilogStart() override { OS << "\t.seh_startepilogue\n"; }
9097
void EmitARM64WinCFIEpilogEnd() override { OS << "\t.seh_endepilogue\n"; }
98+
void EmitARM64WinCFITrapFrame() override { OS << "\t.seh_trap_frame\n"; }
99+
void EmitARM64WinCFIMachineFrame() override { OS << "\t.seh_pushframe\n"; }
100+
void EmitARM64WinCFIContext() override { OS << "\t.seh_context\n"; }
101+
void EmitARM64WinCFIClearUnwoundToCall() override {
102+
OS << "\t.seh_clear_unwound_to_call\n";
103+
}
91104

92105
public:
93106
AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,29 @@ class AArch64TargetStreamer : public MCTargetStreamer {
3737
virtual void emitInst(uint32_t Inst);
3838

3939
virtual void EmitARM64WinCFIAllocStack(unsigned Size) {}
40+
virtual void EmitARM64WinCFISaveR19R20X(int Offset) {}
4041
virtual void EmitARM64WinCFISaveFPLR(int Offset) {}
4142
virtual void EmitARM64WinCFISaveFPLRX(int Offset) {}
4243
virtual void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) {}
4344
virtual void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) {}
4445
virtual void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) {}
4546
virtual void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) {}
47+
virtual void EmitARM64WinCFISaveLRPair(unsigned Reg, int Offset) {}
4648
virtual void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) {}
4749
virtual void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) {}
4850
virtual void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) {}
4951
virtual void EmitARM64WinCFISaveFRegPX(unsigned Reg, int Offset) {}
5052
virtual void EmitARM64WinCFISetFP() {}
5153
virtual void EmitARM64WinCFIAddFP(unsigned Size) {}
5254
virtual void EmitARM64WinCFINop() {}
55+
virtual void EmitARM64WinCFISaveNext() {}
5356
virtual void EmitARM64WinCFIPrologEnd() {}
5457
virtual void EmitARM64WinCFIEpilogStart() {}
5558
virtual void EmitARM64WinCFIEpilogEnd() {}
59+
virtual void EmitARM64WinCFITrapFrame() {}
60+
virtual void EmitARM64WinCFIMachineFrame() {}
61+
virtual void EmitARM64WinCFIContext() {}
62+
virtual void EmitARM64WinCFIClearUnwoundToCall() {}
5663

5764
private:
5865
std::unique_ptr<AssemblerConstantPools> ConstantPools;
@@ -82,22 +89,30 @@ class AArch64TargetWinCOFFStreamer : public llvm::AArch64TargetStreamer {
8289
// The unwind codes on ARM64 Windows are documented at
8390
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
8491
void EmitARM64WinCFIAllocStack(unsigned Size) override;
92+
void EmitARM64WinCFISaveR19R20X(int Offset) override;
8593
void EmitARM64WinCFISaveFPLR(int Offset) override;
8694
void EmitARM64WinCFISaveFPLRX(int Offset) override;
8795
void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) override;
8896
void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) override;
8997
void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) override;
9098
void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override;
99+
void EmitARM64WinCFISaveLRPair(unsigned Reg, int Offset) override;
91100
void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) override;
92101
void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) override;
93102
void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) override;
94103
void EmitARM64WinCFISaveFRegPX(unsigned Reg, int Offset) override;
95104
void EmitARM64WinCFISetFP() override;
96105
void EmitARM64WinCFIAddFP(unsigned Size) override;
97106
void EmitARM64WinCFINop() override;
107+
void EmitARM64WinCFISaveNext() override;
98108
void EmitARM64WinCFIPrologEnd() override;
99109
void EmitARM64WinCFIEpilogStart() override;
100110
void EmitARM64WinCFIEpilogEnd() override;
111+
void EmitARM64WinCFITrapFrame() override;
112+
void EmitARM64WinCFIMachineFrame() override;
113+
void EmitARM64WinCFIContext() override;
114+
void EmitARM64WinCFIClearUnwoundToCall() override;
115+
101116
private:
102117
void EmitARM64WinUnwindCode(unsigned UnwindCode, int Reg, int Offset);
103118
};

0 commit comments

Comments
 (0)