Skip to content

Commit a4a6c91

Browse files
committed
Using prioritized StringTableBuilder
1 parent 4204ca0 commit a4a6c91

File tree

3 files changed

+77
-30
lines changed

3 files changed

+77
-30
lines changed

lld/COFF/Writer.cpp

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/ADT/STLExtras.h"
2525
#include "llvm/ADT/StringSet.h"
2626
#include "llvm/BinaryFormat/COFF.h"
27+
#include "llvm/MC/StringTableBuilder.h"
2728
#include "llvm/Support/BinaryStreamReader.h"
2829
#include "llvm/Support/Debug.h"
2930
#include "llvm/Support/Endian.h"
@@ -204,7 +205,8 @@ struct ChunkRange {
204205
class Writer {
205206
public:
206207
Writer(COFFLinkerContext &c)
207-
: buffer(c.e.outputBuffer), delayIdata(c), ctx(c) {}
208+
: buffer(c.e.outputBuffer), strtab(StringTableBuilder::WinCOFF),
209+
delayIdata(c), ctx(c) {}
208210
void run();
209211

210212
private:
@@ -284,8 +286,7 @@ class Writer {
284286

285287
std::unique_ptr<FileOutputBuffer> &buffer;
286288
std::map<PartialSectionKey, PartialSection *> partialSections;
287-
std::vector<char> strtab;
288-
StringMap<size_t> strtabMap;
289+
StringTableBuilder strtab;
289290
std::vector<llvm::object::coff_symbol16> outputSymtab;
290291
std::vector<ECCodeMapEntry> codeMap;
291292
IdataContents idata;
@@ -1438,17 +1439,6 @@ void Writer::assignOutputSectionIndices() {
14381439
sc->setOutputSectionIdx(mc->getOutputSectionIdx());
14391440
}
14401441

1441-
size_t Writer::addEntryToStringTable(StringRef str) {
1442-
assert(str.size() > COFF::NameSize);
1443-
size_t newOffsetOfEntry = strtab.size() + 4; // +4 for the size field
1444-
auto res = strtabMap.try_emplace(str, newOffsetOfEntry);
1445-
if (res.second) {
1446-
strtab.insert(strtab.end(), str.begin(), str.end());
1447-
strtab.push_back('\0');
1448-
}
1449-
return res.first->getValue();
1450-
}
1451-
14521442
std::optional<coff_symbol16> Writer::createSymbol(Defined *def) {
14531443
coff_symbol16 sym;
14541444
switch (def->kind()) {
@@ -1489,7 +1479,8 @@ std::optional<coff_symbol16> Writer::createSymbol(Defined *def) {
14891479
StringRef name = def->getName();
14901480
if (name.size() > COFF::NameSize) {
14911481
sym.Name.Offset.Zeroes = 0;
1492-
sym.Name.Offset.Offset = addEntryToStringTable(name);
1482+
sym.Name.Offset.Offset = 0; // Filled in later.
1483+
strtab.add(name);
14931484
} else {
14941485
memset(sym.Name.ShortName, 0, COFF::NameSize);
14951486
memcpy(sym.Name.ShortName, name.data(), name.size());
@@ -1521,6 +1512,7 @@ void Writer::createSymbolAndStringTable() {
15211512
// solution where discardable sections have long names preserved and
15221513
// non-discardable sections have their names truncated, to ensure that any
15231514
// section which is mapped at runtime also has its name mapped at runtime.
1515+
SmallVector<OutputSection *> longNameSections;
15241516
for (OutputSection *sec : ctx.outputSections) {
15251517
if (sec->name.size() <= COFF::NameSize)
15261518
continue;
@@ -1532,9 +1524,13 @@ void Writer::createSymbolAndStringTable() {
15321524
<< " is longer than 8 characters and will use a non-standard string "
15331525
"table";
15341526
}
1535-
sec->setStringTableOff(addEntryToStringTable(sec->name));
1527+
// Put the section name in the begin of strtab so that its offset is less
1528+
// than Max7DecimalOffset otherwise lldb/gdb will not read it.
1529+
strtab.add(sec->name, /*Priority=*/UINT8_MAX);
1530+
longNameSections.push_back(sec);
15361531
}
15371532

1533+
std::vector<std::pair<size_t, StringRef>> longNameSymbols;
15381534
if (ctx.config.writeSymtab) {
15391535
for (ObjFile *file : ctx.objFileInstances) {
15401536
for (Symbol *b : file->getSymbols()) {
@@ -1549,15 +1545,22 @@ void Writer::createSymbolAndStringTable() {
15491545
continue;
15501546
}
15511547

1552-
if (std::optional<coff_symbol16> sym = createSymbol(d))
1548+
if (std::optional<coff_symbol16> sym = createSymbol(d)) {
1549+
if (d->getName().size() > COFF::NameSize)
1550+
longNameSymbols.emplace_back(outputSymtab.size(), d->getName());
15531551
outputSymtab.push_back(*sym);
1552+
}
15541553

15551554
if (auto *dthunk = dyn_cast<DefinedImportThunk>(d)) {
15561555
if (!dthunk->wrappedSym->writtenToSymtab) {
15571556
dthunk->wrappedSym->writtenToSymtab = true;
15581557
if (std::optional<coff_symbol16> sym =
1559-
createSymbol(dthunk->wrappedSym))
1558+
createSymbol(dthunk->wrappedSym)) {
1559+
if (d->getName().size() > COFF::NameSize)
1560+
longNameSymbols.emplace_back(outputSymtab.size(),
1561+
dthunk->wrappedSym->getName());
15601562
outputSymtab.push_back(*sym);
1563+
}
15611564
}
15621565
}
15631566
}
@@ -1567,11 +1570,19 @@ void Writer::createSymbolAndStringTable() {
15671570
if (outputSymtab.empty() && strtab.empty())
15681571
return;
15691572

1573+
strtab.finalize();
1574+
for (OutputSection *sec : longNameSections)
1575+
sec->setStringTableOff(strtab.getOffset(sec->name));
1576+
for (auto P : longNameSymbols) {
1577+
coff_symbol16 &sym = outputSymtab[P.first];
1578+
sym.Name.Offset.Offset = strtab.getOffset(P.second);
1579+
}
1580+
15701581
// We position the symbol table to be adjacent to the end of the last section.
15711582
uint64_t fileOff = fileSize;
15721583
pointerToSymbolTable = fileOff;
15731584
fileOff += outputSymtab.size() * sizeof(coff_symbol16);
1574-
fileOff += 4 + strtab.size();
1585+
fileOff += strtab.getSize();
15751586
fileSize = alignTo(fileOff, ctx.config.fileAlign);
15761587
}
15771588

@@ -1952,9 +1963,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
19521963
// Create the string table, it follows immediately after the symbol table.
19531964
// The first 4 bytes is length including itself.
19541965
buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]);
1955-
write32le(buf, strtab.size() + 4);
1956-
if (!strtab.empty())
1957-
memcpy(buf + 4, strtab.data(), strtab.size());
1966+
strtab.write(buf);
19581967
}
19591968

19601969
void Writer::openFile(StringRef path) {

llvm/include/llvm/MC/StringTableBuilder.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class StringTableBuilder {
3737
};
3838

3939
private:
40+
// Only non-zero priority will be recorded.
41+
DenseMap<CachedHashStringRef, uint8_t> StringPriorityMap;
4042
DenseMap<CachedHashStringRef, size_t> StringIndexMap;
4143
size_t Size = 0;
4244
Kind K;
@@ -50,11 +52,15 @@ class StringTableBuilder {
5052
StringTableBuilder(Kind K, Align Alignment = Align(1));
5153
~StringTableBuilder();
5254

53-
/// Add a string to the builder. Returns the position of S in the
54-
/// table. The position will be changed if finalize is used.
55-
/// Can only be used before the table is finalized.
56-
size_t add(CachedHashStringRef S);
57-
size_t add(StringRef S) { return add(CachedHashStringRef(S)); }
55+
/// Add a string to the builder. Returns the position of S in the table. The
56+
/// position will be changed if finalize is used. Can only be used before the
57+
/// table is finalized. Priority is only useful with reordering. Strings with
58+
/// same priority will be put together. Strings with higher priority are
59+
/// placed closer to the begin of string table.
60+
size_t add(CachedHashStringRef S, uint8_t Priority = 0);
61+
size_t add(StringRef S, uint8_t Priority = 0) {
62+
return add(CachedHashStringRef(S), Priority);
63+
}
5864

5965
/// Analyze the strings and build the final table. No more strings can
6066
/// be added after this point.
@@ -77,6 +83,7 @@ class StringTableBuilder {
7783
bool contains(StringRef S) const { return contains(CachedHashStringRef(S)); }
7884
bool contains(CachedHashStringRef S) const { return StringIndexMap.count(S); }
7985

86+
bool empty() const { return StringIndexMap.empty(); }
8087
size_t getSize() const { return Size; }
8188
void clear();
8289

llvm/lib/MC/StringTableBuilder.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,41 @@ void StringTableBuilder::finalizeInOrder() {
138138
void StringTableBuilder::finalizeStringTable(bool Optimize) {
139139
Finalized = true;
140140

141-
if (Optimize) {
141+
if (Optimize && StringIndexMap.size()) {
142142
std::vector<StringPair *> Strings;
143143
Strings.reserve(StringIndexMap.size());
144144
for (StringPair &P : StringIndexMap)
145145
Strings.push_back(&P);
146146

147-
multikeySort(Strings, 0);
147+
auto getStringPriority = [this](const CachedHashStringRef Str) -> uint8_t {
148+
if (StringPriorityMap.contains(Str))
149+
return StringPriorityMap[Str];
150+
return 0;
151+
};
152+
153+
size_t RangeBegin = 0;
154+
MutableArrayRef<StringPair *> StringsRef(Strings);
155+
if (StringPriorityMap.size()) {
156+
llvm::sort(Strings,
157+
[&](const StringPair *LHS, const StringPair *RHS) -> bool {
158+
return getStringPriority(LHS->first) >
159+
getStringPriority(RHS->first);
160+
});
161+
// Make sure ArrayRef is valid. Although std::sort implementaion is
162+
// normally in-place , it is not guaranteed by standard.
163+
StringsRef = Strings;
164+
165+
uint8_t RangePriority = getStringPriority(Strings[0]->first);
166+
for (size_t I = 1, E = Strings.size(); I != E && RangePriority; ++I) {
167+
uint8_t Priority = getStringPriority(Strings[I]->first);
168+
if (Priority != RangePriority) {
169+
multikeySort(StringsRef.slice(RangeBegin, I - RangeBegin), 0);
170+
RangePriority = Priority;
171+
RangeBegin = I;
172+
}
173+
}
174+
}
175+
multikeySort(StringsRef.slice(RangeBegin), 0);
148176
initSize();
149177

150178
StringRef Previous;
@@ -199,11 +227,14 @@ size_t StringTableBuilder::getOffset(CachedHashStringRef S) const {
199227
return I->second;
200228
}
201229

202-
size_t StringTableBuilder::add(CachedHashStringRef S) {
230+
size_t StringTableBuilder::add(CachedHashStringRef S, uint8_t Priority) {
203231
if (K == WinCOFF)
204232
assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
205233

206234
assert(!isFinalized());
235+
if (Priority)
236+
StringPriorityMap[S] = std::max(Priority, StringPriorityMap[S]);
237+
207238
auto P = StringIndexMap.insert(std::make_pair(S, 0));
208239
if (P.second) {
209240
size_t Start = alignTo(Size, Alignment);

0 commit comments

Comments
 (0)