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
2122namespace {
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
2675class 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
85147void 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.
0 commit comments