Skip to content

Commit 8018359

Browse files
[SFrames] reland Emit and relax FREs #158154
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 6523258 commit 8018359

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)