[lld][WebAssembly] Generate TLS relocation code also when linking statically
authorSam Clegg <sbc@chromium.org>
Fri, 29 Oct 2021 16:58:56 +0000 (09:58 -0700)
committerSam Clegg <sbc@chromium.org>
Fri, 29 Oct 2021 20:26:35 +0000 (13:26 -0700)
Previously relocations were only generated for PIC output, but
relocations for TLS GOT entries are always needed when shared
memory is enabled, not just in PIC mode.

This means that the `__wasm_apply_global_tls_relocs` is now
generated even for statically linked (non-PIC) output.  Without
this the globals that hold the addresses of TLS symbols are
not set correctly.

Differential Revision: https://reviews.llvm.org/D112833

lld/test/wasm/pie.ll
lld/test/wasm/tls-non-shared-memory.s
lld/test/wasm/tls.s
lld/wasm/SyntheticSections.cpp
lld/wasm/SyntheticSections.h
lld/wasm/Writer.cpp

index 0dba0aa..ee2f027 100644 (file)
@@ -91,7 +91,7 @@ declare void @external_func()
 ; 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
 
@@ -109,13 +109,11 @@ declare void @external_func()
 ; 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
 
index 222db77..0468129 100644 (file)
@@ -48,6 +48,9 @@ tls1:
 # 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:
index 4544c74..a8345a3 100644 (file)
@@ -33,6 +33,17 @@ tls_align:
   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
@@ -114,7 +125,7 @@ tls3:
 # 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
@@ -122,33 +133,43 @@ tls3:
 # 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
@@ -172,6 +193,8 @@ tls3:
 # 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
index 37b498a..7fc5c32 100644 (file)
@@ -455,10 +455,18 @@ void GlobalSection::writeBody() {
   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))
index 4caab9d..956c896 100644 (file)
@@ -287,7 +287,16 @@ public:
   // 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;
index d504593..91e90ae 100644 (file)
@@ -997,6 +997,14 @@ void Writer::createSyntheticInitFunctions() {
     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
@@ -1011,13 +1019,6 @@ void Writer::createSyntheticInitFunctions() {
           "__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();
-      }
     }
   }