[lld] a0495e6 - [lld][WebAssembly] Apply relocations to TLS data
Sam Clegg via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 31 15:51:37 PST 2023
Author: Sam Clegg
Date: 2023-01-31T15:50:44-08:00
New Revision: a0495e6b008c7b1f5af2d0756bf62aefdc6a43ea
URL: https://github.com/llvm/llvm-project/commit/a0495e6b008c7b1f5af2d0756bf62aefdc6a43ea
DIFF: https://github.com/llvm/llvm-project/commit/a0495e6b008c7b1f5af2d0756bf62aefdc6a43ea.diff
LOG: [lld][WebAssembly] Apply relocations to TLS data
This is only needed in the case of dynamic linking and pthreads.
Previously these relocations were simply not being applied.
Verified that this works using a more real world emscripten test:
https://github.com/emscripten-core/emscripten/pull/18641
Differential Revision: https://reviews.llvm.org/D143020
Added:
lld/test/wasm/tls-relocations.s
Modified:
lld/test/wasm/tls.s
lld/wasm/InputChunks.cpp
lld/wasm/Symbols.cpp
lld/wasm/Symbols.h
lld/wasm/Writer.cpp
Removed:
################################################################################
diff --git a/lld/test/wasm/tls-relocations.s b/lld/test/wasm/tls-relocations.s
new file mode 100644
index 0000000000000..ebe83227631f4
--- /dev/null
+++ b/lld/test/wasm/tls-relocations.s
@@ -0,0 +1,88 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
+
+.section data,"",@
+ .int32 41
+data_sym:
+ .int32 42
+ .size data_sym, 4
+
+# TLS data section of size 16 with as relocations at offset 8 and 12
+.section tls_sec,"T",@
+.globl tls_sym
+.p2align 2
+ .int32 0x50
+tls_sym:
+ .int32 0x51
+ .int32 data_sym
+ .int32 tls_sym
+ .size tls_sym, 4
+
+.section .custom_section.target_features,"",@
+ .int8 2
+ .int8 43
+ .int8 7
+ .ascii "atomics"
+ .int8 43
+ .int8 11
+ .ascii "bulk-memory"
+
+# RUN: wasm-ld --experimental-pic -pie -no-gc-sections --shared-memory --no-entry -o %t.wasm %t.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+# RUN: llvm-objdump -d --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck --check-prefix=ASM %s --
+
+# CHECK: - Type: GLOBAL
+
+# __tls_base
+# CHECK-NEXT: Globals:
+# CHECK-NEXT: - Index: 3
+# CHECK-NEXT: Type: I32
+# CHECK-NEXT: Mutable: true
+# CHECK-NEXT: InitExpr:
+# CHECK-NEXT: Opcode: I32_CONST
+# CHECK-NEXT: Value: 0
+
+# __tls_size
+# CHECK-NEXT: - Index: 4
+# CHECK-NEXT: Type: I32
+# CHECK-NEXT: Mutable: false
+# CHECK-NEXT: InitExpr:
+# CHECK-NEXT: Opcode: I32_CONST
+# CHECK-NEXT: Value: 16
+
+# __tls_align
+# CHECK-NEXT: - Index: 5
+# CHECK-NEXT: Type: I32
+# CHECK-NEXT: Mutable: false
+# CHECK-NEXT: InitExpr:
+# CHECK-NEXT: Opcode: I32_CONST
+# CHECK-NEXT: Value: 4
+
+# ASM: <__wasm_init_tls>:
+# ASM-EMPTY:
+# ASM-NEXT: local.get 0
+# ASM-NEXT: global.set 3
+# ASM-NEXT: local.get 0
+# ASM-NEXT: i32.const 0
+# ASM-NEXT: i32.const 16
+# ASM-NEXT: memory.init 0, 0
+# call to __wasm_apply_tls_relocs
+# ASM-NEXT: call 4
+# ASM-NEXT: end
+
+# ASM: <__wasm_apply_tls_relocs>:
+# ASM-EMPTY:
+# ASM-NEXT: i32.const 8
+# ASM-NEXT: global.get 3
+# ASM-NEXT: i32.add
+# ASM-NEXT: global.get 1
+# ASM-NEXT: i32.const 20
+# ASM-NEXT: i32.add
+# ASM-NEXT: i32.store 0
+# ASM-NEXT: i32.const 12
+# ASM-NEXT: global.get 3
+# ASM-NEXT: i32.add
+# ASM-NEXT: global.get 3
+# ASM-NEXT: i32.const 4
+# ASM-NEXT: i32.add
+# ASM-NEXT: i32.store 0
+# ASM-NEXT: end
diff --git a/lld/test/wasm/tls.s b/lld/test/wasm/tls.s
index a8345a367caa8..b1f47f6769927 100644
--- a/lld/test/wasm/tls.s
+++ b/lld/test/wasm/tls.s
@@ -133,7 +133,7 @@ tls3:
# ASM-NEXT: i32.const 0
# ASM-NEXT: i32.const 12
# ASM-NEXT: memory.init 0, 0
-# call to __wasm_apply_global_tls_relocs>
+# call to __wasm_apply_global_tls_relocs
# ASM-NEXT: call 3
# ASM-NEXT: end
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index 53b5288801d86..09437939e1b90 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -384,14 +384,17 @@ void InputChunk::generateRelocationCode(raw_ostream &os) const {
<< " addend=" << rel.Addend << " index=" << rel.Index
<< " output offset=" << offset << "\n");
- // Calculate the address at which to apply the relocations
+ // Calculate the address at which to apply the relocation
writeU8(os, opcode_ptr_const, "CONST");
writeSleb128(os, offset, "offset");
// In PIC mode we need to add the __memory_base
if (config->isPic) {
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
- writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
+ if (isTLS())
+ writeUleb128(os, WasmSym::tlsBase->getGlobalIndex(), "tls_base");
+ else
+ writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
writeU8(os, opcode_ptr_add, "ADD");
}
@@ -418,6 +421,8 @@ void InputChunk::generateRelocationCode(raw_ostream &os) const {
if (rel.Type == R_WASM_TABLE_INDEX_I32 ||
rel.Type == R_WASM_TABLE_INDEX_I64)
baseSymbol = WasmSym::tableBase;
+ else if (sym->isTLS())
+ baseSymbol = WasmSym::tlsBase;
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
writeU8(os, opcode_reloc_const, "CONST");
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 5ef92dde7cc58..8864e840dd585 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -77,6 +77,7 @@ DefinedFunction *WasmSym::callDtors;
DefinedFunction *WasmSym::initMemory;
DefinedFunction *WasmSym::applyDataRelocs;
DefinedFunction *WasmSym::applyGlobalRelocs;
+DefinedFunction *WasmSym::applyTLSRelocs;
DefinedFunction *WasmSym::applyGlobalTLSRelocs;
DefinedFunction *WasmSym::initTLS;
DefinedFunction *WasmSym::startFunction;
@@ -308,7 +309,7 @@ uint64_t DefinedData::getVA() const {
// output segment (__tls_base). When building without shared memory, TLS
// symbols absolute, just like non-TLS.
if (isTLS() && config->sharedMemory)
- return getOutputSegmentOffset() + value;
+ return getOutputSegmentOffset();
if (segment)
return segment->getVA(value);
return value;
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 6bdf587f90e76..16f1b535876e0 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -578,6 +578,11 @@ struct WasmSym {
// Unlike __wasm_apply_data_relocs this needs to run on every thread.
static DefinedFunction *applyGlobalRelocs;
+ // __wasm_apply_tls_relocs
+ // Like applyDataRelocs but for TLS section. These must be delayed until
+ // __wasm_init_tls.
+ static DefinedFunction *applyTLSRelocs;
+
// __wasm_apply_global_tls_relocs
// Like applyGlobalRelocs but for globals that hold TLS addresses. These
// must be delayed until __wasm_init_tls.
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 36005037cd17e..8fe0b060b248f 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -63,6 +63,7 @@ class Writer {
void createStartFunction();
void createApplyDataRelocationsFunction();
void createApplyGlobalRelocationsFunction();
+ void createApplyTLSRelocationsFunction();
void createApplyGlobalTLSRelocationsFunction();
void createCallCtorsFunction();
void createInitTLSFunction();
@@ -1043,14 +1044,31 @@ void Writer::createSyntheticInitFunctions() {
}
}
- if (config->sharedMemory && out.globalSec->needsTLSRelocations()) {
- WasmSym::applyGlobalTLSRelocs = symtab->addSyntheticFunction(
- "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
- make<SyntheticFunction>(nullSignature,
- "__wasm_apply_global_tls_relocs"));
- WasmSym::applyGlobalTLSRelocs->markLive();
- // TLS relocations depend on the __tls_base symbols
- WasmSym::tlsBase->markLive();
+ if (config->sharedMemory) {
+ if (out.globalSec->needsTLSRelocations()) {
+ WasmSym::applyGlobalTLSRelocs = symtab->addSyntheticFunction(
+ "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
+ make<SyntheticFunction>(nullSignature,
+ "__wasm_apply_global_tls_relocs"));
+ WasmSym::applyGlobalTLSRelocs->markLive();
+ // TLS relocations depend on the __tls_base symbols
+ WasmSym::tlsBase->markLive();
+ }
+
+ auto hasTLSRelocs = [](const OutputSegment *segment) {
+ if (segment->isTLS())
+ for (const auto* is: segment->inputSegments)
+ if (is->getRelocations().size())
+ return true;
+ return false;
+ };
+ if (llvm::any_of(segments, hasTLSRelocs)) {
+ WasmSym::applyTLSRelocs = symtab->addSyntheticFunction(
+ "__wasm_apply_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
+ make<SyntheticFunction>(nullSignature,
+ "__wasm_apply_tls_relocs"));
+ WasmSym::applyTLSRelocs->markLive();
+ }
}
if (config->isPic && out.globalSec->needsRelocations()) {
@@ -1332,8 +1350,9 @@ void Writer::createApplyDataRelocationsFunction() {
raw_string_ostream os(bodyContent);
writeUleb128(os, 0, "num locals");
for (const OutputSegment *seg : segments)
- for (const InputChunk *inSeg : seg->inputSegments)
- inSeg->generateRelocationCode(os);
+ if (!config->sharedMemory || !seg->isTLS())
+ for (const InputChunk *inSeg : seg->inputSegments)
+ inSeg->generateRelocationCode(os);
writeU8(os, WASM_OPCODE_END, "END");
}
@@ -1341,6 +1360,23 @@ void Writer::createApplyDataRelocationsFunction() {
createFunction(WasmSym::applyDataRelocs, bodyContent);
}
+void Writer::createApplyTLSRelocationsFunction() {
+ LLVM_DEBUG(dbgs() << "createApplyTLSRelocationsFunction\n");
+ std::string bodyContent;
+ {
+ raw_string_ostream os(bodyContent);
+ writeUleb128(os, 0, "num locals");
+ for (const OutputSegment *seg : segments)
+ if (seg->isTLS())
+ for (const InputChunk *inSeg : seg->inputSegments)
+ inSeg->generateRelocationCode(os);
+
+ writeU8(os, WASM_OPCODE_END, "END");
+ }
+
+ createFunction(WasmSym::applyTLSRelocs, bodyContent);
+}
+
// Similar to createApplyDataRelocationsFunction but generates relocation code
// for WebAssembly globals. Because these globals are not shared between threads
// these relocation need to run on every thread.
@@ -1476,6 +1512,12 @@ void Writer::createInitTLSFunction() {
writeU8(os, 0, "memory index immediate");
}
+ if (WasmSym::applyTLSRelocs) {
+ writeU8(os, WASM_OPCODE_CALL, "CALL");
+ writeUleb128(os, WasmSym::applyTLSRelocs->getFunctionIndex(),
+ "function index");
+ }
+
if (WasmSym::applyGlobalTLSRelocs) {
writeU8(os, WASM_OPCODE_CALL, "CALL");
writeUleb128(os, WasmSym::applyGlobalTLSRelocs->getFunctionIndex(),
@@ -1619,6 +1661,8 @@ void Writer::run() {
createApplyDataRelocationsFunction();
if (WasmSym::applyGlobalRelocs)
createApplyGlobalRelocationsFunction();
+ if (WasmSym::applyTLSRelocs)
+ createApplyTLSRelocationsFunction();
if (WasmSym::applyGlobalTLSRelocs)
createApplyGlobalTLSRelocationsFunction();
if (WasmSym::initMemory)
More information about the llvm-commits
mailing list