Skip to content

Commit f1aa605

Browse files
committed
MCFragment: Use trailing data for fixed-size part
Reapply after #151724 switched to `char *Data`, fixing a -fsanitize=pointer-overflow issue in MCAssembler::layout. --- The fixed-size content of the MCFragment object is now stored as trailing data, replacing ContentStart/ContentEnd with ContentSize. The available space for trailing data is tracked using `FragSpace`. If the available space is insufficient, a new block is allocated within the bump allocator `MCObjectStreamer::FragStorage`. FragList::Tail cannot be reused when switching sections or subsections, as it is not associated with the fragment space tracked by `FragSpace`. Instead, allocate a new fragment, which becomes less expensive after #150574. Data can only be appended to the tail fragment of a subsection, not to fragments in the middle. Post-assembler-layout adjustments (such as .llvm_addrsig and .llvm.call-graph-profile) have been updated to use the variable-size part instead. Pull Request: #150846
1 parent 9d7a233 commit f1aa605

File tree

7 files changed

+144
-59
lines changed

7 files changed

+144
-59
lines changed

llvm/include/llvm/MC/MCObjectStreamer.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ class MCObjectStreamer : public MCStreamer {
5252
DenseMap<const MCSymbol *, SmallVector<PendingAssignment, 1>>
5353
pendingAssignments;
5454

55+
SmallVector<std::unique_ptr<uint8_t[]>, 0> FragStorage;
56+
// Available bytes in the current block for trailing data or new fragments.
57+
size_t FragSpace = 0;
58+
5559
void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &);
5660
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
5761
void emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
@@ -84,11 +88,18 @@ class MCObjectStreamer : public MCStreamer {
8488
// Add a fragment with a variable-size tail and start a new empty fragment.
8589
void insert(MCFragment *F);
8690

91+
uint8_t *getCurFragEnd() const {
92+
return reinterpret_cast<uint8_t *>(CurFrag + 1) + CurFrag->getFixedSize();
93+
}
94+
MCFragment *allocFragSpace(size_t Headroom);
8795
// Add a new fragment to the current section without a variable-size tail.
8896
void newFragment();
8997

98+
void ensureHeadroom(size_t Headroom);
9099
void appendContents(ArrayRef<char> Contents);
91-
void appendContents(size_t Num, char Elt);
100+
void appendContents(size_t Num, uint8_t Elt);
101+
// Add a fixup to the current fragment. Call ensureHeadroom beforehand to
102+
// ensure the fixup and appended content apply to the same fragment.
92103
void addFixup(const MCExpr *Value, MCFixupKind Kind);
93104

94105
void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;

llvm/include/llvm/MC/MCSection.h

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@ class MCFragment {
9191
bool AllowAutoPadding : 1;
9292

9393
// Track content and fixups for the fixed-size part as fragments are
94-
// appended to the section. The content remains immutable, except when
95-
// modified by applyFixup.
96-
uint32_t ContentStart = 0;
97-
uint32_t ContentEnd = 0;
94+
// appended to the section. The content is stored as trailing data of the
95+
// MCFragment. The content remains immutable, except when modified by
96+
// applyFixup.
97+
uint32_t FixedSize = 0;
9898
uint32_t FixupStart = 0;
9999
uint32_t FixupEnd = 0;
100100

@@ -188,18 +188,6 @@ class MCFragment {
188188
//== Content-related functions manage parent's storage using ContentStart and
189189
// ContentSize.
190190

191-
// Get a SmallVector reference. The caller should call doneAppending to update
192-
// `ContentEnd`.
193-
SmallVectorImpl<char> &getContentsForAppending();
194-
void doneAppending();
195-
void appendContents(ArrayRef<char> Contents) {
196-
getContentsForAppending().append(Contents.begin(), Contents.end());
197-
doneAppending();
198-
}
199-
void appendContents(size_t Num, char Elt) {
200-
getContentsForAppending().append(Num, Elt);
201-
doneAppending();
202-
}
203191
MutableArrayRef<char> getContents();
204192
ArrayRef<char> getContents() const;
205193

@@ -208,10 +196,10 @@ class MCFragment {
208196
MutableArrayRef<char> getVarContents();
209197
ArrayRef<char> getVarContents() const;
210198

211-
size_t getFixedSize() const { return ContentEnd - ContentStart; }
199+
size_t getFixedSize() const { return FixedSize; }
212200
size_t getVarSize() const { return VarContentEnd - VarContentStart; }
213201
size_t getSize() const {
214-
return ContentEnd - ContentStart + (VarContentEnd - VarContentStart);
202+
return FixedSize + (VarContentEnd - VarContentStart);
215203
}
216204

217205
//== Fixup-related functions manage parent's storage using FixupStart and
@@ -626,28 +614,11 @@ class LLVM_ABI MCSection {
626614
bool isBssSection() const { return IsBss; }
627615
};
628616

629-
inline SmallVectorImpl<char> &MCFragment::getContentsForAppending() {
630-
SmallVectorImpl<char> &S = getParent()->ContentStorage;
631-
if (LLVM_UNLIKELY(ContentEnd != S.size())) {
632-
// Move the elements to the end. Reserve space to avoid invalidating
633-
// S.begin()+I for `append`.
634-
auto Size = ContentEnd - ContentStart;
635-
auto I = std::exchange(ContentStart, S.size());
636-
S.reserve(S.size() + Size);
637-
S.append(S.begin() + I, S.begin() + I + Size);
638-
}
639-
return S;
640-
}
641-
inline void MCFragment::doneAppending() {
642-
ContentEnd = getParent()->ContentStorage.size();
643-
}
644617
inline MutableArrayRef<char> MCFragment::getContents() {
645-
return MutableArrayRef(getParent()->ContentStorage)
646-
.slice(ContentStart, ContentEnd - ContentStart);
618+
return {reinterpret_cast<char *>(this + 1), FixedSize};
647619
}
648620
inline ArrayRef<char> MCFragment::getContents() const {
649-
return ArrayRef(getParent()->ContentStorage)
650-
.slice(ContentStart, ContentEnd - ContentStart);
621+
return {reinterpret_cast<const char *>(this + 1), FixedSize};
651622
}
652623

653624
inline MutableArrayRef<char> MCFragment::getVarContents() {

llvm/lib/MC/MCObjectStreamer.cpp

Lines changed: 100 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,27 +46,83 @@ MCAssembler *MCObjectStreamer::getAssemblerPtr() {
4646
return nullptr;
4747
}
4848

49+
constexpr size_t FragBlockSize = 16384;
50+
// Ensure the new fragment can at least store a few bytes.
51+
constexpr size_t NewFragHeadroom = 8;
52+
53+
static_assert(NewFragHeadroom >= alignof(MCFragment));
54+
static_assert(FragBlockSize >= sizeof(MCFragment) + NewFragHeadroom);
55+
56+
MCFragment *MCObjectStreamer::allocFragSpace(size_t Headroom) {
57+
auto Size = std::max(FragBlockSize, sizeof(MCFragment) + Headroom);
58+
FragSpace = Size - sizeof(MCFragment);
59+
auto Block = std::unique_ptr<uint8_t[]>(new uint8_t[Size]);
60+
auto *F = reinterpret_cast<MCFragment *>(Block.get());
61+
FragStorage.push_back(std::move(Block));
62+
return F;
63+
}
64+
4965
void MCObjectStreamer::newFragment() {
50-
addFragment(getContext().allocFragment<MCFragment>());
66+
MCFragment *F;
67+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
68+
auto End = reinterpret_cast<size_t>(getCurFragEnd());
69+
F = reinterpret_cast<MCFragment *>(
70+
alignToPowerOf2(End, alignof(MCFragment)));
71+
FragSpace -= size_t(F) - End + sizeof(MCFragment);
72+
} else {
73+
F = allocFragSpace(0);
74+
}
75+
new (F) MCFragment();
76+
addFragment(F);
77+
}
78+
79+
void MCObjectStreamer::ensureHeadroom(size_t Headroom) {
80+
if (Headroom <= FragSpace)
81+
return;
82+
auto *F = allocFragSpace(Headroom);
83+
new (F) MCFragment();
84+
addFragment(F);
5185
}
5286

53-
void MCObjectStreamer::insert(MCFragment *F) {
54-
assert(F->getKind() != MCFragment::FT_Data &&
87+
void MCObjectStreamer::insert(MCFragment *Frag) {
88+
assert(Frag->getKind() != MCFragment::FT_Data &&
5589
"F should have a variable-size tail");
90+
// Frag is not connected to FragSpace. Before modifying CurFrag with
91+
// addFragment(Frag), allocate an empty fragment to maintain FragSpace
92+
// connectivity, potentially reusing CurFrag's associated space.
93+
MCFragment *F;
94+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
95+
auto End = reinterpret_cast<size_t>(getCurFragEnd());
96+
F = reinterpret_cast<MCFragment *>(
97+
alignToPowerOf2(End, alignof(MCFragment)));
98+
FragSpace -= size_t(F) - End + sizeof(MCFragment);
99+
} else {
100+
F = allocFragSpace(0);
101+
}
102+
new (F) MCFragment();
103+
104+
addFragment(Frag);
56105
addFragment(F);
57-
newFragment();
58106
}
59107

60108
void MCObjectStreamer::appendContents(ArrayRef<char> Contents) {
61-
CurFrag->appendContents(Contents);
109+
ensureHeadroom(Contents.size());
110+
assert(FragSpace >= Contents.size());
111+
llvm::copy(Contents, getCurFragEnd());
112+
CurFrag->FixedSize += Contents.size();
113+
FragSpace -= Contents.size();
62114
}
63115

64-
void MCObjectStreamer::appendContents(size_t Num, char Elt) {
65-
CurFrag->appendContents(Num, Elt);
116+
void MCObjectStreamer::appendContents(size_t Num, uint8_t Elt) {
117+
ensureHeadroom(Num);
118+
MutableArrayRef<uint8_t> Data(getCurFragEnd(), Num);
119+
llvm::fill(Data, Elt);
120+
CurFrag->FixedSize += Num;
121+
FragSpace -= Num;
66122
}
67123

68124
void MCObjectStreamer::addFixup(const MCExpr *Value, MCFixupKind Kind) {
69-
CurFrag->addFixup(MCFixup::create(CurFrag->getFixedSize(), Value, Kind));
125+
CurFrag->addFixup(MCFixup::create(getCurFragSize(), Value, Kind));
70126
}
71127

72128
// As a compile-time optimization, avoid allocating and evaluating an MCExpr
@@ -115,6 +171,8 @@ void MCObjectStreamer::reset() {
115171
}
116172
EmitEHFrame = true;
117173
EmitDebugFrame = false;
174+
FragStorage.clear();
175+
FragSpace = 0;
118176
MCStreamer::reset();
119177
}
120178

@@ -143,7 +201,6 @@ void MCObjectStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {
143201
void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
144202
SMLoc Loc) {
145203
MCStreamer::emitValueImpl(Value, Size, Loc);
146-
MCFragment *DF = getCurrentFragment();
147204

148205
MCDwarfLineEntry::make(this, getCurrentSectionOnly());
149206

@@ -158,9 +215,9 @@ void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
158215
emitIntValue(AbsValue, Size);
159216
return;
160217
}
161-
DF->addFixup(MCFixup::create(DF->getContents().size(), Value,
162-
MCFixup::getDataKindForSize(Size)));
163-
DF->appendContents(Size, 0);
218+
ensureHeadroom(Size);
219+
addFixup(Value, MCFixup::getDataKindForSize(Size));
220+
appendContents(Size, 0);
164221
}
165222

166223
MCSymbol *MCObjectStreamer::emitCFILabel() {
@@ -194,7 +251,7 @@ void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
194251
// section.
195252
MCFragment *F = CurFrag;
196253
Symbol->setFragment(F);
197-
Symbol->setOffset(F->getContents().size());
254+
Symbol->setOffset(F->getFixedSize());
198255

199256
emitPendingAssignments(Symbol);
200257
}
@@ -260,20 +317,38 @@ void MCObjectStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
260317
F0 = CurFrag;
261318
}
262319

320+
// To maintain connectivity between CurFrag and FragSpace when CurFrag is
321+
// modified, allocate an empty fragment and append it to the fragment list.
322+
// (Subsections[I].second.Tail is not connected to FragSpace.)
323+
MCFragment *F;
324+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
325+
auto End = reinterpret_cast<size_t>(getCurFragEnd());
326+
F = reinterpret_cast<MCFragment *>(
327+
alignToPowerOf2(End, alignof(MCFragment)));
328+
FragSpace -= size_t(F) - End + sizeof(MCFragment);
329+
} else {
330+
F = allocFragSpace(0);
331+
}
332+
new (F) MCFragment();
333+
F->setParent(Section);
334+
263335
auto &Subsections = Section->Subsections;
264336
size_t I = 0, E = Subsections.size();
265337
while (I != E && Subsections[I].first < Subsection)
266338
++I;
267339
// If the subsection number is not in the sorted Subsections list, create a
268340
// new fragment list.
269341
if (I == E || Subsections[I].first != Subsection) {
270-
auto *F = getContext().allocFragment<MCFragment>();
271-
F->setParent(Section);
272342
Subsections.insert(Subsections.begin() + I,
273343
{Subsection, MCSection::FragList{F, F}});
344+
Section->CurFragList = &Subsections[I].second;
345+
CurFrag = F;
346+
} else {
347+
Section->CurFragList = &Subsections[I].second;
348+
CurFrag = Subsections[I].second.Tail;
349+
// Ensure CurFrag is associated with FragSpace.
350+
addFragment(F);
274351
}
275-
Section->CurFragList = &Subsections[I].second;
276-
CurFrag = Section->CurFragList->Tail;
277352

278353
// Define the section symbol at subsection 0's initial fragment if required.
279354
if (!NewSec)
@@ -344,11 +419,15 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
344419
MCFragment *F = getCurrentFragment();
345420

346421
// Append the instruction to the data fragment.
347-
size_t CodeOffset = F->getContents().size();
422+
size_t CodeOffset = getCurFragSize();
423+
SmallString<16> Content;
348424
SmallVector<MCFixup, 1> Fixups;
349-
getAssembler().getEmitter().encodeInstruction(
350-
Inst, F->getContentsForAppending(), Fixups, STI);
351-
F->doneAppending();
425+
getAssembler().getEmitter().encodeInstruction(Inst, Content, Fixups, STI);
426+
appendContents(Content);
427+
if (CurFrag != F) {
428+
F = CurFrag;
429+
CodeOffset = 0;
430+
}
352431
F->setHasInstructions(STI);
353432

354433
if (Fixups.empty())

llvm/lib/MC/MCWin64EH.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
318318

319319
// Emit the epilog instructions.
320320
if (EnableUnwindV2) {
321+
// Ensure the fixups and appended content apply to the same fragment.
322+
OS->ensureHeadroom(info->EpilogMap.size() * 2);
323+
321324
bool IsLast = true;
322325
for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
323326
if (IsLast) {

llvm/lib/MC/MCWinCOFFStreamer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ void MCWinCOFFStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
280280
void MCWinCOFFStreamer::emitCOFFSectionIndex(const MCSymbol *Symbol) {
281281
visitUsedSymbol(*Symbol);
282282
const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
283+
ensureHeadroom(2);
283284
addFixup(SRE, FK_SecRel_2);
284285
appendContents(2, 0);
285286
}
@@ -293,6 +294,7 @@ void MCWinCOFFStreamer::emitCOFFSecRel32(const MCSymbol *Symbol,
293294
if (Offset)
294295
MCE = MCBinaryExpr::createAdd(
295296
MCE, MCConstantExpr::create(Offset, getContext()), getContext());
297+
ensureHeadroom(4);
296298
addFixup(MCE, FK_SecRel_4);
297299
// Emit 4 bytes (zeros) to the object file.
298300
appendContents(4, 0);
@@ -308,6 +310,7 @@ void MCWinCOFFStreamer::emitCOFFImgRel32(const MCSymbol *Symbol,
308310
if (Offset)
309311
MCE = MCBinaryExpr::createAdd(
310312
MCE, MCConstantExpr::create(Offset, getContext()), getContext());
313+
ensureHeadroom(4);
311314
addFixup(MCE, FK_Data_4);
312315
// Emit 4 bytes (zeros) to the object file.
313316
appendContents(4, 0);
@@ -318,6 +321,7 @@ void MCWinCOFFStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {
318321
// Create Symbol for section number.
319322
const MCExpr *MCE = MCCOFFSectionNumberTargetExpr::create(
320323
*Symbol, this->getWriter(), getContext());
324+
ensureHeadroom(4);
321325
addFixup(MCE, FK_Data_4);
322326
// Emit 4 bytes (zeros) to the object file.
323327
appendContents(4, 0);
@@ -328,6 +332,7 @@ void MCWinCOFFStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
328332
// Create Symbol for section offset.
329333
const MCExpr *MCE =
330334
MCCOFFSectionOffsetTargetExpr::create(*Symbol, getContext());
335+
ensureHeadroom(4);
331336
addFixup(MCE, FK_Data_4);
332337
// Emit 4 bytes (zeros) to the object file.
333338
appendContents(4, 0);

llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,37 +1034,43 @@ MCELFStreamer &MipsTargetELFStreamer::getStreamer() {
10341034

10351035
void MipsTargetELFStreamer::emitGPRel32Value(const MCExpr *Value) {
10361036
auto &S = getStreamer();
1037+
S.ensureHeadroom(4);
10371038
S.addFixup(Value, Mips::fixup_Mips_GPREL32);
10381039
S.appendContents(4, 0);
10391040
}
10401041

10411042
void MipsTargetELFStreamer::emitGPRel64Value(const MCExpr *Value) {
10421043
auto &S = getStreamer();
1044+
S.ensureHeadroom(8);
10431045
// fixup_Mips_GPREL32 desginates R_MIPS_GPREL32+R_MIPS_64 on MIPS64.
10441046
S.addFixup(Value, Mips::fixup_Mips_GPREL32);
10451047
S.appendContents(8, 0);
10461048
}
10471049

10481050
void MipsTargetELFStreamer::emitDTPRel32Value(const MCExpr *Value) {
10491051
auto &S = getStreamer();
1052+
S.ensureHeadroom(4);
10501053
S.addFixup(Value, Mips::fixup_Mips_DTPREL32);
10511054
S.appendContents(4, 0);
10521055
}
10531056

10541057
void MipsTargetELFStreamer::emitDTPRel64Value(const MCExpr *Value) {
10551058
auto &S = getStreamer();
1059+
S.ensureHeadroom(8);
10561060
S.addFixup(Value, Mips::fixup_Mips_DTPREL64);
10571061
S.appendContents(8, 0);
10581062
}
10591063

10601064
void MipsTargetELFStreamer::emitTPRel32Value(const MCExpr *Value) {
10611065
auto &S = getStreamer();
1066+
S.ensureHeadroom(4);
10621067
S.addFixup(Value, Mips::fixup_Mips_TPREL32);
10631068
S.appendContents(4, 0);
10641069
}
10651070

10661071
void MipsTargetELFStreamer::emitTPRel64Value(const MCExpr *Value) {
10671072
auto &S = getStreamer();
1073+
S.ensureHeadroom(8);
10681074
S.addFixup(Value, Mips::fixup_Mips_TPREL64);
10691075
S.appendContents(8, 0);
10701076
}

0 commit comments

Comments
 (0)