Skip to content

Commit 3888595

Browse files
[SFrames] Add FDEs for functions with .cfi_startproc (#154213)
This continues the sframe implementation. This change tracks and fills out the necessary fields for FDEs, but doesn't create or add FREs.
1 parent efa99ec commit 3888595

File tree

2 files changed

+130
-7
lines changed

2 files changed

+130
-7
lines changed

llvm/lib/MC/MCSFrame.cpp

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "llvm/MC/MCSFrame.h"
1010
#include "llvm/BinaryFormat/SFrame.h"
11+
#include "llvm/MC/MCAsmInfo.h"
1112
#include "llvm/MC/MCContext.h"
1213
#include "llvm/MC/MCObjectFileInfo.h"
1314
#include "llvm/MC/MCObjectStreamer.h"
@@ -20,11 +21,60 @@ using namespace sframe;
2021

2122
namespace {
2223

24+
// High-level structure to track info needed to emit a sframe_func_desc_entry
25+
// and its associated FREs.
26+
struct SFrameFDE {
27+
// Reference to the original dwarf frame to avoid copying.
28+
const MCDwarfFrameInfo &DFrame;
29+
// Label where this FDE's FREs start.
30+
MCSymbol *FREStart;
31+
32+
SFrameFDE(const MCDwarfFrameInfo &DF, MCSymbol *FRES)
33+
: DFrame(DF), FREStart(FRES) {}
34+
35+
void emit(MCObjectStreamer &S, const MCSymbol *FRESubSectionStart) {
36+
MCContext &C = S.getContext();
37+
38+
// sfde_func_start_address
39+
const MCExpr *V = C.getAsmInfo()->getExprForFDESymbol(
40+
&(*DFrame.Begin), C.getObjectFileInfo()->getFDEEncoding(), S);
41+
S.emitValue(V, sizeof(int32_t));
42+
43+
// sfde_func_size
44+
S.emitAbsoluteSymbolDiff(DFrame.End, DFrame.Begin, sizeof(uint32_t));
45+
46+
// sfde_func_start_fre_off
47+
auto *F = S.getCurrentFragment();
48+
const MCExpr *Diff = MCBinaryExpr::createSub(
49+
MCSymbolRefExpr::create(FREStart, C),
50+
MCSymbolRefExpr::create(FRESubSectionStart, C), C);
51+
52+
F->addFixup(MCFixup::create(F->getContents().size(), Diff,
53+
MCFixup::getDataKindForSize(4)));
54+
S.emitInt32(0);
55+
56+
// sfde_func_start_num_fres
57+
S.emitInt32(0);
58+
59+
// sfde_func_info word
60+
FDEInfo<endianness::native> I;
61+
I.setFuncInfo(0 /* No pauth key */, FDEType::PCInc, FREType::Addr1);
62+
S.emitInt8(I.Info);
63+
64+
// sfde_func_rep_size. Not relevant in non-PCMASK fdes.
65+
S.emitInt8(0);
66+
67+
// sfde_func_padding2
68+
S.emitInt16(0);
69+
}
70+
};
71+
2372
// Emitting these field-by-field, instead of constructing the actual structures
2473
// lets Streamer do target endian-fixups for free.
2574

2675
class SFrameEmitterImpl {
2776
MCObjectStreamer &Streamer;
77+
SmallVector<SFrameFDE> FDEs;
2878
ABI SFrameABI;
2979
MCSymbol *FDESubSectionStart;
3080
MCSymbol *FRESubSectionStart;
@@ -36,16 +86,21 @@ class SFrameEmitterImpl {
3686
.getObjectFileInfo()
3787
->getSFrameABIArch()
3888
.has_value());
89+
FDEs.reserve(Streamer.getDwarfFrameInfos().size());
3990
SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch();
4091
FDESubSectionStart = Streamer.getContext().createTempSymbol();
4192
FRESubSectionStart = Streamer.getContext().createTempSymbol();
4293
FRESubSectionEnd = Streamer.getContext().createTempSymbol();
4394
}
4495

96+
void BuildSFDE(const MCDwarfFrameInfo &DF) {
97+
FDEs.emplace_back(DF, Streamer.getContext().createTempSymbol());
98+
}
99+
45100
void emitPreamble() {
46101
Streamer.emitInt16(Magic);
47102
Streamer.emitInt8(static_cast<uint8_t>(Version::V2));
48-
Streamer.emitInt8(0);
103+
Streamer.emitInt8(static_cast<uint8_t>(Flags::FDEFuncStartPCRel));
49104
}
50105

51106
void emitHeader() {
@@ -59,7 +114,7 @@ class SFrameEmitterImpl {
59114
// sfh_auxhdr_len
60115
Streamer.emitInt8(0);
61116
// shf_num_fdes
62-
Streamer.emitInt32(0);
117+
Streamer.emitInt32(FDEs.size());
63118
// shf_num_fres
64119
Streamer.emitInt32(0);
65120
// shf_fre_len
@@ -72,10 +127,17 @@ class SFrameEmitterImpl {
72127
sizeof(uint32_t));
73128
}
74129

75-
void emitFDEs() { Streamer.emitLabel(FDESubSectionStart); }
130+
void emitFDEs() {
131+
Streamer.emitLabel(FDESubSectionStart);
132+
for (auto &FDE : FDEs) {
133+
FDE.emit(Streamer, FRESubSectionStart);
134+
}
135+
}
76136

77137
void emitFREs() {
78138
Streamer.emitLabel(FRESubSectionStart);
139+
for (auto &FDE : FDEs)
140+
Streamer.emitLabel(FDE.FREStart);
79141
Streamer.emitLabel(FRESubSectionEnd);
80142
}
81143
};
@@ -84,7 +146,22 @@ class SFrameEmitterImpl {
84146

85147
void MCSFrameEmitter::emit(MCObjectStreamer &Streamer) {
86148
MCContext &Context = Streamer.getContext();
149+
// If this target doesn't support sframes, return now. Gas doesn't warn in
150+
// this case, but if we want to, it should be done at option-parsing time,
151+
// rather than here.
152+
if (!Streamer.getContext()
153+
.getObjectFileInfo()
154+
->getSFrameABIArch()
155+
.has_value())
156+
return;
157+
87158
SFrameEmitterImpl Emitter(Streamer);
159+
ArrayRef<MCDwarfFrameInfo> FrameArray = Streamer.getDwarfFrameInfos();
160+
161+
// Both the header itself and the FDEs include various offsets and counts.
162+
// Therefore, all of this must be precomputed.
163+
for (const auto &DFrame : FrameArray)
164+
Emitter.BuildSFDE(DFrame);
88165

89166
MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();
90167
// Not strictly necessary, but gas always aligns to 8, so match that.

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

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,69 @@
44
// RUN: llvm-readelf --sframe %t.o | FileCheck %s
55

66
.cfi_sections .sframe
7-
87
f1:
98
.cfi_startproc
109
nop
1110
.cfi_endproc
1211

12+
f2:
13+
.cfi_startproc
14+
nop
15+
nop
16+
.cfi_endproc
17+
1318
// CHECK: SFrame section '.sframe' {
1419
// CHECK-NEXT: Header {
1520
// CHECK-NEXT: Magic: 0xDEE2
1621
// CHECK-NEXT: Version: V2 (0x2)
17-
// CHECK-NEXT: Flags [ (0x0)
22+
// CHECK-NEXT: Flags [ (0x4)
1823
// CHECK: ABI: AMD64EndianLittle (0x3)
1924
// CHECK-NEXT: CFA fixed FP offset (unused): 0
2025
// CHECK-NEXT: CFA fixed RA offset: 0
2126
// CHECK-NEXT: Auxiliary header length: 0
22-
// CHECK-NEXT: Num FDEs: 0
27+
// CHECK-NEXT: Num FDEs: 2
2328
// CHECK-NEXT: Num FREs: 0
2429
// CHECK-NEXT: FRE subsection length: 0
2530
// CHECK-NEXT: FDE subsection offset: 0
26-
// CHECK-NEXT: FRE subsection offset: 0
31+
// CHECK-NEXT: FRE subsection offset: 40
32+
// CHECK: Function Index [
33+
// CHECK-NEXT: FuncDescEntry [0] {
34+
// CHECK-NEXT: PC {
35+
// CHECK-NEXT: Relocation: {{.*}}32{{.*}}
36+
// CHECK-NEXT: Symbol Name: .text
37+
// CHECK-NEXT: Start Address: 0x0
38+
// CHECK-NEXT: }
39+
// CHECK-NEXT: Size: 0x1
40+
// CHECK-NEXT: Start FRE Offset: 0x0
41+
// CHECK-NEXT: Num FREs: 0
42+
// CHECK-NEXT: Info {
43+
// CHECK-NEXT: FRE Type: Addr1 (0x0)
44+
// CHECK-NEXT: FDE Type: PCInc (0x0)
45+
// CHECK-NEXT: Raw: 0x0
46+
// CHECK-NEXT: }
47+
// CHECK-NEXT: Repetitive block size (unused): 0x0
48+
// CHECK-NEXT: Padding2: 0x0
49+
// CHECK-NEXT: FREs [
50+
// CHECK-NEXT: ]
51+
// CHECK-NEXT: }
52+
// CHECK-NEXT: FuncDescEntry [1] {
53+
// CHECK-NEXT: PC {
54+
// CHECK-NEXT: Relocation: R_X86_64_PC32
55+
// CHECK-NEXT: Symbol Name: .text
56+
// CHECK-NEXT: Start Address: {{.*}}
57+
// CHECK-NEXT: }
58+
// CHECK-NEXT: Size: 0x2
59+
// CHECK-NEXT: Start FRE Offset: 0x0
60+
// CHECK-NEXT: Num FREs: 0
61+
// CHECK-NEXT: Info {
62+
// CHECK-NEXT: FRE Type: Addr1 (0x0)
63+
// CHECK-NEXT: FDE Type: PCInc (0x0)
64+
// CHECK-NEXT: Raw: 0x0
65+
// CHECK-NEXT: }
66+
// CHECK-NEXT: Repetitive block size (unused): 0x0
67+
// CHECK-NEXT: Padding2: 0x0
68+
// CHECK-NEXT: FREs [
69+
// CHECK-NEXT: ]
70+
// CHECK-NEXT: }
71+
// CHECK-NEXT: ]
72+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)