[llvm] 6a73d65 - [LLD] Set alignment as part of Characteristics in TLS table.

Luqman Aden via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 15 00:26:39 PDT 2020


Author: Luqman Aden
Date: 2020-10-15T00:22:40-07:00
New Revision: 6a73d6564a3c7d0757692aa93bdef5be0c8f01a5

URL: https://github.com/llvm/llvm-project/commit/6a73d6564a3c7d0757692aa93bdef5be0c8f01a5
DIFF: https://github.com/llvm/llvm-project/commit/6a73d6564a3c7d0757692aa93bdef5be0c8f01a5.diff

LOG: [LLD] Set alignment as part of Characteristics in TLS table.

Fixes https://bugs.llvm.org/show_bug.cgi?id=46473

LLD wasn't previously specifying any specific alignment in the TLS table's Characteristics field so the loader would just assume the default value (16 bytes). This works most of the time except if you have thread locals that want specific higher alignments (e.g. 32 as in the bug) *even* if they specify an alignment on the thread local. This change updates LLD to take the max alignment from tls section.

Reviewed By: rnk

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

Added: 
    

Modified: 
    lld/COFF/Writer.cpp
    lld/test/COFF/tls-alignment-32.ll
    lld/test/COFF/tls-alignment-64.ll
    llvm/include/llvm/Object/COFF.h

Removed: 
    


################################################################################
diff  --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index c13cd34f2ddc..534ea82dc3c2 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -241,6 +241,7 @@ class Writer {
   void addSyntheticIdata();
   void fixPartialSectionChars(StringRef name, uint32_t chars);
   bool fixGnuImportChunks();
+  void fixTlsAlignment();
   PartialSection *createPartialSection(StringRef name, uint32_t outChars);
   PartialSection *findPartialSection(StringRef name, uint32_t outChars);
 
@@ -267,6 +268,7 @@ class Writer {
   DelayLoadContents delayIdata;
   EdataContents edata;
   bool setNoSEHCharacteristic = false;
+  uint32_t tlsAlignment = 0;
 
   DebugDirectoryChunk *debugDirectory = nullptr;
   std::vector<std::pair<COFF::DebugType, Chunk *>> debugRecords;
@@ -633,6 +635,11 @@ void Writer::run() {
   writeSections();
   sortExceptionTable();
 
+  // Fix up the alignment in the TLS Directory's characteristic field,
+  // if a specific alignment value is needed
+  if (tlsAlignment)
+    fixTlsAlignment();
+
   t1.stop();
 
   if (!config->pdbPath.empty() && config->debug) {
@@ -866,6 +873,10 @@ void Writer::createSections() {
     StringRef name = c->getSectionName();
     if (shouldStripSectionSuffix(sc, name))
       name = name.split('$').first;
+
+    if (name.startswith(".tls"))
+      tlsAlignment = std::max(tlsAlignment, c->getAlignment());
+
     PartialSection *pSec = createPartialSection(name,
                                                 c->getOutputCharacteristics());
     pSec->chunks.push_back(c);
@@ -2038,3 +2049,33 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
     return it->second;
   return nullptr;
 }
+
+void Writer::fixTlsAlignment() {
+  Defined *tlsSym =
+      dyn_cast_or_null<Defined>(symtab->findUnderscore("_tls_used"));
+  if (!tlsSym)
+    return;
+
+  OutputSection *sec = tlsSym->getChunk()->getOutputSection();
+  assert(sec && tlsSym->getRVA() >= sec->getRVA() &&
+         "no output section for _tls_used");
+
+  uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
+  uint64_t tlsOffset = tlsSym->getRVA() - sec->getRVA();
+  uint64_t directorySize = config->is64()
+                               ? sizeof(object::coff_tls_directory64)
+                               : sizeof(object::coff_tls_directory32);
+
+  if (tlsOffset + directorySize > sec->getRawSize())
+    fatal("_tls_used sym is malformed");
+
+  if (config->is64()) {
+    object::coff_tls_directory64 *tlsDir =
+        reinterpret_cast<object::coff_tls_directory64 *>(&secBuf[tlsOffset]);
+    tlsDir->setAlignment(tlsAlignment);
+  } else {
+    object::coff_tls_directory32 *tlsDir =
+        reinterpret_cast<object::coff_tls_directory32 *>(&secBuf[tlsOffset]);
+    tlsDir->setAlignment(tlsAlignment);
+  }
+}

diff  --git a/lld/test/COFF/tls-alignment-32.ll b/lld/test/COFF/tls-alignment-32.ll
index bf9df5ca725f..8df11e7fd1c2 100644
--- a/lld/test/COFF/tls-alignment-32.ll
+++ b/lld/test/COFF/tls-alignment-32.ll
@@ -13,7 +13,8 @@
 ; RUN: llvm-readobj --coff-tls-directory %t.exe | FileCheck %s
 
 ; CHECK: TLSDirectory {
-; CHECK: Characteristics [ (0x0)
+; CHECK: Characteristics [ (0x600000)
+; CHECK-NEXT: IMAGE_SCN_ALIGN_32BYTES (0x600000)
 
 target triple = "i686-pc-windows-msvc"
 

diff  --git a/lld/test/COFF/tls-alignment-64.ll b/lld/test/COFF/tls-alignment-64.ll
index 056bce97aae0..04813ca0021e 100644
--- a/lld/test/COFF/tls-alignment-64.ll
+++ b/lld/test/COFF/tls-alignment-64.ll
@@ -13,7 +13,8 @@
 ; RUN: llvm-readobj --coff-tls-directory %t.exe | FileCheck %s
 
 ; CHECK: TLSDirectory {
-; CHECK: Characteristics [ (0x0)
+; CHECK: Characteristics [ (0x700000)
+; CHECK-NEXT: IMAGE_SCN_ALIGN_64BYTES (0x700000)
 
 target triple = "x86_64-pc-windows-msvc"
 

diff  --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h
index 505aab8bff5b..e7cf1b5495c6 100644
--- a/llvm/include/llvm/Object/COFF.h
+++ b/llvm/include/llvm/Object/COFF.h
@@ -576,11 +576,22 @@ struct coff_tls_directory {
 
   uint32_t getAlignment() const {
     // Bit [20:24] contains section alignment.
-    uint32_t Shift = (Characteristics & 0x00F00000) >> 20;
+    uint32_t Shift = (Characteristics & COFF::IMAGE_SCN_ALIGN_MASK) >> 20;
     if (Shift > 0)
       return 1U << (Shift - 1);
     return 0;
   }
+
+  void setAlignment(uint32_t Align) {
+    uint32_t AlignBits = 0;
+    if (Align) {
+      assert(llvm::isPowerOf2_32(Align) && "alignment is not a power of 2");
+      assert(llvm::Log2_32(Align) <= 13 && "alignment requested is too large");
+      AlignBits = (llvm::Log2_32(Align) + 1) << 20;
+    }
+    Characteristics =
+        (Characteristics & ~COFF::IMAGE_SCN_ALIGN_MASK) | AlignBits;
+  }
 };
 
 using coff_tls_directory32 = coff_tls_directory<support::little32_t>;


        


More information about the llvm-commits mailing list