Skip to content

Commit 714f032

Browse files
[SFrames] reland Emit and relax FREs #158154 (#159643)
[Previously reverted due to msan failures on two uninitialized padding bits.] This PR emits and relaxes the FREs generated in the previous PR. After this change llvm emits usable sframe sections that can be linked with the gnu linker. There are a few remaining cfi directives to handle before they are generally usable, however. The output isn't identical with gnu-gas in every case (this code produces fewer identical FREs in a row than gas), but I'm reasonably sure that they are correct regardless. There are even more size optimizations that can be done later. Also, while working on the tests, I found a few bugs in older portions and cleaned those up. This is a fairly big commit, but I'm not sure how to make it smaller.
1 parent 5a402ac commit 714f032

File tree

13 files changed

+512
-85
lines changed

13 files changed

+512
-85
lines changed

llvm/include/llvm/BinaryFormat/SFrame.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ template <endianness E> struct FDEInfo {
117117
Info = ((PAuthKey & 1) << 5) | ((static_cast<uint8_t>(FDE) & 1) << 4) |
118118
(static_cast<uint8_t>(FRE) & 0xf);
119119
}
120+
uint8_t getFuncInfo() const { return Info; }
120121
};
121122

122123
template <endianness E> struct FuncDescEntry {
@@ -155,6 +156,7 @@ template <endianness E> struct FREInfo {
155156
Info = ((RA & 1) << 7) | ((static_cast<uint8_t>(Sz) & 3) << 5) |
156157
((N & 0xf) << 1) | (static_cast<uint8_t>(Reg) & 1);
157158
}
159+
uint8_t getFREInfo() const { return Info; }
158160
};
159161

160162
template <typename T, endianness E> struct FrameRowEntry {

llvm/include/llvm/MC/MCAsmBackend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ class LLVM_ABI MCAsmBackend {
168168
virtual bool relaxAlign(MCFragment &F, unsigned &Size) { return false; }
169169
virtual bool relaxDwarfLineAddr(MCFragment &) const { return false; }
170170
virtual bool relaxDwarfCFA(MCFragment &) const { return false; }
171+
virtual bool relaxSFrameCFA(MCFragment &) const { return false; }
171172

172173
// Defined by linker relaxation targets to possibly emit LEB128 relocations
173174
// and set Value at the relocated location.

llvm/include/llvm/MC/MCAssembler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class MCAssembler {
117117
void relaxBoundaryAlign(MCBoundaryAlignFragment &BF);
118118
void relaxDwarfLineAddr(MCFragment &F);
119119
void relaxDwarfCallFrameFragment(MCFragment &F);
120+
void relaxSFrameFragment(MCFragment &DF);
120121

121122
public:
122123
/// Construct a new assembler instance.

llvm/include/llvm/MC/MCObjectStreamer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ class MCObjectStreamer : public MCStreamer {
150150
MCSymbol *EndLabel = nullptr) override;
151151
void emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
152152
const MCSymbol *Label, SMLoc Loc);
153+
void emitSFrameCalculateFuncOffset(const MCSymbol *FunCabsel,
154+
const MCSymbol *FREBegin,
155+
MCFragment *FDEFrag, SMLoc Loc);
153156
void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
154157
unsigned Column, bool PrologueEnd, bool IsStmt,
155158
StringRef FileName, SMLoc Loc) override;

llvm/include/llvm/MC/MCSFrame.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,30 @@
1616
#ifndef LLVM_MC_MCSFRAME_H
1717
#define LLVM_MC_MCSFRAME_H
1818

19+
#include "llvm/ADT/SmallVector.h"
20+
#include <cstdint>
21+
1922
namespace llvm {
2023

24+
class MCContext;
2125
class MCObjectStreamer;
26+
class MCFragment;
2227

2328
class MCSFrameEmitter {
2429
public:
2530
// Emit the sframe section.
2631
//
2732
// \param Streamer - Emit into this stream.
2833
static void emit(MCObjectStreamer &Streamer);
34+
35+
// Encode the FRE's function offset.
36+
//
37+
// \param C - Context.
38+
// \param Offset - Offset to encode.
39+
// \param Out - Destination of the encoding.
40+
// \param FDEFrag - Frag that specifies the encoding format.
41+
static void encodeFuncOffset(MCContext &C, uint64_t Offset,
42+
SmallVectorImpl<char> &Out, MCFragment *FDEFrag);
2943
};
3044

3145
} // end namespace llvm

llvm/include/llvm/MC/MCSection.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class MCFragment {
5959
FT_Org,
6060
FT_Dwarf,
6161
FT_DwarfFrame,
62+
FT_SFrame,
6263
FT_BoundaryAlign,
6364
FT_SymbolId,
6465
FT_CVInlineLines,
@@ -143,6 +144,12 @@ class MCFragment {
143144
// .loc dwarf directives.
144145
int64_t LineDelta;
145146
} dwarf;
147+
struct {
148+
// This FRE describes unwind info at AddrDelta from function start.
149+
const MCExpr *AddrDelta;
150+
// Fragment that records how many bytes of AddrDelta to emit.
151+
MCFragment *FDEFragment;
152+
} sframe;
146153
} u{};
147154

148155
public:
@@ -296,6 +303,24 @@ class MCFragment {
296303
assert(Kind == FT_Dwarf);
297304
u.dwarf.LineDelta = LineDelta;
298305
}
306+
307+
//== FT_SFrame functions
308+
const MCExpr &getSFrameAddrDelta() const {
309+
assert(Kind == FT_SFrame);
310+
return *u.sframe.AddrDelta;
311+
}
312+
void setSFrameAddrDelta(const MCExpr *E) {
313+
assert(Kind == FT_SFrame);
314+
u.sframe.AddrDelta = E;
315+
}
316+
MCFragment *getSFrameFDE() const {
317+
assert(Kind == FT_SFrame);
318+
return u.sframe.FDEFragment;
319+
}
320+
void setSFrameFDE(MCFragment *F) {
321+
assert(Kind == FT_SFrame);
322+
u.sframe.FDEFragment = F;
323+
}
299324
};
300325

301326
// MCFragment subclasses do not use the fixed-size part or variable-size tail of

llvm/lib/MC/MCAssembler.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/MC/MCFixup.h"
2323
#include "llvm/MC/MCInst.h"
2424
#include "llvm/MC/MCObjectWriter.h"
25+
#include "llvm/MC/MCSFrame.h"
2526
#include "llvm/MC/MCSection.h"
2627
#include "llvm/MC/MCSymbol.h"
2728
#include "llvm/MC/MCValue.h"
@@ -199,6 +200,7 @@ uint64_t MCAssembler::computeFragmentSize(const MCFragment &F) const {
199200
case MCFragment::FT_LEB:
200201
case MCFragment::FT_Dwarf:
201202
case MCFragment::FT_DwarfFrame:
203+
case MCFragment::FT_SFrame:
202204
case MCFragment::FT_CVInlineLines:
203205
case MCFragment::FT_CVDefRange:
204206
return F.getSize();
@@ -399,6 +401,7 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
399401
case MCFragment::FT_LEB:
400402
case MCFragment::FT_Dwarf:
401403
case MCFragment::FT_DwarfFrame:
404+
case MCFragment::FT_SFrame:
402405
case MCFragment::FT_CVInlineLines:
403406
case MCFragment::FT_CVDefRange: {
404407
if (F.getKind() == MCFragment::FT_Data)
@@ -914,6 +917,24 @@ void MCAssembler::relaxDwarfCallFrameFragment(MCFragment &F) {
914917
F.clearVarFixups();
915918
}
916919

920+
void MCAssembler::relaxSFrameFragment(MCFragment &F) {
921+
assert(F.getKind() == MCFragment::FT_SFrame);
922+
MCContext &C = getContext();
923+
int64_t Value;
924+
bool Abs = F.getSFrameAddrDelta().evaluateAsAbsolute(Value, *this);
925+
if (!Abs) {
926+
C.reportError(F.getSFrameAddrDelta().getLoc(),
927+
"invalid CFI advance_loc expression in sframe");
928+
F.setSFrameAddrDelta(MCConstantExpr::create(0, C));
929+
return;
930+
}
931+
932+
SmallVector<char, 4> Data;
933+
MCSFrameEmitter::encodeFuncOffset(Context, Value, Data, F.getSFrameFDE());
934+
F.setVarContents(Data);
935+
F.clearVarFixups();
936+
}
937+
917938
bool MCAssembler::relaxFragment(MCFragment &F) {
918939
auto Size = computeFragmentSize(F);
919940
switch (F.getKind()) {
@@ -932,6 +953,9 @@ bool MCAssembler::relaxFragment(MCFragment &F) {
932953
case MCFragment::FT_DwarfFrame:
933954
relaxDwarfCallFrameFragment(F);
934955
break;
956+
case MCFragment::FT_SFrame:
957+
relaxSFrameFragment(F);
958+
break;
935959
case MCFragment::FT_BoundaryAlign:
936960
relaxBoundaryAlign(static_cast<MCBoundaryAlignFragment &>(F));
937961
break;

llvm/lib/MC/MCFragment.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
5353
case MCFragment::FT_Org: OS << "Org"; break;
5454
case MCFragment::FT_Dwarf: OS << "Dwarf"; break;
5555
case MCFragment::FT_DwarfFrame: OS << "DwarfCallFrame"; break;
56+
case MCFragment::FT_SFrame: OS << "SFrame"; break;
5657
case MCFragment::FT_LEB: OS << "LEB"; break;
5758
case MCFragment::FT_BoundaryAlign: OS<<"BoundaryAlign"; break;
5859
case MCFragment::FT_SymbolId: OS << "SymbolId"; break;
@@ -79,7 +80,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
7980
case MCFragment::FT_Align:
8081
case MCFragment::FT_LEB:
8182
case MCFragment::FT_Dwarf:
82-
case MCFragment::FT_DwarfFrame: {
83+
case MCFragment::FT_DwarfFrame:
84+
case MCFragment::FT_SFrame: {
8385
if (isLinkerRelaxable())
8486
OS << " LinkerRelaxable";
8587
auto Fixed = getContents();
@@ -129,6 +131,7 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
129131
OS << " LineDelta:" << getDwarfLineDelta();
130132
break;
131133
case MCFragment::FT_DwarfFrame:
134+
case MCFragment::FT_SFrame:
132135
OS << " AddrDelta:";
133136
getDwarfAddrDelta().print(OS, nullptr);
134137
break;

llvm/lib/MC/MCObjectStreamer.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,19 @@ void MCObjectStreamer::emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
583583
newFragment();
584584
}
585585

586+
void MCObjectStreamer::emitSFrameCalculateFuncOffset(const MCSymbol *FuncBase,
587+
const MCSymbol *FREBegin,
588+
MCFragment *FDEFrag,
589+
SMLoc Loc) {
590+
assert(FuncBase && "No function base address");
591+
assert(FREBegin && "FRE doesn't describe a location");
592+
auto *F = getCurrentFragment();
593+
F->Kind = MCFragment::FT_SFrame;
594+
F->setSFrameAddrDelta(buildSymbolDiff(*this, FREBegin, FuncBase, Loc));
595+
F->setSFrameFDE(FDEFrag);
596+
newFragment();
597+
}
598+
586599
void MCObjectStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,
587600
unsigned Line, unsigned Column,
588601
bool PrologueEnd, bool IsStmt,

0 commit comments

Comments
 (0)