mirror of
https://github.com/intel/llvm.git
synced 2026-01-24 08:30:34 +08:00
[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
This commit is contained in:
88
lld/test/wasm/tls-relocations.s
Normal file
88
lld/test/wasm/tls-relocations.s
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -63,6 +63,7 @@ private:
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user