[lld] 70f3c6e - [lld][WebAssembly] Delay the merging of data section when dynamic linking
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 11 10:54:27 PST 2021
Author: Sam Clegg
Date: 2021-02-11T10:54:15-08:00
New Revision: 70f3c6e9e6b8a0e5efc7cbf8997df32156ea9536
URL: https://github.com/llvm/llvm-project/commit/70f3c6e9e6b8a0e5efc7cbf8997df32156ea9536
DIFF: https://github.com/llvm/llvm-project/commit/70f3c6e9e6b8a0e5efc7cbf8997df32156ea9536.diff
LOG: [lld][WebAssembly] Delay the merging of data section when dynamic linking
With dynamic linking we have the current limitation that there can be
only a single active data segment (since we use __memory_base as the
load address and we can't do arithmetic in constant expresions).
This change delays the merging of active segments until a little later
in the linking process which means that the grouping of data by section,
and the magic __start/__end symbols work as expected under dynamic
linking.
Differential Revision: https://reviews.llvm.org/D96453
Added:
Modified:
lld/test/wasm/data-segments.ll
lld/test/wasm/tls-no-shared.s
lld/wasm/InputChunks.cpp
lld/wasm/InputChunks.h
lld/wasm/MapFile.cpp
lld/wasm/OutputSegment.h
lld/wasm/Symbols.cpp
lld/wasm/Writer.cpp
Removed:
################################################################################
diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll
index 1af6dccce457..9c0382c693d2 100644
--- a/lld/test/wasm/data-segments.ll
+++ b/lld/test/wasm/data-segments.ll
@@ -121,8 +121,8 @@
; PASSIVE32-PIC-NEXT: - Type: I32
; PASSIVE64-PIC-NEXT: - Type: I64
; PASSIVE-PIC-NEXT: Count: 1
-; PASSIVE32-PIC-NEXT: Body: 230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
-; PASSIVE64-PIC-NEXT: Body: 230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
+; PASSIVE32-PIC-NEXT: Body: 230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B4CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
+; PASSIVE64-PIC-NEXT: Body: 230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B4CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
; PASSIVE-PIC-NEXT: - Index: 3
; PASSIVE-PIC-NEXT: Locals: []
; PASSIVE-PIC-NEXT: Body: 0B
diff --git a/lld/test/wasm/tls-no-shared.s b/lld/test/wasm/tls-no-shared.s
index 6c17489b7d42..d93a19c84338 100644
--- a/lld/test/wasm/tls-no-shared.s
+++ b/lld/test/wasm/tls-no-shared.s
@@ -54,7 +54,7 @@ tls1:
# CHECK-NEXT: Mutable: false
# CHECK-NEXT: InitExpr:
# CHECK-NEXT: Opcode: I32_CONST
-# CHECK-NEXT: Value: 1028
+# CHECK-NEXT: Value: 1024
# CHECK-NEXT: - Type: EXPORT
# CHECK: - Type: DATA
@@ -65,11 +65,11 @@ tls1:
# CHECK-NEXT: Offset:
# CHECK-NEXT: Opcode: I32_CONST
# CHECK-NEXT: Value: 1024
-# CHECK-NEXT: Content: 2A000000
+# CHECK-NEXT: Content: 2B000000
# .tdata
# CHECK-NEXT: - SectionOffset: 17
# CHECK-NEXT: InitFlags: 0
# CHECK-NEXT: Offset:
# CHECK-NEXT: Opcode: I32_CONST
# CHECK-NEXT: Value: 1028
-# CHECK-NEXT: Content: 2B000000
+# CHECK-NEXT: Content: 2A000000
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index d8c5f84c0487..d90342491e34 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -353,6 +353,10 @@ void InputFunction::writeTo(uint8_t *buf) const {
LLVM_DEBUG(dbgs() << " total: " << (buf + chunkSize - orig) << "\n");
}
+uint64_t InputSegment::getVA() const {
+ return outputSeg->startVA + outputSegmentOffset;
+}
+
// Generate code to apply relocations to the data section at runtime.
// This is only called when generating shared libaries (PIC) where address are
// not known at static link time.
@@ -370,10 +374,9 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
auto tombstone = getTombstone();
// TODO(sbc): Encode the relocations in the data section and write a loop
// here to apply them.
- uint64_t segmentVA = outputSeg->startVA + outputSegmentOffset;
for (const WasmRelocation &rel : relocations) {
uint64_t offset = rel.Offset - getInputSectionOffset();
- uint64_t outputOffset = segmentVA + offset;
+ uint64_t outputOffset = getVA() + offset;
LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(rel.Type)
<< " addend=" << rel.Addend << " index=" << rel.Index
diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index 9082d1dada5f..e237888cf480 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -108,6 +108,7 @@ class InputSegment : public InputChunk {
uint32_t getInputSectionOffset() const override {
return segment.SectionOffset;
}
+ uint64_t getVA() const;
const OutputSegment *outputSeg = nullptr;
int32_t outputSegmentOffset = 0;
diff --git a/lld/wasm/MapFile.cpp b/lld/wasm/MapFile.cpp
index c6f08b785413..e1497aa6e0ee 100644
--- a/lld/wasm/MapFile.cpp
+++ b/lld/wasm/MapFile.cpp
@@ -138,7 +138,7 @@ void lld::wasm::writeMapFile(ArrayRef<OutputSection *> outputSections) {
oseg->size);
os << oseg->name << '\n';
for (auto *chunk : oseg->inputSegments) {
- writeHeader(os, oseg->startVA + chunk->outputSegmentOffset,
+ writeHeader(os, chunk->getVA(),
chunk->outputSec->getOffset() + chunk->outputOffset,
chunk->getSize());
os.indent(8) << toString(chunk) << '\n';
diff --git a/lld/wasm/OutputSegment.h b/lld/wasm/OutputSegment.h
index 34c3c49ff796..f6985ce855e6 100644
--- a/lld/wasm/OutputSegment.h
+++ b/lld/wasm/OutputSegment.h
@@ -22,10 +22,11 @@ class OutputSegment {
public:
OutputSegment(StringRef n) : name(n) {}
- void addInputSegment(InputSegment *inSeg) {
- alignment = std::max(alignment, inSeg->getAlignment());
+ void addInputSegment(InputSegment *inSeg, uint32_t forceAlignment = 0) {
+ uint32_t segAlign = std::max(forceAlignment, inSeg->getAlignment());
+ alignment = std::max(alignment, segAlign);
inputSegments.push_back(inSeg);
- size = llvm::alignTo(size, 1ULL << inSeg->getAlignment());
+ size = llvm::alignTo(size, 1ULL << segAlign);
inSeg->outputSeg = this;
inSeg->outputSegmentOffset = size;
size += inSeg->getSize();
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 6db1fa944ffc..269357921589 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -279,7 +279,7 @@ DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
uint64_t DefinedData::getVirtualAddress() const {
LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
if (segment)
- return segment->outputSeg->startVA + segment->outputSegmentOffset + offset;
+ return segment->getVA() + offset;
return offset;
}
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index be35f7a6d146..d91b6b811081 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -77,6 +77,7 @@ class Writer {
void calculateCustomSections();
void calculateTypes();
void createOutputSegments();
+ void combineOutputSegments();
void layoutMemory();
void createHeader();
@@ -86,6 +87,7 @@ class Writer {
void createCustomSections();
void createSyntheticSections();
+ void createSyntheticSectionsPostLayout();
void finalizeSections();
// Custom sections
@@ -795,10 +797,6 @@ static StringRef getOutputDataSegmentName(StringRef name) {
// We also need to merge .tbss into .tdata so they share the same offsets.
if (name.startswith(".tdata") || name.startswith(".tbss"))
return ".tdata";
- // With PIC code we currently only support a single data segment since
- // we only have a single __memory_base to use as our base address.
- if (config->isPic)
- return ".data";
if (!config->mergeDataSegments)
return name;
if (name.startswith(".text."))
@@ -843,9 +841,9 @@ void Writer::createOutputSegments() {
[](const OutputSegment *a, const OutputSegment *b) {
auto order = [](StringRef name) {
return StringSwitch<int>(name)
- .StartsWith(".rodata", 0)
- .StartsWith(".data", 1)
- .StartsWith(".tdata", 2)
+ .StartsWith(".tdata", 0)
+ .StartsWith(".rodata", 1)
+ .StartsWith(".data", 2)
.StartsWith(".bss", 4)
.Default(3);
};
@@ -856,6 +854,52 @@ void Writer::createOutputSegments() {
segments[i]->index = i;
}
+void Writer::combineOutputSegments() {
+ // With PIC code we currently only support a single data segment since
+ // we only have a single __memory_base to use as our base address.
+ // This pass combines all non-TLS data segments into a single .data
+ // segment.
+ // This restructions can be relaxed once we have extended constant
+ // expressions available:
+ // https://github.com/WebAssembly/extended-const
+ assert(config->isPic);
+ if (segments.size() <= 1)
+ return;
+ OutputSegment *combined = nullptr;
+ std::vector<OutputSegment *> new_segments;
+ for (OutputSegment *s : segments) {
+ if (s->name == ".tdata") {
+ new_segments.push_back(s);
+ } else {
+ if (!combined) {
+ combined = make<OutputSegment>(".data");
+ combined->startVA = s->startVA;
+ if (config->sharedMemory)
+ combined->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE;
+ }
+ bool first = true;
+ for (InputSegment *inSeg : s->inputSegments) {
+ uint32_t alignment = first ? s->alignment : 0;
+ first = false;
+#ifndef NDEBUG
+ uint64_t oldVA = inSeg->getVA();
+#endif
+ combined->addInputSegment(inSeg, alignment);
+#ifndef NDEBUG
+ uint64_t newVA = inSeg->getVA();
+ assert(oldVA == newVA);
+#endif
+ }
+ }
+ }
+ if (combined) {
+ new_segments.push_back(combined);
+ segments = new_segments;
+ for (size_t i = 0; i < segments.size(); ++i)
+ segments[i]->index = i;
+ }
+}
+
static void createFunction(DefinedFunction *func, StringRef bodyContent) {
std::string functionBody;
{
@@ -1295,11 +1339,14 @@ void Writer::createSyntheticSections() {
out.exportSec = make<ExportSection>();
out.startSec = make<StartSection>();
out.elemSec = make<ElemSection>();
+ out.producersSec = make<ProducersSection>();
+ out.targetFeaturesSec = make<TargetFeaturesSection>();
+}
+
+void Writer::createSyntheticSectionsPostLayout() {
out.dataCountSec = make<DataCountSection>(segments);
out.linkingSec = make<LinkingSection>(initFunctions, segments);
out.nameSec = make<NameSection>(segments);
- out.producersSec = make<ProducersSection>();
- out.targetFeaturesSec = make<TargetFeaturesSection>();
}
void Writer::run() {
@@ -1318,18 +1365,15 @@ void Writer::run() {
createOutputSegments();
log("-- createSyntheticSections");
createSyntheticSections();
- log("-- populateProducers");
- populateProducers();
- log("-- calculateImports");
- calculateImports();
log("-- layoutMemory");
layoutMemory();
if (!config->relocatable) {
// Create linker synthesized __start_SECNAME/__stop_SECNAME symbols
// This has to be done after memory layout is performed.
- for (const OutputSegment *seg : segments)
+ for (const OutputSegment *seg : segments) {
addStartStopSymbols(seg);
+ }
}
// Delay reporting error about explict exports until after addStartStopSymbols
@@ -1345,6 +1389,17 @@ void Writer::run() {
warn(Twine("symbol exported via --export not found: ") + name);
}
+ if (config->isPic) {
+ log("-- combineOutputSegments");
+ combineOutputSegments();
+ }
+
+ log("-- createSyntheticSectionsPostLayout");
+ createSyntheticSectionsPostLayout();
+ log("-- populateProducers");
+ populateProducers();
+ log("-- calculateImports");
+ calculateImports();
log("-- scanRelocations");
scanRelocations();
log("-- finalizeIndirectFunctionTable");
More information about the llvm-commits
mailing list