Skip to content

Commit 4272372

Browse files
committed
[ MC ] Match labels to existing fragments even when switching sections.
Summary: This commit builds upon Derek Schuff's 2014 commit for attaching labels to existing fragments ( Diff Revision: http://reviews.llvm.org/D5915 ) When temporary labels appear ahead of a fragment, MCObjectStreamer will track the temporary label symbol in a "Pending Labels" list. Labels are associated with fragments when a real fragment arrives; otherwise, an empty data fragment will be created if the streamer's section changes or if the stream finishes. This commit moves the "Pending Labels" list into each MCStream, so that this label-fragment matching process is resilient to section changes. If the streamer emits a label in a new section, switches to another section to do other work, then switches back to the first section and emits a fragment, that initial label will be associated with this new fragment. Labels will only receive empty data fragments in the case where no other fragment exists for that section. The downstream effects of this can be seen in Mach-O relocations. The previous approach could produce local section relocations and external symbol relocations for the same data in an object file, and this mix of relocation types resulted in problems in the ld64 Mach-O linker. This commit ensures relocations triggered by temporary labels are consistent. Reviewers: pete, ab, dschuff Reviewed By: pete, dschuff Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D71368
1 parent ad622af commit 4272372

File tree

5 files changed

+177
-19
lines changed

5 files changed

+177
-19
lines changed

llvm/include/llvm/MC/MCObjectStreamer.h

+14-6
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class MCObjectStreamer : public MCStreamer {
3838
bool EmitEHFrame;
3939
bool EmitDebugFrame;
4040
SmallVector<MCSymbol *, 2> PendingLabels;
41+
SmallVector<MCSection*, 2> PendingLabelSections;
42+
unsigned CurSubsectionIdx;
4143
struct PendingMCFixup {
4244
const MCSymbol *Sym;
4345
MCFixup Fixup;
@@ -87,17 +89,23 @@ class MCObjectStreamer : public MCStreamer {
8789
protected:
8890
bool changeSectionImpl(MCSection *Section, const MCExpr *Subsection);
8991

90-
/// If any labels have been emitted but not assigned fragments, ensure that
91-
/// they get assigned, either to F if possible or to a new data fragment.
92-
/// Optionally, it is also possible to provide an offset \p FOffset, which
93-
/// will be used as a symbol offset within the fragment.
92+
/// Assign a label to the current Section and Subsection even though a
93+
/// fragment is not yet present. Use flushPendingLabels(F) to associate
94+
/// a fragment with this label.
95+
void addPendingLabel(MCSymbol* label);
96+
97+
/// If any labels have been emitted but not assigned fragments in the current
98+
/// Section and Subsection, ensure that they get assigned, either to fragment
99+
/// F if possible or to a new data fragment. Optionally, one can provide an
100+
/// offset \p FOffset as a symbol offset within the fragment.
94101
void flushPendingLabels(MCFragment *F, uint64_t FOffset = 0);
95102

96103
public:
97104
void visitUsedSymbol(const MCSymbol &Sym) override;
98105

99-
/// Create a dummy fragment to assign any pending labels.
100-
void flushPendingLabels() { flushPendingLabels(nullptr); }
106+
/// Create a data fragment for any pending labels across all Sections
107+
/// and Subsections.
108+
void flushPendingLabels();
101109

102110
MCAssembler &getAssembler() { return *Assembler; }
103111
MCAssembler *getAssemblerPtr() override;

llvm/include/llvm/MC/MCSection.h

+21
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ class MCSection {
9292
/// below that number.
9393
SmallVector<std::pair<unsigned, MCFragment *>, 1> SubsectionFragmentMap;
9494

95+
/// State for tracking labels that don't yet have Fragments
96+
struct PendingLabel {
97+
MCSymbol* Sym;
98+
unsigned Subsection;
99+
PendingLabel(MCSymbol* Sym, unsigned Subsection = 0)
100+
: Sym(Sym), Subsection(Subsection) {}
101+
};
102+
SmallVector<PendingLabel, 2> PendingLabels;
103+
95104
protected:
96105
SectionVariant Variant;
97106
SectionKind Kind;
@@ -187,6 +196,18 @@ class MCSection {
187196
/// Check whether this section is "virtual", that is has no actual object
188197
/// file contents.
189198
virtual bool isVirtualSection() const = 0;
199+
200+
/// Add a pending label for the requested subsection. This label will be
201+
/// associated with a fragment in flushPendingLabels()
202+
void addPendingLabel(MCSymbol* label, unsigned Subsection = 0);
203+
204+
/// Associate all pending labels in a subsection with a fragment.
205+
void flushPendingLabels(MCFragment *F, uint64_t FOffset = 0,
206+
unsigned Subsection = 0);
207+
208+
/// Associate all pending labels with empty data fragments. One fragment
209+
/// will be created for each subsection as necessary.
210+
void flushPendingLabels();
190211
};
191212

192213
} // end namespace llvm

llvm/lib/MC/MCObjectStreamer.cpp

+59-13
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,64 @@ MCAssembler *MCObjectStreamer::getAssemblerPtr() {
4242
return nullptr;
4343
}
4444

45+
void MCObjectStreamer::addPendingLabel(MCSymbol* S) {
46+
MCSection *CurSection = getCurrentSectionOnly();
47+
if (CurSection) {
48+
// Register labels that have not yet been assigned to a Section.
49+
if (!PendingLabels.empty()) {
50+
for (MCSymbol* Sym : PendingLabels)
51+
CurSection->addPendingLabel(Sym);
52+
PendingLabels.clear();
53+
}
54+
55+
// Add this label to the current Section / Subsection.
56+
CurSection->addPendingLabel(S, CurSubsectionIdx);
57+
58+
// Add this Section to the list of PendingLabelSections.
59+
auto SecIt = std::find(PendingLabelSections.begin(),
60+
PendingLabelSections.end(), CurSection);
61+
if (SecIt == PendingLabelSections.end())
62+
PendingLabelSections.push_back(CurSection);
63+
}
64+
else
65+
// There is no Section / Subsection for this label yet.
66+
PendingLabels.push_back(S);
67+
}
68+
4569
void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
46-
if (PendingLabels.empty())
70+
MCSection *CurSection = getCurrentSectionOnly();
71+
if (!CurSection) {
72+
assert(PendingLabels.empty());
4773
return;
48-
if (!F) {
49-
F = new MCDataFragment();
50-
MCSection *CurSection = getCurrentSectionOnly();
51-
CurSection->getFragmentList().insert(CurInsertionPoint, F);
52-
F->setParent(CurSection);
5374
}
54-
for (MCSymbol *Sym : PendingLabels) {
55-
Sym->setFragment(F);
56-
Sym->setOffset(FOffset);
75+
// Register labels that have not yet been assigned to a Section.
76+
if (!PendingLabels.empty()) {
77+
for (MCSymbol* Sym : PendingLabels)
78+
CurSection->addPendingLabel(Sym, CurSubsectionIdx);
79+
PendingLabels.clear();
5780
}
58-
PendingLabels.clear();
81+
82+
// Associate a fragment with this label, either the supplied fragment
83+
// or an empty data fragment.
84+
if (F)
85+
CurSection->flushPendingLabels(F, FOffset, CurSubsectionIdx);
86+
else
87+
CurSection->flushPendingLabels(nullptr, 0, CurSubsectionIdx);
88+
}
89+
90+
void MCObjectStreamer::flushPendingLabels() {
91+
// Register labels that have not yet been assigned to a Section.
92+
if (!PendingLabels.empty()) {
93+
MCSection *CurSection = getCurrentSectionOnly();
94+
assert(CurSection);
95+
for (MCSymbol* Sym : PendingLabels)
96+
CurSection->addPendingLabel(Sym, CurSubsectionIdx);
97+
PendingLabels.clear();
98+
}
99+
100+
// Assign an empty data fragment to all remaining pending labels.
101+
for (MCSection* Section : PendingLabelSections)
102+
Section->flushPendingLabels();
59103
}
60104

61105
// When fixup's offset is a forward declared label, e.g.:
@@ -120,6 +164,7 @@ void MCObjectStreamer::reset() {
120164
EmitEHFrame = true;
121165
EmitDebugFrame = false;
122166
PendingLabels.clear();
167+
PendingLabelSections.clear();
123168
MCStreamer::reset();
124169
}
125170

@@ -237,7 +282,7 @@ void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) {
237282
// fragment. (They will all be reassigned to a real fragment in
238283
// flushPendingLabels())
239284
Symbol->setOffset(0);
240-
PendingLabels.push_back(Symbol);
285+
addPendingLabel(Symbol);
241286
}
242287
}
243288

@@ -257,7 +302,7 @@ void MCObjectStreamer::EmitLabelAtPos(MCSymbol *Symbol, SMLoc Loc,
257302
assert(isa<MCDummyFragment>(F) &&
258303
"F must either be an MCDataFragment or the pending MCDummyFragment");
259304
assert(Offset == 0);
260-
PendingLabels.push_back(Symbol);
305+
addPendingLabel(Symbol);
261306
}
262307
}
263308

@@ -292,7 +337,6 @@ void MCObjectStreamer::ChangeSection(MCSection *Section,
292337
bool MCObjectStreamer::changeSectionImpl(MCSection *Section,
293338
const MCExpr *Subsection) {
294339
assert(Section && "Cannot switch to a null section!");
295-
flushPendingLabels(nullptr);
296340
getContext().clearDwarfLocSeen();
297341

298342
bool Created = getAssembler().registerSection(*Section);
@@ -712,7 +756,9 @@ void MCObjectStreamer::FinishImpl() {
712756
// Dump out the dwarf file & directory tables and line tables.
713757
MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams());
714758

759+
// Update any remaining pending labels with empty data fragments.
715760
flushPendingLabels();
761+
716762
resolvePendingFixups();
717763
getAssembler().Finish();
718764
}

llvm/lib/MC/MCSection.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,41 @@ MCSection::getSubsectionInsertionPoint(unsigned Subsection) {
8686
return IP;
8787
}
8888

89+
void MCSection::addPendingLabel(MCSymbol* label, unsigned Subsection) {
90+
PendingLabels.push_back(PendingLabel(label, Subsection));
91+
}
92+
93+
void MCSection::flushPendingLabels(MCFragment *F, uint64_t FOffset,
94+
unsigned Subsection) {
95+
if (PendingLabels.empty())
96+
return;
97+
98+
// Set the fragment and fragment offset for all pending symbols in the
99+
// specified Subsection, and remove those symbols from the pending list.
100+
for (auto It = PendingLabels.begin(); It != PendingLabels.end(); ++It) {
101+
PendingLabel& Label = *It;
102+
if (Label.Subsection == Subsection) {
103+
Label.Sym->setFragment(F);
104+
Label.Sym->setOffset(FOffset);
105+
PendingLabels.erase(It--);
106+
}
107+
}
108+
}
109+
110+
void MCSection::flushPendingLabels() {
111+
// Make sure all remaining pending labels point to data fragments, by
112+
// creating new empty data fragments for each Subsection with labels pending.
113+
while (!PendingLabels.empty()) {
114+
PendingLabel& Label = PendingLabels[0];
115+
iterator CurInsertionPoint =
116+
this->getSubsectionInsertionPoint(Label.Subsection);
117+
MCFragment *F = new MCDataFragment();
118+
getFragmentList().insert(CurInsertionPoint, F);
119+
F->setParent(this);
120+
flushPendingLabels(F, 0, Label.Subsection);
121+
}
122+
}
123+
89124
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
90125
LLVM_DUMP_METHOD void MCSection::dump() const {
91126
raw_ostream &OS = errs();

llvm/test/MC/MachO/pending-labels.s

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Verify relocations for temporary labels are referenced by real symbols
2+
// at the same address.
3+
//
4+
// RUN: llvm-mc -triple x86_64-apple-darwin -filetype=obj -o - %s | llvm-objdump -r - | FileCheck %s
5+
6+
L1:
7+
.section __TEXT,__text_cold,regular,pure_instructions
8+
L2:
9+
.text
10+
L3:
11+
.section __TEXT,__text_cold,regular,pure_instructions
12+
L4:
13+
_function2:
14+
L5:
15+
nop
16+
L6:
17+
.text
18+
L7:
19+
_function1:
20+
L8:
21+
nop
22+
23+
.data
24+
__data:
25+
.quad L1-.
26+
.quad L2-.
27+
.quad L3-.
28+
.quad L4-.
29+
.quad L5-.
30+
.quad L6-.
31+
.quad L7-.
32+
.quad L8-.
33+
// CHECK: 0000000000000038 X86_64_RELOC_SUBTRACTOR _function1-__data
34+
// CHECK: 0000000000000038 X86_64_RELOC_UNSIGNED _function1
35+
// CHECK: 0000000000000030 X86_64_RELOC_SUBTRACTOR _function1-__data
36+
// CHECK: 0000000000000030 X86_64_RELOC_UNSIGNED _function1
37+
// CHECK: 0000000000000028 X86_64_RELOC_SUBTRACTOR _function2-__data
38+
// CHECK: 0000000000000028 X86_64_RELOC_UNSIGNED _function2
39+
// CHECK: 0000000000000020 X86_64_RELOC_SUBTRACTOR _function2-__data
40+
// CHECK: 0000000000000020 X86_64_RELOC_UNSIGNED _function2
41+
// CHECK: 0000000000000018 X86_64_RELOC_SUBTRACTOR _function2-__data
42+
// CHECK: 0000000000000018 X86_64_RELOC_UNSIGNED _function2
43+
// CHECK: 0000000000000010 X86_64_RELOC_SUBTRACTOR _function1-__data
44+
// CHECK: 0000000000000010 X86_64_RELOC_UNSIGNED _function1
45+
// CHECK: 0000000000000008 X86_64_RELOC_SUBTRACTOR _function2-__data
46+
// CHECK: 0000000000000008 X86_64_RELOC_UNSIGNED _function2
47+
// CHECK: 0000000000000000 X86_64_RELOC_SUBTRACTOR _function1-__data
48+
// CHECK: 0000000000000000 X86_64_RELOC_UNSIGNED _function1

0 commit comments

Comments
 (0)