; RUN: obj2yaml %t.shmem.wasm | FileCheck %s --check-prefix=SHMEM
; SHMEM: - Type: CODE
-; SHMEM: - Index: 7
+; SHMEM: - Index: 6
; SHMEM-NEXT: Locals: []
; SHMEM-NEXT: Body: 100310050B
; SHMEM-NEXT: - Index: 5
; SHMEM-NEXT: Name: __wasm_apply_global_relocs
; SHMEM-NEXT: - Index: 6
-; SHMEM-NEXT: Name: __wasm_apply_global_tls_relocs
-; SHMEM-NEXT: - Index: 7
; SHMEM-NEXT: Name: __wasm_start
-; SHMEM-NEXT: - Index: 8
+; SHMEM-NEXT: - Index: 7
; SHMEM-NEXT: Name: foo
-; SHMEM-NEXT: - Index: 9
+; SHMEM-NEXT: - Index: 8
; SHMEM-NEXT: Name: get_data_address
-; SHMEM-NEXT: - Index: 10
+; SHMEM-NEXT: - Index: 9
; SHMEM-NEXT: Name: _start
# RUN: wasm-ld --experimental-pic -shared -o %t.so %t.o
# RUN: obj2yaml %t.so | FileCheck %s --check-prefix=PIC
+# RUN: wasm-ld --experimental-pic --no-gc-sections --no-entry -pie -o %t-pie.wasm %t.o
+# RUN: obj2yaml %t.so | FileCheck %s --check-prefix=PIC
+
# CHECK: - Type: GLOBAL
# __stack_pointer
# CHECK-NEXT: Globals:
global.get __tls_align
end_function
+# TLS symbols can also be accessed by `global.get tls1@GOT@TLS`
+# which is the pattern emitted for non-DSO-local symbols.
+# In this case the global that holds that address must be
+# initialized by `__wasm_apply_global_tls_relocs` which is
+# called by `__wasm_init_tls`.
+.globl tls1_got_addr
+tls1_got_addr:
+ .functype tls1_got_addr () -> (i32)
+ global.get tls1@GOT@TLS
+ end_function
+
.section .bss.no_tls,"",@
.globl no_tls
.p2align 2
# CHECK-NEXT: Value: 4
-# ASM: <__wasm_init_tls>:
+# ASM-LABEL: <__wasm_init_tls>:
# ASM-EMPTY:
# ASM-NEXT: local.get 0
# ASM-NEXT: global.set 1
# ASM-NEXT: i32.const 0
# ASM-NEXT: i32.const 12
# ASM-NEXT: memory.init 0, 0
+# call to __wasm_apply_global_tls_relocs>
+# ASM-NEXT: call 3
# ASM-NEXT: end
-# ASM: <tls1_addr>:
+# ASM-LABEL: <__wasm_apply_global_tls_relocs>:
+# ASM-EMPTY:
+# ASM-NEXT: global.get 1
+# ASM-NEXT: i32.const 0
+# ASM-NEXT: i32.add
+# ASM-NEXT: global.set 4
+# ASM-NEXT: end
+
+# ASM-LABEL: <tls1_addr>:
# ASM-EMPTY:
# ASM-NEXT: global.get 1
# ASM-NEXT: i32.const 0
# ASM-NEXT: i32.add
# ASM-NEXT: end
-# ASM: <tls2_addr>:
+# ASM-LABEL: <tls2_addr>:
# ASM-EMPTY:
# ASM-NEXT: global.get 1
# ASM-NEXT: i32.const 4
# ASM-NEXT: i32.add
# ASM-NEXT: end
-# ASM: <tls3_addr>:
+# ASM-LABEL: <tls3_addr>:
# ASM-EMPTY:
# ASM-NEXT: global.get 1
# ASM-NEXT: i32.const 8
# ASM-NEXT: i32.add
# ASM-NEXT: end
-# ASM: <tls_align>:
+# ASM-LABEL: <tls_align>:
# ASM-EMPTY:
-# ASM-NEXT: global.get 3
-# ASM-NEXT: end
+# ASM-NEXT: global.get 3
+# ASM-NEXT: end
# Also verify TLS usage with --relocatable
# RUN: wasm-ld --relocatable -o %t3.wasm %t.o
# RELOC-NEXT: Name: __tls_base
# RELOC-NEXT: - Index: 1
# RELOC-NEXT: Name: __tls_align
+# RELOC-NEXT: - Index: 2
+# RELOC-NEXT: Name: GOT.data.internal.tls1
# RELOC-NEXT: DataSegmentNames:
# RELOC-NEXT: - Index: 0
# RELOC-NEXT: Name: .tdata
bool is64 = config->is64.getValueOr(false);
uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32;
for (const Symbol *sym : internalGotSymbols) {
- // In the case of dynamic linking, internal GOT entries
- // need to be mutable since they get updated to the correct
- // runtime value during `__wasm_apply_global_relocs`.
- bool mutable_ = config->isPic & !sym->isStub;
+ bool mutable_ = false;
+ if (!sym->isStub) {
+ // In the case of dynamic linking, these global must to be mutable since
+ // they get updated to the correct runtime value during
+ // `__wasm_apply_global_relocs`.
+ if (config->isPic && !sym->isTLS())
+ mutable_ = true;
+ // With multi-theadeding any TLS globals must be mutable since they get
+ // set during `__wasm_apply_global_tls_relocs`
+ if (config->sharedMemory && sym->isTLS())
+ mutable_ = true;
+ }
WasmGlobalType type{itype, mutable_};
WasmInitExpr initExpr;
if (auto *d = dyn_cast<DefinedData>(sym))
// specific relocation types combined with linker relaxation which could
// transform a `global.get` to an `i32.const`.
void addInternalGOTEntry(Symbol *sym);
- bool needsRelocations() { return internalGotSymbols.size(); }
+ bool needsRelocations() {
+ return llvm::find_if(internalGotSymbols, [=](Symbol *sym) {
+ return !sym->isTLS();
+ }) != internalGotSymbols.end();
+ }
+ bool needsTLSRelocations() {
+ return llvm::find_if(internalGotSymbols, [=](Symbol *sym) {
+ return sym->isTLS();
+ }) != internalGotSymbols.end();
+ }
void generateRelocationCode(raw_ostream &os, bool TLS) const;
std::vector<DefinedData *> dataAddressGlobals;
WasmSym::initMemory->markLive();
}
+ 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();
+ }
+
if (config->isPic) {
// For PIC code we create synthetic functions that apply relocations.
// These get called from __wasm_call_ctors before the user-level
"__wasm_apply_global_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
make<SyntheticFunction>(nullSignature, "__wasm_apply_global_relocs"));
WasmSym::applyGlobalRelocs->markLive();
- if (config->sharedMemory) {
- WasmSym::applyGlobalTLSRelocs = symtab->addSyntheticFunction(
- "__wasm_apply_global_tls_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
- make<SyntheticFunction>(nullSignature,
- "__wasm_apply_global_tls_relocs"));
- WasmSym::applyGlobalTLSRelocs->markLive();
- }
}
}