[llvm] 44177e5 - [WebAssembly] Add explict TLS symbol flag

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 9 07:12:14 PDT 2021


Author: Sam Clegg
Date: 2021-09-09T10:03:30-04:00
New Revision: 44177e5fb20d00de01f6f322841bf532e19c4a8c

URL: https://github.com/llvm/llvm-project/commit/44177e5fb20d00de01f6f322841bf532e19c4a8c
DIFF: https://github.com/llvm/llvm-project/commit/44177e5fb20d00de01f6f322841bf532e19c4a8c.diff

LOG: [WebAssembly] Add explict TLS symbol flag

As before we maintain backwards compat with older object files
by also infering the TLS flag based on the name of the segment.

This change is was split out from https://reviews.llvm.org/D108877.

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

Added: 
    

Modified: 
    lld/wasm/InputChunks.h
    lld/wasm/InputFiles.cpp
    lld/wasm/Relocations.cpp
    lld/wasm/Symbols.cpp
    lld/wasm/Symbols.h
    lld/wasm/Writer.cpp
    llvm/include/llvm/BinaryFormat/Wasm.h
    llvm/include/llvm/MC/MCSymbolWasm.h
    llvm/include/llvm/MC/MCWasmStreamer.h
    llvm/lib/MC/MCWasmStreamer.cpp
    llvm/lib/MC/WasmObjectWriter.cpp
    llvm/lib/ObjectYAML/WasmYAML.cpp
    llvm/test/MC/WebAssembly/tls.s
    llvm/test/MC/WebAssembly/tls64.s

Removed: 
    


################################################################################
diff  --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index f1174d937ad3b..ed86662e75692 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -81,12 +81,7 @@ class InputChunk {
   void writeRelocations(llvm::raw_ostream &os) const;
   void generateRelocationCode(raw_ostream &os) const;
 
-  bool isTLS() const {
-    // Older object files don't include WASM_SEG_FLAG_TLS and instead
-    // relied on the naming convention.
-    return flags & llvm::wasm::WASM_SEG_FLAG_TLS || name.startswith(".tdata") ||
-           name.startswith(".tbss");
-  }
+  bool isTLS() const { return flags & llvm::wasm::WASM_SEG_FLAG_TLS; }
 
   ObjFile *file;
   OutputSection *outputSec = nullptr;
@@ -113,11 +108,15 @@ class InputChunk {
   // Signals the chunk was discarded by COMDAT handling.
   unsigned discarded : 1;
 
+  // Signals that the chuck was implicitly marked as TLS based on its name
+  // alone. This is a compatibility mechanism to support older object files.
+  unsigned implicitTLS : 1;
+
 protected:
   InputChunk(ObjFile *f, Kind k, StringRef name, uint32_t alignment = 0,
              uint32_t flags = 0)
       : name(name), file(f), alignment(alignment), flags(flags), sectionKind(k),
-        live(!config->gcSections), discarded(false) {}
+        live(!config->gcSections), discarded(false), implicitTLS(false) {}
   ArrayRef<uint8_t> data() const { return rawData; }
   uint64_t getTombstone() const;
 

diff  --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 35d8dd1ed7be7..3f87df07a9519 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -491,7 +491,14 @@ void ObjFile::parse(bool ignoreComdats) {
     } else
       seg = make<InputSegment>(s, this);
     seg->discarded = isExcludedByComdat(seg);
-
+    // Older object files did not include WASM_SEG_FLAG_TLS and instead
+    // relied on the naming convention.  To maintain compat with such objects
+    // we still imply the TLS flag based on the name of the segment.
+    if (!seg->isTLS() &&
+        (seg->name.startswith(".tdata") || seg->name.startswith(".tbss"))) {
+      seg->flags |= WASM_SEG_FLAG_TLS;
+      seg->implicitTLS = true;
+    }
     segments.emplace_back(seg);
   }
   setRelocs(segments, dataSection);
@@ -592,6 +599,9 @@ Symbol *ObjFile::createDefined(const WasmSymbol &sym) {
     InputChunk *seg = segments[sym.Info.DataRef.Segment];
     auto offset = sym.Info.DataRef.Offset;
     auto size = sym.Info.DataRef.Size;
+    if (seg->implicitTLS) {
+      flags |= WASM_SYMBOL_TLS;
+    }
     if (sym.isBindingLocal())
       return make<DefinedData>(name, flags, this, seg, offset, size);
     if (seg->discarded)

diff  --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp
index 1dca6d621b262..06d7f5d6752b5 100644
--- a/lld/wasm/Relocations.cpp
+++ b/lld/wasm/Relocations.cpp
@@ -120,6 +120,12 @@ void scanRelocations(InputChunk *chunk) {
       // merged with normal data and allowing TLS relocation in non-TLS
       // segments.
       if (config->sharedMemory) {
+        if (!sym->isTLS()) {
+          error(toString(file) + ": relocation " +
+                relocTypeToString(reloc.Type) +
+                " cannot be used against non-TLS symbol `" + toString(*sym) +
+                "`");
+        }
         if (auto *D = dyn_cast<DefinedData>(sym)) {
           if (!D->segment->outputSeg->isTLS()) {
             error(toString(file) + ": relocation " +
@@ -133,6 +139,12 @@ void scanRelocations(InputChunk *chunk) {
     }
 
     if (config->isPic) {
+      if (sym->isTLS() && sym->isUndefined()) {
+        error(toString(file) +
+              ": TLS symbol is undefined, but TLS symbols cannot yet be "
+              "imported: `" +
+              toString(*sym) + "`");
+      }
       switch (reloc.Type) {
       case R_WASM_TABLE_INDEX_SLEB:
       case R_WASM_TABLE_INDEX_SLEB64:
@@ -146,15 +158,6 @@ void scanRelocations(InputChunk *chunk) {
               " cannot be used against symbol " + toString(*sym) +
               "; recompile with -fPIC");
         break;
-      case R_WASM_MEMORY_ADDR_TLS_SLEB:
-      case R_WASM_MEMORY_ADDR_TLS_SLEB64:
-        if (!sym->isDefined()) {
-          error(toString(file) +
-                ": TLS symbol is undefined, but TLS symbols cannot yet be "
-                "imported: `" +
-                toString(*sym) + "`");
-        }
-        break;
       case R_WASM_TABLE_INDEX_I32:
       case R_WASM_TABLE_INDEX_I64:
       case R_WASM_MEMORY_ADDR_I32:

diff  --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 09b5badb9c07c..fd13b70f8c6da 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -205,6 +205,8 @@ bool Symbol::isHidden() const {
   return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
 }
 
+bool Symbol::isTLS() const { return flags & WASM_SYMBOL_TLS; }
+
 void Symbol::setHidden(bool isHidden) {
   LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
   flags &= ~WASM_SYMBOL_VISIBILITY_MASK;

diff  --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index ef2ae7f457af9..415881e0c1982 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -74,6 +74,7 @@ class Symbol {
   bool isLocal() const;
   bool isWeak() const;
   bool isHidden() const;
+  bool isTLS() const;
 
   // Returns true if this symbol exists in a discarded (due to COMDAT) section
   bool isDiscarded() const;

diff  --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 82a2499081fb8..eff5bf5b4213f 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -639,7 +639,7 @@ void Writer::calculateExports() {
     } else if (auto *t = dyn_cast<DefinedTag>(sym)) {
       export_ = {name, WASM_EXTERNAL_TAG, t->getTagIndex()};
     } else if (auto *d = dyn_cast<DefinedData>(sym)) {
-      if (d->segment && d->segment->isTLS()) {
+      if (sym->isTLS()) {
         // We can't currenly export TLS data symbols.
         if (sym->isExportedExplicit())
           error("TLS symbols cannot yet be exported: `" + toString(*sym) + "`");

diff  --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index c38e64928521f..1d0eb7009c7cc 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -379,6 +379,7 @@ const unsigned WASM_SYMBOL_UNDEFINED = 0x10;
 const unsigned WASM_SYMBOL_EXPORTED = 0x20;
 const unsigned WASM_SYMBOL_EXPLICIT_NAME = 0x40;
 const unsigned WASM_SYMBOL_NO_STRIP = 0x80;
+const unsigned WASM_SYMBOL_TLS = 0x100;
 
 #define WASM_RELOC(name, value) name = value,
 

diff  --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h
index 852ab678e6165..7feffb4a6929f 100644
--- a/llvm/include/llvm/MC/MCSymbolWasm.h
+++ b/llvm/include/llvm/MC/MCSymbolWasm.h
@@ -67,6 +67,11 @@ class MCSymbolWasm : public MCSymbol {
     modifyFlags(wasm::WASM_SYMBOL_NO_STRIP, wasm::WASM_SYMBOL_NO_STRIP);
   }
 
+  bool isTLS() const { return getFlags() & wasm::WASM_SYMBOL_TLS; }
+  void setTLS() const {
+    modifyFlags(wasm::WASM_SYMBOL_TLS, wasm::WASM_SYMBOL_TLS);
+  }
+
   bool isWeak() const { return IsWeak; }
   void setWeak(bool isWeak) { IsWeak = isWeak; }
 

diff  --git a/llvm/include/llvm/MC/MCWasmStreamer.h b/llvm/include/llvm/MC/MCWasmStreamer.h
index 6651f071f799d..818f59e5ab3e5 100644
--- a/llvm/include/llvm/MC/MCWasmStreamer.h
+++ b/llvm/include/llvm/MC/MCWasmStreamer.h
@@ -41,6 +41,9 @@ class MCWasmStreamer : public MCObjectStreamer {
   /// @{
 
   void changeSection(MCSection *Section, const MCExpr *Subsection) override;
+  void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
+  void emitLabelAtPos(MCSymbol *Symbol, SMLoc Loc, MCFragment *F,
+                      uint64_t Offset) override;
   void emitAssemblerFlag(MCAssemblerFlag Flag) override;
   void emitThumbFunc(MCSymbol *Func) override;
   void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
@@ -68,6 +71,8 @@ class MCWasmStreamer : public MCObjectStreamer {
   void emitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &) override;
   void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override;
 
+  void fixSymbolsInTLSFixups(const MCExpr *expr);
+
   /// Merge the content of the fragment \p EF into the fragment \p DF.
   void mergeFragment(MCDataFragment *, MCDataFragment *);
 

diff  --git a/llvm/lib/MC/MCWasmStreamer.cpp b/llvm/lib/MC/MCWasmStreamer.cpp
index e3d2439cef817..47951bd5e8726 100644
--- a/llvm/lib/MC/MCWasmStreamer.cpp
+++ b/llvm/lib/MC/MCWasmStreamer.cpp
@@ -49,6 +49,27 @@ void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) {
   DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
 }
 
+void MCWasmStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
+  auto *Symbol = cast<MCSymbolWasm>(S);
+  MCObjectStreamer::emitLabel(Symbol, Loc);
+
+  const MCSectionWasm &Section =
+      static_cast<const MCSectionWasm &>(*getCurrentSectionOnly());
+  if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS)
+    Symbol->setTLS();
+}
+
+void MCWasmStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment *F,
+                                    uint64_t Offset) {
+  auto *Symbol = cast<MCSymbolWasm>(S);
+  MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset);
+
+  const MCSectionWasm &Section =
+      static_cast<const MCSectionWasm &>(*getCurrentSectionOnly());
+  if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS)
+    Symbol->setTLS();
+}
+
 void MCWasmStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) {
   // Let the target do whatever target specific stuff it needs to do.
   getAssembler().getBackend().handleAssemblerFlag(Flag);
@@ -117,6 +138,10 @@ bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
     Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
     break;
 
+  case MCSA_ELF_TypeTLS:
+    Symbol->setTLS();
+    break;
+
   case MCSA_ELF_TypeObject:
   case MCSA_Cold:
     break;
@@ -156,6 +181,10 @@ void MCWasmStreamer::emitIdent(StringRef IdentString) {
 void MCWasmStreamer::emitInstToFragment(const MCInst &Inst,
                                         const MCSubtargetInfo &STI) {
   this->MCObjectStreamer::emitInstToFragment(Inst, STI);
+  MCRelaxableFragment &F = *cast<MCRelaxableFragment>(getCurrentFragment());
+
+  for (auto &Fixup : F.getFixups())
+    fixSymbolsInTLSFixups(Fixup.getValue());
 }
 
 void MCWasmStreamer::emitInstToData(const MCInst &Inst,
@@ -166,6 +195,9 @@ void MCWasmStreamer::emitInstToData(const MCInst &Inst,
   raw_svector_ostream VecOS(Code);
   Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
 
+  for (auto &Fixup : Fixups)
+    fixSymbolsInTLSFixups(Fixup.getValue());
+
   // Append the encoded instruction to the current data fragment (or create a
   // new such fragment if the current fragment is not a data fragment).
   MCDataFragment *DF = getOrCreateDataFragment();
@@ -185,16 +217,32 @@ void MCWasmStreamer::finishImpl() {
   this->MCObjectStreamer::finishImpl();
 }
 
-MCStreamer *llvm::createWasmStreamer(MCContext &Context,
-                                     std::unique_ptr<MCAsmBackend> &&MAB,
-                                     std::unique_ptr<MCObjectWriter> &&OW,
-                                     std::unique_ptr<MCCodeEmitter> &&CE,
-                                     bool RelaxAll) {
-  MCWasmStreamer *S =
-      new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));
-  if (RelaxAll)
-    S->getAssembler().setRelaxAll(true);
-  return S;
+void MCWasmStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) {
+  switch (expr->getKind()) {
+  case MCExpr::Target:
+  case MCExpr::Constant:
+    break;
+
+  case MCExpr::Binary: {
+    const MCBinaryExpr *be = cast<MCBinaryExpr>(expr);
+    fixSymbolsInTLSFixups(be->getLHS());
+    fixSymbolsInTLSFixups(be->getRHS());
+    break;
+  }
+
+  case MCExpr::SymbolRef: {
+    const MCSymbolRefExpr &symRef = *cast<MCSymbolRefExpr>(expr);
+    if (symRef.getKind() == MCSymbolRefExpr::VK_WASM_TLSREL) {
+      getAssembler().registerSymbol(symRef.getSymbol());
+      cast<MCSymbolWasm>(symRef.getSymbol()).setTLS();
+    }
+    break;
+  }
+
+  case MCExpr::Unary:
+    fixSymbolsInTLSFixups(cast<MCUnaryExpr>(expr)->getSubExpr());
+    break;
+  }
 }
 
 void MCWasmStreamer::emitThumbFunc(MCSymbol *Func) {
@@ -215,3 +263,15 @@ void MCWasmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
                                     uint64_t Size, unsigned ByteAlignment) {
   llvm_unreachable("Wasm doesn't support this directive");
 }
+
+MCStreamer *llvm::createWasmStreamer(MCContext &Context,
+                                     std::unique_ptr<MCAsmBackend> &&MAB,
+                                     std::unique_ptr<MCObjectWriter> &&OW,
+                                     std::unique_ptr<MCCodeEmitter> &&CE,
+                                     bool RelaxAll) {
+  MCWasmStreamer *S =
+      new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));
+  if (RelaxAll)
+    S->getAssembler().setRelaxAll(true);
+  return S;
+}

diff  --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 7da5e1534bf15..2d16c3747180f 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -1748,6 +1748,8 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
       Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
     if (WS.hasExportName())
       Flags |= wasm::WASM_SYMBOL_EXPORTED;
+    if (WS.isTLS())
+      Flags |= wasm::WASM_SYMBOL_TLS;
 
     wasm::WasmSymbolInfo Info;
     Info.Name = WS.getName();

diff  --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp
index 752654ddbbaf1..365f63cce9bc3 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -561,6 +561,7 @@ void ScalarBitSetTraits<WasmYAML::SymbolFlags>::bitset(
   BCaseMask(EXPORTED, EXPORTED);
   BCaseMask(EXPLICIT_NAME, EXPLICIT_NAME);
   BCaseMask(NO_STRIP, NO_STRIP);
+  BCaseMask(TLS, TLS);
 #undef BCaseMask
 }
 

diff  --git a/llvm/test/MC/WebAssembly/tls.s b/llvm/test/MC/WebAssembly/tls.s
index 542273c339c30..fc7c7c1b28b4d 100644
--- a/llvm/test/MC/WebAssembly/tls.s
+++ b/llvm/test/MC/WebAssembly/tls.s
@@ -18,6 +18,11 @@ tls_store:
   i32.store 0
   end_function
 
+tls_get_undefined:
+  .functype tls_get_undefined (i32) -> (i32)
+  i32.const tls_undefined at TLSREL
+  end_function
+
 .section .tls.foo,"T",@
 # CHECK: .tls.foo,"T",@
 tls1:
@@ -56,13 +61,22 @@ tls2:
 # CHECK-OBJ-NEXT:      - Index:           2
 # CHECK-OBJ-NEXT:        Kind:            DATA
 # CHECK-OBJ-NEXT:        Name:            tls1
-# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL ]
+# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL, TLS ]
 # CHECK-OBJ-NEXT:        Segment:         0
 # CHECK-OBJ-NEXT:        Size:            4
 # CHECK-OBJ-NEXT:      - Index:           3
+# CHECK-OBJ-NEXT:        Kind:            FUNCTION
+# CHECK-OBJ-NEXT:        Name:            tls_get_undefined
+# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL ]
+# CHECK-OBJ-NEXT:        Function:        1
+# CHECK-OBJ-NEXT:      - Index:           4
+# CHECK-OBJ-NEXT:        Kind:            DATA
+# CHECK-OBJ-NEXT:        Name:            tls_undefined
+# CHECK-OBJ-NEXT:        Flags:           [ UNDEFINED, TLS ]
+# CHECK-OBJ-NEXT:      - Index:           5
 # CHECK-OBJ-NEXT:        Kind:            DATA
 # CHECK-OBJ-NEXT:        Name:            tls2
-# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL ]
+# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL, TLS ]
 # CHECK-OBJ-NEXT:        Segment:         1
 # CHECK-OBJ-NEXT:        Size:            4
 # CHECK-OBJ-NEXT:    SegmentInfo:

diff  --git a/llvm/test/MC/WebAssembly/tls64.s b/llvm/test/MC/WebAssembly/tls64.s
index f066fd29424e2..9d6dd5a0f729a 100644
--- a/llvm/test/MC/WebAssembly/tls64.s
+++ b/llvm/test/MC/WebAssembly/tls64.s
@@ -56,13 +56,13 @@ tls2:
 # CHECK-OBJ-NEXT:      - Index:           2
 # CHECK-OBJ-NEXT:        Kind:            DATA
 # CHECK-OBJ-NEXT:        Name:            tls1
-# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL ]
+# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL, TLS ]
 # CHECK-OBJ-NEXT:        Segment:         0
 # CHECK-OBJ-NEXT:        Size:            4
 # CHECK-OBJ-NEXT:      - Index:           3
 # CHECK-OBJ-NEXT:        Kind:            DATA
 # CHECK-OBJ-NEXT:        Name:            tls2
-# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL ]
+# CHECK-OBJ-NEXT:        Flags:           [ BINDING_LOCAL, TLS ]
 # CHECK-OBJ-NEXT:        Segment:         1
 # CHECK-OBJ-NEXT:        Size:            4
 # CHECK-OBJ-NEXT:    SegmentInfo:


        


More information about the llvm-commits mailing list