summaryrefslogtreecommitdiffstats
path: root/lld/wasm/Writer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/wasm/Writer.cpp')
-rw-r--r--lld/wasm/Writer.cpp81
1 files changed, 77 insertions, 4 deletions
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 77a29a2d99e..23a63edee7c 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -57,6 +57,7 @@ private:
void createInitMemoryFunction();
void createApplyRelocationsFunction();
void createCallCtorsFunction();
+ void createInitTLSFunction();
void assignIndexes();
void populateSymtab();
@@ -242,6 +243,11 @@ void Writer::layoutMemory() {
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name,
memoryPtr, seg->size, seg->alignment));
memoryPtr += seg->size;
+
+ if (WasmSym::tlsSize && seg->name == ".tdata") {
+ auto *tlsSize = cast<DefinedGlobal>(WasmSym::tlsSize);
+ tlsSize->global->global.InitExpr.Value.Int32 = seg->size;
+ }
}
// TODO: Add .bss space here.
@@ -353,6 +359,7 @@ void Writer::populateTargetFeatures() {
StringMap<std::string> used;
StringMap<std::string> required;
StringMap<std::string> disallowed;
+ bool tlsUsed = false;
// Only infer used features if user did not specify features
bool inferFeatures = !config->features.hasValue();
@@ -385,6 +392,14 @@ void Writer::populateTargetFeatures() {
std::to_string(feature.Prefix));
}
}
+
+ for (InputSegment *segment : file->segments) {
+ if (!segment->live)
+ continue;
+ StringRef name = segment->getName();
+ if (name.startswith(".tdata") || name.startswith(".tbss"))
+ tlsUsed = true;
+ }
}
if (inferFeatures)
@@ -411,6 +426,10 @@ void Writer::populateTargetFeatures() {
error("'bulk-memory' feature must be used in order to emit passive "
"segments");
+ if (!used.count("bulk-memory") && tlsUsed)
+ error("'bulk-memory' feature must be used in order to use thread-local "
+ "storage");
+
// Validate that used features are allowed in output
if (!inferFeatures) {
for (auto &feature : used.keys()) {
@@ -492,8 +511,8 @@ void Writer::calculateExports() {
// implement in all major browsers.
// See: https://github.com/WebAssembly/mutable-global
if (g->getGlobalType()->Mutable) {
- // Only the __stack_pointer should ever be create as mutable.
- assert(g == WasmSym::stackPointer);
+ // Only __stack_pointer and __tls_base should ever be create as mutable.
+ assert(g == WasmSym::stackPointer || g == WasmSym::tlsBase);
continue;
}
export_ = {name, WASM_EXTERNAL_GLOBAL, g->getGlobalIndex()};
@@ -602,6 +621,11 @@ static StringRef getOutputDataSegmentName(StringRef name) {
// we only have a single __memory_base to use as our base address.
if (config->isPic)
return ".data";
+ // We only support one thread-local segment, so we must merge the segments
+ // despite --no-merge-data-segments.
+ // We also need to merge .tbss into .tdata so they share the same offsets.
+ if (name.startswith(".tdata") || name.startswith(".tbss"))
+ return ".tdata";
if (!config->mergeDataSegments)
return name;
if (name.startswith(".text."))
@@ -625,7 +649,7 @@ void Writer::createOutputSegments() {
if (s == nullptr) {
LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
s = make<OutputSegment>(name, segments.size());
- if (config->passiveSegments)
+ if (config->passiveSegments || name == ".tdata")
s->initFlags = WASM_SEGMENT_IS_PASSIVE;
segments.push_back(s);
}
@@ -655,7 +679,7 @@ void Writer::createInitMemoryFunction() {
// initialize passive data segments
for (const OutputSegment *s : segments) {
- if (s->initFlags & WASM_SEGMENT_IS_PASSIVE) {
+ if (s->initFlags & WASM_SEGMENT_IS_PASSIVE && s->name != ".tdata") {
// destination address
writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
writeSleb128(os, s->startVA, "destination address");
@@ -737,6 +761,49 @@ void Writer::createCallCtorsFunction() {
createFunction(WasmSym::callCtors, bodyContent);
}
+void Writer::createInitTLSFunction() {
+ if (!WasmSym::initTLS->isLive())
+ return;
+
+ std::string bodyContent;
+ {
+ raw_string_ostream os(bodyContent);
+
+ OutputSegment *tlsSeg = nullptr;
+ for (auto *seg : segments) {
+ if (seg->name == ".tdata")
+ tlsSeg = seg;
+ break;
+ }
+
+ writeUleb128(os, 0, "num locals");
+ if (tlsSeg) {
+ writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
+ writeUleb128(os, 0, "local index");
+
+ writeU8(os, WASM_OPCODE_GLOBAL_SET, "global.set");
+ writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "global index");
+
+ writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
+ writeUleb128(os, 0, "local index");
+
+ writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
+ writeSleb128(os, 0, "segment offset");
+
+ writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
+ writeSleb128(os, tlsSeg->size, "memory region size");
+
+ writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
+ writeUleb128(os, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT");
+ writeUleb128(os, tlsSeg->index, "segment index immediate");
+ writeU8(os, 0, "memory index immediate");
+ }
+ writeU8(os, WASM_OPCODE_END, "end function");
+ }
+
+ createFunction(WasmSym::initTLS, bodyContent);
+}
+
// Populate InitFunctions vector with init functions from all input objects.
// This is then used either when creating the output linking section or to
// synthesize the "__wasm_call_ctors" function.
@@ -829,6 +896,12 @@ void Writer::run() {
createCallCtorsFunction();
}
+ if (config->sharedMemory && !config->shared)
+ createInitTLSFunction();
+
+ if (errorCount())
+ return;
+
log("-- calculateTypes");
calculateTypes();
log("-- calculateExports");
OpenPOWER on IntegriCloud