Skip to content

Commit 5fca9c5

Browse files
committed
[BOLT] Change order of new sections
While the order of new sections in the output binary was deterministic in the past (i.e. there was no run-to-run variation), it wasn't always rational as we used size to define the precedence of allocatable sections within "code" or "data" groups (probably unintentionally). Fix that by defining stricter section-ordering rules. Other than the order of sections, this should be NFC. Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D135235
1 parent 0b213c9 commit 5fca9c5

File tree

3 files changed

+52
-9
lines changed

3 files changed

+52
-9
lines changed

bolt/include/bolt/Core/BinarySection.h

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class BinaryData;
4343
class BinarySection {
4444
friend class BinaryContext;
4545

46+
/// Count the number of sections created.
47+
static uint64_t Count;
48+
4649
BinaryContext &BC; // Owning BinaryContext
4750
std::string Name; // Section name
4851
const SectionRef Section; // SectionRef (may be null)
@@ -86,6 +89,7 @@ class BinarySection {
8689
uint64_t OutputSize{0}; // Section size in the rewritten binary.
8790
uint64_t OutputFileOffset{0}; // File offset in the rewritten binary file.
8891
StringRef OutputContents; // Rewritten section contents.
92+
const uint64_t SectionNumber; // Order in which the section was created.
8993
unsigned SectionID{-1u}; // Unique ID used for address mapping.
9094
// Set by ExecutableFileMemoryManager.
9195
uint32_t Index{0}; // Section index in the output file.
@@ -147,13 +151,14 @@ class BinarySection {
147151
Size(Section.getSize()), Alignment(Section.getAlignment()),
148152
ELFType(Section.getELFType()), ELFFlags(Section.getELFFlags()),
149153
Relocations(Section.Relocations),
150-
PendingRelocations(Section.PendingRelocations), OutputName(Name) {}
154+
PendingRelocations(Section.PendingRelocations), OutputName(Name),
155+
SectionNumber(++Count) {}
151156

152157
BinarySection(BinaryContext &BC, SectionRef Section)
153158
: BC(BC), Name(getName(Section)), Section(Section),
154159
Contents(getContents(Section)), Address(Section.getAddress()),
155160
Size(Section.getSize()), Alignment(Section.getAlignment()),
156-
OutputName(Name) {
161+
OutputName(Name), SectionNumber(++Count) {
157162
if (isELF()) {
158163
ELFType = ELFSectionRef(Section).getType();
159164
ELFFlags = ELFSectionRef(Section).getFlags();
@@ -173,7 +178,7 @@ class BinarySection {
173178
Contents(reinterpret_cast<const char *>(Data), Data ? Size : 0),
174179
Address(0), Size(Size), Alignment(Alignment), ELFType(ELFType),
175180
ELFFlags(ELFFlags), IsFinalized(true), OutputName(Name),
176-
OutputSize(Size), OutputContents(Contents) {
181+
OutputSize(Size), OutputContents(Contents), SectionNumber(++Count) {
177182
assert(Alignment > 0 && "section alignment must be > 0");
178183
}
179184

@@ -207,10 +212,34 @@ class BinarySection {
207212

208213
// Order sections by their immutable properties.
209214
bool operator<(const BinarySection &Other) const {
210-
return (getAddress() < Other.getAddress() ||
211-
(getAddress() == Other.getAddress() &&
212-
(getSize() < Other.getSize() ||
213-
(getSize() == Other.getSize() && getName() < Other.getName()))));
215+
// Allocatable before non-allocatable.
216+
if (isAllocatable() != Other.isAllocatable())
217+
return isAllocatable() > Other.isAllocatable();
218+
219+
// Input sections take precedence.
220+
if (hasSectionRef() != Other.hasSectionRef())
221+
return hasSectionRef() > Other.hasSectionRef();
222+
223+
// Compare allocatable input sections by their address.
224+
if (getAddress() != Other.getAddress())
225+
return getAddress() < Other.getAddress();
226+
if (getAddress() && getSize() != Other.getSize())
227+
return getSize() < Other.getSize();
228+
229+
// Code before data.
230+
if (isText() != Other.isText())
231+
return isText() > Other.isText();
232+
233+
// Read-only before writable.
234+
if (isReadOnly() != Other.isReadOnly())
235+
return isReadOnly() > Other.isReadOnly();
236+
237+
// BSS at the end.
238+
if (isBSS() != Other.isBSS())
239+
return isBSS() < Other.isBSS();
240+
241+
// Otherwise, preserve the order of creation.
242+
return SectionNumber < Other.SectionNumber;
214243
}
215244

216245
///
@@ -228,13 +257,13 @@ class BinarySection {
228257
bool isText() const {
229258
if (isELF())
230259
return (ELFFlags & ELF::SHF_EXECINSTR);
231-
return getSectionRef().isText();
260+
return hasSectionRef() && getSectionRef().isText();
232261
}
233262
bool isData() const {
234263
if (isELF())
235264
return (ELFType == ELF::SHT_PROGBITS &&
236265
(ELFFlags & (ELF::SHF_ALLOC | ELF::SHF_WRITE)));
237-
return getSectionRef().isData();
266+
return hasSectionRef() && getSectionRef().isData();
238267
}
239268
bool isBSS() const {
240269
return (ELFType == ELF::SHT_NOBITS &&

bolt/lib/Core/BinarySection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ extern cl::opt<bool> PrintRelocations;
2626
extern cl::opt<bool> HotData;
2727
} // namespace opts
2828

29+
uint64_t BinarySection::Count = 0;
30+
2931
bool BinarySection::isELF() const { return BC.isELF(); }
3032

3133
bool BinarySection::isMachO() const { return BC.isMachO(); }
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
REQUIRES: system-linux
2+
3+
RUN: %clang %p/Inputs/basic-instrumentation.s -Wl,-q -o %t.exe
4+
RUN: llvm-bolt %t.exe -o %t --instrument
5+
RUN: llvm-readelf --section-headers %t | FileCheck %s
6+
7+
## Verify that llvm-bolt outputs new sections in expected order.
8+
CHECK: .text.bolt.extra.1
9+
CHECK: .rodata.bolt.extra.1
10+
CHECK: .data.bolt.extra.1
11+
CHECK: .bss.bolt.extra.1
12+

0 commit comments

Comments
 (0)