[llvm] 8b70d52 - [LLD] Set alignment as part of Characteristics in TLS table.

Luqman Aden via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 14 19:37:18 PDT 2020


Author: Luqman Aden
Date: 2020-10-14T19:34:31-07:00
New Revision: 8b70d527d7ec1c8b9e921177119a0d906ffad4f0

URL: https://github.com/llvm/llvm-project/commit/8b70d527d7ec1c8b9e921177119a0d906ffad4f0
DIFF: https://github.com/llvm/llvm-project/commit/8b70d527d7ec1c8b9e921177119a0d906ffad4f0.diff

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

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

Added: 
    

Modified: 
    lld/COFF/Writer.cpp
    llvm/include/llvm/Object/COFF.h

Removed: 
    


################################################################################
diff  --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index c13cd34f2ddc..ba8f502ea81c 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,34 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
     return it->second;
   return nullptr;
 }
+
+void Writer::fixTlsAlignment() {
+  if (Symbol *sym = symtab->findUnderscore("_tls_used")) {
+    if (Defined *b = dyn_cast<Defined>(sym)) {
+      OutputSection *sec = b->getChunk()->getOutputSection();
+      assert(sec && b->getRVA() >= sec->getRVA() &&
+             "no output section for _tls_used");
+
+      uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff();
+      uint64_t tlsOffset = b->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 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);
+      }
+    }
+  }
+}
\ No newline at end of file

diff  --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h
index 505aab8bff5b..649042579c94 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) {
+    if (!align) {
+      Characteristics &= ~COFF::IMAGE_SCN_ALIGN_MASK;
+    } else {
+      assert(llvm::isPowerOf2_32(align) && "alignment is not a power of 2");
+      uint32_t p2Align = llvm::Log2_32(align);
+      assert(p2Align <= 13 && "invalid alignment requested");
+      Characteristics |= (p2Align + 1) << 20;
+    }
+  }
 };
 
 using coff_tls_directory32 = coff_tls_directory<support::little32_t>;


        


More information about the llvm-commits mailing list