[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