Skip to content

Commit

Permalink
[MC] Support .cfi_label
Browse files Browse the repository at this point in the history
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 llvm#97222

Pull Request: llvm#97922

Change-Id: Ic236d33bf52ac5631bd202c2896d23463c8e099b
  • Loading branch information
MaskRay authored and ronlieb committed Jul 9, 2024
1 parent 952ae43 commit 48f05fd
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 5 deletions.
3 changes: 3 additions & 0 deletions bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2538,6 +2538,7 @@ struct CFISnapshot {
case MCCFIInstruction::OpWindowSave:
case MCCFIInstruction::OpNegateRAState:
case MCCFIInstruction::OpLLVMDefAspaceCfa:
case MCCFIInstruction::OpLabel:
llvm_unreachable("unsupported CFI opcode");
break;
case MCCFIInstruction::OpRememberState:
Expand Down Expand Up @@ -2675,6 +2676,7 @@ struct CFISnapshotDiff : public CFISnapshot {
case MCCFIInstruction::OpWindowSave:
case MCCFIInstruction::OpNegateRAState:
case MCCFIInstruction::OpLLVMDefAspaceCfa:
case MCCFIInstruction::OpLabel:
llvm_unreachable("unsupported CFI opcode");
return false;
case MCCFIInstruction::OpRememberState:
Expand Down Expand Up @@ -2823,6 +2825,7 @@ BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState,
case MCCFIInstruction::OpWindowSave:
case MCCFIInstruction::OpNegateRAState:
case MCCFIInstruction::OpLLVMDefAspaceCfa:
case MCCFIInstruction::OpLabel:
llvm_unreachable("unsupported CFI opcode");
break;
case MCCFIInstruction::OpGnuArgsSize:
Expand Down
18 changes: 18 additions & 0 deletions llvm/include/llvm/MC/MCDwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ class MCCFIInstruction {
OpWindowSave,
OpNegateRAState,
OpGnuArgsSize,
OpLabel,
OpLLVMRegisterPair,
OpLLVMVectorRegisters,
OpLLVMVectorOffset,
Expand Down Expand Up @@ -546,6 +547,7 @@ class MCCFIInstruction {
unsigned Register;
unsigned Register2;
} RR;
MCSymbol *CfiLabel;
} U;
OpType Operation;
SMLoc Loc;
Expand Down Expand Up @@ -586,6 +588,12 @@ class MCCFIInstruction {
U.RI = {R, O};
}

MCCFIInstruction(OpType Op, MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc)
: Label(L), Operation(Op), Loc(Loc) {
assert(Op == OpLabel);
U.CfiLabel = CfiLabel;
}

public:
/// .cfi_def_cfa defines a rule for computing CFA as: take address from
/// Register and add Offset to it.
Expand Down Expand Up @@ -706,6 +714,11 @@ class MCCFIInstruction {
return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc);
}

static MCCFIInstruction createLabel(MCSymbol *L, MCSymbol *CfiLabel,
SMLoc Loc) {
return MCCFIInstruction(OpLabel, L, CfiLabel, Loc);
}

/// .cfi_llvm_register_pair Previous value of Register is saved in R1:R2.
static MCCFIInstruction
createLLVMRegisterPair(MCSymbol *L, unsigned Register, unsigned R1,
Expand Down Expand Up @@ -783,6 +796,11 @@ class MCCFIInstruction {
return U.RI.Offset;
}

MCSymbol *getCfiLabel() const {
assert(Operation == OpLabel);
return U.CfiLabel;
}

StringRef getValues() const {
assert(Operation == OpEscape);
return StringRef(&Values[0], Values.size());
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,7 @@ class MCStreamer {
int64_t MaskRegister,
int64_t MaskRegisterSizeInBits,
int64_t Offset, SMLoc Loc = {});
virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name);

virtual void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
virtual void emitWinCFIEndProc(SMLoc Loc = SMLoc());
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CFIInstrInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpLLVMRegisterPair:
case MCCFIInstruction::OpLLVMVectorRegisters:
case MCCFIInstruction::OpLLVMVectorOffset:
case MCCFIInstruction::OpLabel:
break;
}
if (CSRReg || CSROffset) {
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ class MCAsmStreamer final : public MCStreamer {
void emitCFILLVMVectorOffset(int64_t Register, int64_t RegisterSize,
int64_t MaskRegister, int64_t MaskRegisterSize,
int64_t Offset, SMLoc Loc) override;
void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;

void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
void emitWinCFIEndProc(SMLoc Loc) override;
Expand Down Expand Up @@ -2178,6 +2179,12 @@ void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {
EmitEOL();
}

void MCAsmStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
MCStreamer::emitCFILabelDirective(Loc, Name);
OS << "\t.cfi_label " << Name;
EmitEOL();
}

void MCAsmStreamer::emitCFIBKeyFrame() {
MCStreamer::emitCFIBKeyFrame();
OS << "\t.cfi_b_key_frame";
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/MC/MCDwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,10 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
Streamer.emitBytes(Instr.getValues());
return;

case MCCFIInstruction::OpLabel:
Streamer.emitLabel(Instr.getCfiLabel(), Instr.getLoc());
return;

case MCCFIInstruction::OpLLVMRegisterPair: {
// CFI for a register spilled to a pair of SGPRs is implemented as an
// expression(E) rule where E is a composite location description with
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/MC/MCParser/AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ class AsmParser : public MCAsmParser {
DK_CFI_UNDEFINED,
DK_CFI_REGISTER,
DK_CFI_WINDOW_SAVE,
DK_CFI_LABEL,
DK_CFI_B_KEY_FRAME,
DK_MACROS_ON,
DK_MACROS_OFF,
Expand Down Expand Up @@ -628,6 +629,7 @@ class AsmParser : public MCAsmParser {
bool parseDirectiveCFILLVMRegisterPair(SMLoc DirectiveLoc);
bool parseDirectiveCFILLVMVectorRegisters(SMLoc DirectiveLoc);
bool parseDirectiveCFILLVMVectorOffset(SMLoc DirectiveLoc);
bool parseDirectiveCFILabel(SMLoc DirectiveLoc);

// macro directives
bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);
Expand Down Expand Up @@ -2236,6 +2238,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveCFIRegister(IDLoc);
case DK_CFI_WINDOW_SAVE:
return parseDirectiveCFIWindowSave(IDLoc);
case DK_CFI_LABEL:
return parseDirectiveCFILabel(IDLoc);
case DK_MACROS_ON:
case DK_MACROS_OFF:
return parseDirectiveMacrosOnOff(IDVal);
Expand Down Expand Up @@ -4545,6 +4549,19 @@ bool AsmParser::parseDirectiveCFILLVMVectorOffset(SMLoc DirectiveLoc) {
return false;
}

/// parseDirectiveCFILabel
/// ::= .cfi_label label
bool AsmParser::parseDirectiveCFILabel(SMLoc Loc) {
StringRef Name;
Loc = Lexer.getLoc();
if (parseIdentifier(Name))
return TokError("expected identifier");
if (parseEOL())
return true;
getStreamer().emitCFILabelDirective(Loc, Name);
return false;
}

/// parseDirectiveAltmacro
/// ::= .altmacro
/// ::= .noaltmacro
Expand Down Expand Up @@ -5620,6 +5637,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;
DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
DirectiveKindMap[".cfi_label"] = DK_CFI_LABEL;
DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
DirectiveKindMap[".cfi_mte_tagged_frame"] = DK_CFI_MTE_TAGGED_FRAME;
DirectiveKindMap[".macros_on"] = DK_MACROS_ON;
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,13 @@ void MCStreamer::emitCFIReturnColumn(int64_t Register) {
CurFrame->RAReg = Register;
}

void MCStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
MCSymbol *Label = emitCFILabel();
MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
if (MCDwarfFrameInfo *F = getCurrentDwarfFrameInfo())
F->Instructions.push_back(MCCFIInstruction::createLabel(Label, Sym, Loc));
}

WinEH::FrameInfo *MCStreamer::EnsureValidWinFrameInfo(SMLoc Loc) {
const MCAsmInfo *MAI = Context.getAsmInfo();
if (!MAI->usesWindowsCFI()) {
Expand Down
1 change: 0 additions & 1 deletion llvm/test/MC/ELF/cfi-label.s
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# XFAIL: *
# RUN: llvm-mc -triple x86_64 %s | FileCheck %s --check-prefix=ASM
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
# RUN: llvm-readelf -sX %t | FileCheck %s --check-prefix=SYMTAB
Expand Down
4 changes: 0 additions & 4 deletions revert_patches.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,3 @@ Revert: breaking MIOpen test 2
f8b1ca4992a2 [MCParser] .altmacro: Support argument expansion not preceded by
812f9e81d2f7 [MCParser] .altmacro: ignore & after a token
---
revert: needs downstream merging from Emma
9abb574f9a68 [MC] Make MCCFIInstruction smaller
2718654c542c [MC] Support .cfi_label
---

0 comments on commit 48f05fd

Please sign in to comment.