Skip to content

Commit 2718654

Browse files
authored
[MC] Support .cfi_label
GNU assembler 2.26 introduced the .cfi_label directive. It does not expand to any CFI instructions, but defines a label in .eh_frame/.debug_frame, which can be used by runtime patching code to locate the FDE. .cfi_label is not allowed for CIE's initial instructions, and can therefore be used to force the next instruction to be placed in a FDE instead of a CIE. In glibc since 2018, sysdeps/riscv/start.S utilizes .cfi_label to force DW_CFA_undefined to be placed in a FDE. arc/csky/loongarch ports have copied this use. ``` .cfi_startproc // DW_CFA_undefined is allowed for CIE's initial instructions. // Without .cfi_label, gas would place DW_CFA_undefined in a CIE. .cfi_label .Ldummy .cfi_undefined ra .cfi_endproc ``` No CFI instruction is associated with .cfi_label, so the `case MCCFIInstruction::OpLabel:` code in BOLT is unreachable and onlt to make -Wswitch happy. Close #97222 Pull Request: #97922
1 parent f13463e commit 2718654

File tree

9 files changed

+120
-1
lines changed

9 files changed

+120
-1
lines changed

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,6 +2538,7 @@ struct CFISnapshot {
25382538
case MCCFIInstruction::OpWindowSave:
25392539
case MCCFIInstruction::OpNegateRAState:
25402540
case MCCFIInstruction::OpLLVMDefAspaceCfa:
2541+
case MCCFIInstruction::OpLabel:
25412542
llvm_unreachable("unsupported CFI opcode");
25422543
break;
25432544
case MCCFIInstruction::OpRememberState:
@@ -2675,6 +2676,7 @@ struct CFISnapshotDiff : public CFISnapshot {
26752676
case MCCFIInstruction::OpWindowSave:
26762677
case MCCFIInstruction::OpNegateRAState:
26772678
case MCCFIInstruction::OpLLVMDefAspaceCfa:
2679+
case MCCFIInstruction::OpLabel:
26782680
llvm_unreachable("unsupported CFI opcode");
26792681
return false;
26802682
case MCCFIInstruction::OpRememberState:
@@ -2823,6 +2825,7 @@ BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState,
28232825
case MCCFIInstruction::OpWindowSave:
28242826
case MCCFIInstruction::OpNegateRAState:
28252827
case MCCFIInstruction::OpLLVMDefAspaceCfa:
2828+
case MCCFIInstruction::OpLabel:
28262829
llvm_unreachable("unsupported CFI opcode");
28272830
break;
28282831
case MCCFIInstruction::OpGnuArgsSize:

llvm/include/llvm/MC/MCDwarf.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,8 @@ class MCCFIInstruction {
500500
OpRegister,
501501
OpWindowSave,
502502
OpNegateRAState,
503-
OpGnuArgsSize
503+
OpGnuArgsSize,
504+
OpLabel,
504505
};
505506

506507
private:
@@ -519,6 +520,7 @@ class MCCFIInstruction {
519520
unsigned Register;
520521
unsigned Register2;
521522
} RR;
523+
MCSymbol *CfiLabel;
522524
} U;
523525
OpType Operation;
524526
SMLoc Loc;
@@ -544,6 +546,12 @@ class MCCFIInstruction {
544546
U.RIA = {R, O, AS};
545547
}
546548

549+
MCCFIInstruction(OpType Op, MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc)
550+
: Label(L), Operation(Op), Loc(Loc) {
551+
assert(Op == OpLabel);
552+
U.CfiLabel = CfiLabel;
553+
}
554+
547555
public:
548556
/// .cfi_def_cfa defines a rule for computing CFA as: take address from
549557
/// Register and add Offset to it.
@@ -664,6 +672,11 @@ class MCCFIInstruction {
664672
return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc);
665673
}
666674

675+
static MCCFIInstruction createLabel(MCSymbol *L, MCSymbol *CfiLabel,
676+
SMLoc Loc) {
677+
return MCCFIInstruction(OpLabel, L, CfiLabel, Loc);
678+
}
679+
667680
OpType getOperation() const { return Operation; }
668681
MCSymbol *getLabel() const { return Label; }
669682

@@ -698,6 +711,11 @@ class MCCFIInstruction {
698711
return U.RI.Offset;
699712
}
700713

714+
MCSymbol *getCfiLabel() const {
715+
assert(Operation == OpLabel);
716+
return U.CfiLabel;
717+
}
718+
701719
StringRef getValues() const {
702720
assert(Operation == OpEscape);
703721
return StringRef(&Values[0], Values.size());

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,7 @@ class MCStreamer {
10191019
SMLoc Loc = {});
10201020
virtual void emitCFIWindowSave(SMLoc Loc = {});
10211021
virtual void emitCFINegateRAState(SMLoc Loc = {});
1022+
virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name);
10221023

10231024
virtual void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
10241025
virtual void emitWinCFIEndProc(SMLoc Loc = SMLoc());

llvm/lib/CodeGen/CFIInstrInserter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
248248
case MCCFIInstruction::OpWindowSave:
249249
case MCCFIInstruction::OpNegateRAState:
250250
case MCCFIInstruction::OpGnuArgsSize:
251+
case MCCFIInstruction::OpLabel:
251252
break;
252253
}
253254
if (CSRReg || CSROffset) {

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ class MCAsmStreamer final : public MCStreamer {
356356
void emitCFIWindowSave(SMLoc Loc) override;
357357
void emitCFINegateRAState(SMLoc Loc) override;
358358
void emitCFIReturnColumn(int64_t Register) override;
359+
void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
359360

360361
void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
361362
void emitWinCFIEndProc(SMLoc Loc) override;
@@ -2126,6 +2127,12 @@ void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {
21262127
EmitEOL();
21272128
}
21282129

2130+
void MCAsmStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
2131+
MCStreamer::emitCFILabelDirective(Loc, Name);
2132+
OS << "\t.cfi_label " << Name;
2133+
EmitEOL();
2134+
}
2135+
21292136
void MCAsmStreamer::emitCFIBKeyFrame() {
21302137
MCStreamer::emitCFIBKeyFrame();
21312138
OS << "\t.cfi_b_key_frame";

llvm/lib/MC/MCDwarf.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,9 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
14651465
case MCCFIInstruction::OpEscape:
14661466
Streamer.emitBytes(Instr.getValues());
14671467
return;
1468+
case MCCFIInstruction::OpLabel:
1469+
Streamer.emitLabel(Instr.getCfiLabel(), Instr.getLoc());
1470+
return;
14681471
}
14691472
llvm_unreachable("Unhandled case in switch");
14701473
}

llvm/lib/MC/MCParser/AsmParser.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ class AsmParser : public MCAsmParser {
520520
DK_CFI_UNDEFINED,
521521
DK_CFI_REGISTER,
522522
DK_CFI_WINDOW_SAVE,
523+
DK_CFI_LABEL,
523524
DK_CFI_B_KEY_FRAME,
524525
DK_MACROS_ON,
525526
DK_MACROS_OFF,
@@ -622,6 +623,7 @@ class AsmParser : public MCAsmParser {
622623
bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc);
623624
bool parseDirectiveCFISignalFrame(SMLoc DirectiveLoc);
624625
bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);
626+
bool parseDirectiveCFILabel(SMLoc DirectiveLoc);
625627

626628
// macro directives
627629
bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);
@@ -2224,6 +2226,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
22242226
return parseDirectiveCFIRegister(IDLoc);
22252227
case DK_CFI_WINDOW_SAVE:
22262228
return parseDirectiveCFIWindowSave(IDLoc);
2229+
case DK_CFI_LABEL:
2230+
return parseDirectiveCFILabel(IDLoc);
22272231
case DK_MACROS_ON:
22282232
case DK_MACROS_OFF:
22292233
return parseDirectiveMacrosOnOff(IDVal);
@@ -4488,6 +4492,19 @@ bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {
44884492
return false;
44894493
}
44904494

4495+
/// parseDirectiveCFILabel
4496+
/// ::= .cfi_label label
4497+
bool AsmParser::parseDirectiveCFILabel(SMLoc Loc) {
4498+
StringRef Name;
4499+
Loc = Lexer.getLoc();
4500+
if (parseIdentifier(Name))
4501+
return TokError("expected identifier");
4502+
if (parseEOL())
4503+
return true;
4504+
getStreamer().emitCFILabelDirective(Loc, Name);
4505+
return false;
4506+
}
4507+
44914508
/// parseDirectiveAltmacro
44924509
/// ::= .altmacro
44934510
/// ::= .noaltmacro
@@ -5560,6 +5577,7 @@ void AsmParser::initializeDirectiveKindMap() {
55605577
DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;
55615578
DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
55625579
DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
5580+
DirectiveKindMap[".cfi_label"] = DK_CFI_LABEL;
55635581
DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
55645582
DirectiveKindMap[".cfi_mte_tagged_frame"] = DK_CFI_MTE_TAGGED_FRAME;
55655583
DirectiveKindMap[".macros_on"] = DK_MACROS_ON;

llvm/lib/MC/MCStreamer.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,13 @@ void MCStreamer::emitCFIReturnColumn(int64_t Register) {
689689
CurFrame->RAReg = Register;
690690
}
691691

692+
void MCStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
693+
MCSymbol *Label = emitCFILabel();
694+
MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
695+
if (MCDwarfFrameInfo *F = getCurrentDwarfFrameInfo())
696+
F->Instructions.push_back(MCCFIInstruction::createLabel(Label, Sym, Loc));
697+
}
698+
692699
WinEH::FrameInfo *MCStreamer::EnsureValidWinFrameInfo(SMLoc Loc) {
693700
const MCAsmInfo *MAI = Context.getAsmInfo();
694701
if (!MAI->usesWindowsCFI()) {

llvm/test/MC/ELF/cfi-label.s

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# RUN: llvm-mc -triple x86_64 %s | FileCheck %s --check-prefix=ASM
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
3+
# RUN: llvm-readelf -sX %t | FileCheck %s --check-prefix=SYMTAB
4+
# RUN: llvm-dwarfdump --eh-frame %t | FileCheck %s
5+
6+
# RUN: not llvm-mc -filetype=obj -triple=x86_64 --defsym ERR=1 %s -o /dev/null 2>&1 | \
7+
# RUN: FileCheck %s --check-prefix=ERR --implicit-check-not=error:
8+
9+
# ASM: nop
10+
# ASM-NEXT: .cfi_label cfi1
11+
# ASM-NEXT: .cfi_escape 0x00
12+
# ASM: .globl cfi2
13+
# ASM-NEXT: .cfi_label cfi2
14+
# ASM: nop
15+
# ASM-NEXT: .cfi_label .Lcfi3
16+
17+
# SYMTAB: 000000000000002b 0 NOTYPE LOCAL DEFAULT 3 (.eh_frame) cfi1
18+
# SYMTAB: 000000000000002d 0 NOTYPE GLOBAL DEFAULT 3 (.eh_frame) cfi2
19+
# SYMTAB-NOT: {{.}}
20+
21+
# CHECK: DW_CFA_remember_state:
22+
# CHECK-NEXT: DW_CFA_advance_loc: 1 to 0x1
23+
# CHECK-NEXT: DW_CFA_nop:
24+
# CHECK-NEXT: DW_CFA_advance_loc: 1 to 0x2
25+
# CHECK-NEXT: DW_CFA_nop:
26+
# CHECK-NEXT: DW_CFA_nop:
27+
# CHECK-NEXT: DW_CFA_advance_loc: 1 to 0x3
28+
# CHECK-NEXT: DW_CFA_nop:
29+
# CHECK-NEXT: DW_CFA_nop:
30+
# CHECK-NEXT: DW_CFA_nop:
31+
# CHECK-NEXT: DW_CFA_restore_state:
32+
33+
.globl foo
34+
foo:
35+
.cfi_startproc
36+
.cfi_remember_state
37+
nop
38+
.cfi_label cfi1
39+
.cfi_escape 0
40+
nop
41+
.globl cfi2
42+
.cfi_label cfi2
43+
.cfi_escape 0, 0
44+
nop
45+
.cfi_label .Lcfi3
46+
.cfi_escape 0, 0, 0
47+
.cfi_restore_state
48+
ret
49+
50+
# ERR: [[#@LINE+10]]:1: error: this directive must appear between .cfi_startproc and .cfi_endproc directives
51+
.ifdef ERR
52+
# ERR: [[#@LINE+1]]:12: error: symbol 'foo' is already defined
53+
.cfi_label foo
54+
# ERR: [[#@LINE+1]]:12: error: symbol '.Lcfi3' is already defined
55+
.cfi_label .Lcfi3
56+
.endif
57+
.cfi_endproc
58+
59+
.ifdef ERR
60+
.cfi_label after_endproc
61+
.endif

0 commit comments

Comments
 (0)