diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 0188f0971a754..c7d4de7006054 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -234,6 +234,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); @@ -260,6 +261,7 @@ class Writer { DelayLoadContents delayIdata; EdataContents edata; bool setNoSEHCharacteristic = false; + uint32_t tlsAlignment = 0; DebugDirectoryChunk *debugDirectory = nullptr; std::vector> debugRecords; @@ -628,6 +630,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) { @@ -848,6 +855,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); @@ -1993,3 +2004,33 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { return it->second; return nullptr; } + +void Writer::fixTlsAlignment() { + Defined *tlsSym = + dyn_cast_or_null(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(&secBuf[tlsOffset]); + tlsDir->setAlignment(tlsAlignment); + } else { + object::coff_tls_directory32 *tlsDir = + reinterpret_cast(&secBuf[tlsOffset]); + tlsDir->setAlignment(tlsAlignment); + } +} diff --git a/lld/test/COFF/Inputs/tlssup-32.ll b/lld/test/COFF/Inputs/tlssup-32.ll new file mode 100644 index 0000000000000..e49cde4969e51 --- /dev/null +++ b/lld/test/COFF/Inputs/tlssup-32.ll @@ -0,0 +1,31 @@ +; We manually create these here if we're not linking against +; the CRT which would usually provide these. + +target triple = "i686-pc-windows-msvc" + +%IMAGE_TLS_DIRECTORY32 = type { + i32, ; StartAddressOfRawData + i32, ; EndAddressOfRawData + i32, ; AddressOfIndex + i32, ; AddressOfCallBacks + i32, ; SizeOfZeroFill + i32 ; Characteristics +} + +@_tls_start = global i8 zeroinitializer, section ".tls" +@_tls_end = global i8 zeroinitializer, section ".tls$ZZZ" +@_tls_index = global i32 0 + +@_tls_used = global %IMAGE_TLS_DIRECTORY32 { + i32 ptrtoint (i8* @_tls_start to i32), + i32 ptrtoint (i8* @_tls_end to i32), + i32 ptrtoint (i32* @_tls_index to i32), + i32 0, + i32 0, + i32 0 +}, section ".rdata$T" + +; MSVC target uses a direct offset (0x58) for x86-64 but expects +; __tls_array to hold the offset (0x2C) on x86. +module asm ".global __tls_array" +module asm "__tls_array = 44" \ No newline at end of file diff --git a/lld/test/COFF/Inputs/tlssup-64.ll b/lld/test/COFF/Inputs/tlssup-64.ll new file mode 100644 index 0000000000000..aadcf989a2def --- /dev/null +++ b/lld/test/COFF/Inputs/tlssup-64.ll @@ -0,0 +1,26 @@ +; We manually create these here if we're not linking against +; the CRT which would usually provide these. + +target triple = "x86_64-pc-windows-msvc" + +%IMAGE_TLS_DIRECTORY64 = type { + i64, ; StartAddressOfRawData + i64, ; EndAddressOfRawData + i64, ; AddressOfIndex + i64, ; AddressOfCallBacks + i32, ; SizeOfZeroFill + i32 ; Characteristics +} + +@_tls_start = global i8 zeroinitializer, section ".tls" +@_tls_end = global i8 zeroinitializer, section ".tls$ZZZ" +@_tls_index = global i64 0 + +@_tls_used = global %IMAGE_TLS_DIRECTORY64 { + i64 ptrtoint (i8* @_tls_start to i64), + i64 ptrtoint (i8* @_tls_end to i64), + i64 ptrtoint (i64* @_tls_index to i64), + i64 0, + i32 0, + i32 0 +}, section ".rdata$T" \ No newline at end of file diff --git a/lld/test/COFF/tls-alignment-32.ll b/lld/test/COFF/tls-alignment-32.ll new file mode 100644 index 0000000000000..0f12498afcfc2 --- /dev/null +++ b/lld/test/COFF/tls-alignment-32.ll @@ -0,0 +1,24 @@ +; This test is to make sure that the necessary alignment for thread locals +; gets reflected in the TLS Directory of the generated executable on x86. +; +; aligned_thread_local specifies 'align 32' and so the generated +; exe should reflect that with a value of IMAGE_SCN_ALIGN_32BYTES +; in the Characteristics field of the IMAGE_TLS_DIRECTORY + +; RUN: llc -filetype=obj %S/Inputs/tlssup-32.ll -o %t.tlssup.obj +; RUN: llc -filetype=obj %s -o %t.obj +; RUN: lld-link %t.tlssup.obj %t.obj -entry:main -nodefaultlib -out:%t.exe +; RUN: llvm-readobj --coff-tls-directory %t.exe | FileCheck %s + +; CHECK: TLSDirectory { +; CHECK: Characteristics [ (0x600000) +; CHECK-NEXT: IMAGE_SCN_ALIGN_32BYTES (0x600000) + +target triple = "i686-pc-windows-msvc" + +@aligned_thread_local = thread_local global i32 42, align 32 + +define i32 @main() { + %t = load i32, i32* @aligned_thread_local + ret i32 %t +} diff --git a/lld/test/COFF/tls-alignment-64.ll b/lld/test/COFF/tls-alignment-64.ll new file mode 100644 index 0000000000000..4c5c691b57131 --- /dev/null +++ b/lld/test/COFF/tls-alignment-64.ll @@ -0,0 +1,24 @@ +; This test is to make sure that the necessary alignment for thread locals +; gets reflected in the TLS Directory of the generated executable on x86-64. +; +; aligned_thread_local specifies 'align 64' and so the generated +; exe should reflect that with a value of IMAGE_SCN_ALIGN_64BYTES +; in the Characteristics field of the IMAGE_TLS_DIRECTORY + +; RUN: llc -filetype=obj %S/Inputs/tlssup-64.ll -o %t.tlssup.obj +; RUN: llc -filetype=obj %s -o %t.obj +; RUN: lld-link %t.tlssup.obj %t.obj -entry:main -nodefaultlib -out:%t.exe +; RUN: llvm-readobj --coff-tls-directory %t.exe | FileCheck %s + +; CHECK: TLSDirectory { +; CHECK: Characteristics [ (0x700000) +; CHECK-NEXT: IMAGE_SCN_ALIGN_64BYTES (0x700000) + +target triple = "x86_64-pc-windows-msvc" + +@aligned_thread_local = thread_local global i32 42, align 64 + +define i32 @main() { + %t = load i32, i32* @aligned_thread_local + ret i32 %t +} diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst index 51cd266ff79e0..5032163add085 100644 --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -286,6 +286,10 @@ The following options are implemented only for the PE/COFF file format. Display the debug directory. +.. option:: --coff-tls-directory + + Display the TLS directory. + .. option:: --coff-directives Display the .drectve section. diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h index 1919d7f0dece9..716d649f7c51c 100644 --- a/llvm/include/llvm/BinaryFormat/COFF.h +++ b/llvm/include/llvm/BinaryFormat/COFF.h @@ -311,6 +311,7 @@ enum SectionCharacteristics : uint32_t { IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000, IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000, IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000, + IMAGE_SCN_ALIGN_MASK = 0x00F00000, IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000, IMAGE_SCN_MEM_DISCARDABLE = 0x02000000, IMAGE_SCN_MEM_NOT_CACHED = 0x04000000, diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h index 8aef00a8809dc..e7cf1b5495c66 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; @@ -786,6 +797,8 @@ class COFFObjectFile : public ObjectFile { const coff_base_reloc_block_header *BaseRelocEnd; const debug_directory *DebugDirectoryBegin; const debug_directory *DebugDirectoryEnd; + const coff_tls_directory32 *TLSDirectory32; + const coff_tls_directory64 *TLSDirectory64; // Either coff_load_configuration32 or coff_load_configuration64. const void *LoadConfig = nullptr; @@ -805,6 +818,7 @@ class COFFObjectFile : public ObjectFile { Error initExportTablePtr(); Error initBaseRelocPtr(); Error initDebugDirectoryPtr(); + Error initTLSDirectoryPtr(); Error initLoadConfigPtr(); public: @@ -976,6 +990,13 @@ class COFFObjectFile : public ObjectFile { return make_range(debug_directory_begin(), debug_directory_end()); } + const coff_tls_directory32 *getTLSDirectory32() const { + return TLSDirectory32; + } + const coff_tls_directory64 *getTLSDirectory64() const { + return TLSDirectory64; + } + const dos_header *getDOSHeader() const { if (!PE32Header && !PE32PlusHeader) return nullptr; diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp index c26d7721b3fe9..cd10e67af239e 100644 --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/lib/Object/COFFObjectFile.cpp @@ -649,6 +649,38 @@ Error COFFObjectFile::initDebugDirectoryPtr() { return Error::success(); } +Error COFFObjectFile::initTLSDirectoryPtr() { + // Get the RVA of the TLS directory. Do nothing if it does not exist. + const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE); + if (!DataEntry) + return Error::success(); + + // Do nothing if the RVA is NULL. + if (DataEntry->RelativeVirtualAddress == 0) + return Error::success(); + + uint64_t DirSize = + is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32); + + // Check that the size is correct. + if (DataEntry->Size != DirSize) + return createStringError( + object_error::parse_failed, + "TLS Directory size (%u) is not the expected size (%u).", + static_cast(DataEntry->Size), DirSize); + + uintptr_t IntPtr = 0; + if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + return E; + + if (is64()) + TLSDirectory64 = reinterpret_cast(IntPtr); + else + TLSDirectory32 = reinterpret_cast(IntPtr); + + return Error::success(); +} + Error COFFObjectFile::initLoadConfigPtr() { // Get the RVA of the debug directory. Do nothing if it does not exist. const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE); @@ -682,7 +714,8 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object) ImportDirectory(nullptr), DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0), ExportDirectory(nullptr), BaseRelocHeader(nullptr), BaseRelocEnd(nullptr), - DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr) {} + DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr), + TLSDirectory32(nullptr), TLSDirectory64(nullptr) {} Error COFFObjectFile::initialize() { // Check that we at least have enough room for a header. @@ -809,10 +842,14 @@ Error COFFObjectFile::initialize() { if (Error E = initBaseRelocPtr()) return E; - // Initialize the pointer to the export table. + // Initialize the pointer to the debug directory. if (Error E = initDebugDirectoryPtr()) return E; + // Initialize the pointer to the TLS directory. + if (Error E = initTLSDirectoryPtr()) + return E; + if (Error E = initLoadConfigPtr()) return E; diff --git a/llvm/test/tools/llvm-readobj/COFF/tls-directory.test b/llvm/test/tools/llvm-readobj/COFF/tls-directory.test new file mode 100644 index 0000000000000..d553130e0a017 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/tls-directory.test @@ -0,0 +1,162 @@ +## Tests for the --coff-tls-directory flag. + +## Test that the output of --coff-tls-directory works on x86. +## The binary created from this yaml definition is such that .rdata contains +## only the IMAGE_TLS_DIRECTORY structure and hence we should have that +## TlsTable.RelativeVirtualAddress == .rdata section VirtualAddress. +## Also note that the .rdata section VirtualSize == sizeof(coff_tls_directory32) == sizeof(IMAGE_TLS_DIRECTORY32) == 24 + +# RUN: yaml2obj %s --docnum=1 -o %t.32.exe -DTLSRVA=10000 -DTLSSIZE=24 +# RUN: llvm-readobj --coff-tls-directory %t.32.exe | FileCheck %s --check-prefix I386 + +# I386: Arch: i386 +# I386-NEXT: AddressSize: 32bit +# I386-NEXT: TLSDirectory { +# I386-NEXT: StartAddressOfRawData: 0x404000 +# I386-NEXT: EndAddressOfRawData: 0x404008 +# I386-NEXT: AddressOfIndex: 0x402000 +# I386-NEXT: AddressOfCallBacks: 0x0 +# I386-NEXT: SizeOfZeroFill: 0x0 +# I386-NEXT: Characteristics [ (0x300000) +# I386-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000) +# I386-NEXT: ] +# I386-NEXT: } + + +## Test that the output of --coff-tls-directory errors on malformed input. +## On x86, the TLS directory should be 24 bytes. +## This test has a truncated TLS directory. + +# RUN: yaml2obj %s --docnum=1 -o %t.wrong-size.32.exe -DTLSRVA=10000 -DTLSSIZE=10 +# RUN: not llvm-readobj --coff-tls-directory %t.wrong-size.32.exe 2>&1 | FileCheck %s --check-prefix I386-WRONG-SIZE-ERR + +# I386-WRONG-SIZE-ERR: error: '{{.*}}': TLS Directory size (10) is not the expected size (24). + +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 0 + ImageBase: 0 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 0 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 0 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [] + SizeOfStackReserve: 0 + SizeOfStackCommit: 0 + SizeOfHeapReserve: 0 + SizeOfHeapCommit: 0 + TlsTable: + RelativeVirtualAddress: [[TLSRVA]] + Size: [[TLSSIZE]] +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE ] +sections: + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 10000 + VirtualSize: 24 + SectionData: '004040000840400000204000000000000000000000003000' +symbols: [] + + +## Test that the output of --coff-tls-directory works on x86_64. +## The binary created from this yaml definition is such that .rdata contains +## only the IMAGE_TLS_DIRECTORY structure and hence we should have that +## TlsTable.RelativeVirtualAddress == .rdata section VirtualAddress. +## Also note that the .rdata section VirtualSize == sizeof(coff_tls_directory64) == sizeof(IMAGE_TLS_DIRECTORY64) == 40 + +# RUN: yaml2obj %s --docnum=2 -o %t.64.exe -DTLSRVA=10000 -DTLSSIZE=40 +# RUN: llvm-readobj --coff-tls-directory %t.64.exe | FileCheck %s --check-prefix X86-64 + +# X86-64: Arch: x86_64 +# X86-64-NEXT: AddressSize: 64bit +# X86-64-NEXT: TLSDirectory { +# X86-64-NEXT: StartAddressOfRawData: 0x140004000 +# X86-64-NEXT: EndAddressOfRawData: 0x140004008 +# X86-64-NEXT: AddressOfIndex: 0x140002000 +# X86-64-NEXT: AddressOfCallBacks: 0x0 +# X86-64-NEXT: SizeOfZeroFill: 0x0 +# X86-64-NEXT: Characteristics [ (0x300000) +# X86-64-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000) +# X86-64-NEXT: ] +# X86-64-NEXT: } + + +## Test that the output of --coff-tls-directory errors on malformed input. + +## On x86-64, the TLS directory should be 40 bytes. +## This test has an erroneously lengthened TLS directory. + +# RUN: yaml2obj %s --docnum=2 -o %t.wrong-size.64.exe -DTLSRVA=10000 -DTLSSIZE=80 +# RUN: not llvm-readobj --coff-tls-directory %t.wrong-size.64.exe 2>&1 | FileCheck %s --check-prefix X86-64-WRONG-SIZE-ERR + +# X86-64-WRONG-SIZE-ERR: error: '{{.*}}': TLS Directory size (80) is not the expected size (40). + + +## This test has a correct TLS Directory size but the RVA is invalid. + +# RUN: yaml2obj %s --docnum=2 -o %t.bad-tls-rva.exe -DTLSRVA=999999 -DTLSSIZE=40 +# RUN: not llvm-readobj --coff-tls-directory %t.bad-tls-rva.exe 2>&1 | FileCheck %s --check-prefix BAD-TLS-RVA-ERR + +# BAD-TLS-RVA-ERR: error: '{{.*}}': Invalid data was encountered while parsing the file + +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 0 + ImageBase: 0 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 0 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 0 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [] + SizeOfStackReserve: 0 + SizeOfStackCommit: 0 + SizeOfHeapReserve: 0 + SizeOfHeapCommit: 0 + TlsTable: + RelativeVirtualAddress: [[TLSRVA]] + Size: [[TLSSIZE]] +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ] +sections: + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + VirtualAddress: 10000 + VirtualSize: 40 + SectionData: '00400040010000000840004001000000002000400100000000000000000000000000000000003000' +symbols: [] + + +## Test that --coff-tls-directory doesn't output anything if there's no TLS directory. + +## Case 1: TlsTable.RelativeVirtualAddress/Size = 0. + +# RUN: yaml2obj %s --docnum=2 -o %t.no-tls1.exe -DTLSRVA=0 -DTLSSIZE=0 +# RUN: llvm-readobj --coff-tls-directory %t.no-tls1.exe | FileCheck %s --check-prefix NO-TLS + +## Case 2: There's no TlsTable listed in the COFF header. + +# RUN: yaml2obj %s --docnum=3 -o %t.no-tls2.exe +# RUN: llvm-readobj --coff-tls-directory %t.no-tls2.exe | FileCheck %s --check-prefix NO-TLS + +# NO-TLS: TLSDirectory { +# NO-TLS-NEXT: } + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ] +sections: [] +symbols: [] diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index 89a904f53ae7d..57162fd38a541 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -94,6 +94,7 @@ class COFFDumper : public ObjDumper { void printCOFFDirectives() override; void printCOFFBaseReloc() override; void printCOFFDebugDirectory() override; + void printCOFFTLSDirectory() override; void printCOFFResources() override; void printCOFFLoadConfig() override; void printCodeViewDebugInfo() override; @@ -121,6 +122,8 @@ class COFFDumper : public ObjDumper { void printBaseOfDataField(const pe32plus_header *Hdr); template void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables); + template + void printCOFFTLSDirectory(const coff_tls_directory *TlsTable); typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *); void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize, PrintExtraCB PrintExtra = 0); @@ -2029,3 +2032,27 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer, Writer.flush(); } } + +void COFFDumper::printCOFFTLSDirectory() { + if (Obj->is64()) + printCOFFTLSDirectory(Obj->getTLSDirectory64()); + else + printCOFFTLSDirectory(Obj->getTLSDirectory32()); +} + +template +void COFFDumper::printCOFFTLSDirectory( + const coff_tls_directory *TlsTable) { + DictScope D(W, "TLSDirectory"); + if (!TlsTable) + return; + + W.printHex("StartAddressOfRawData", TlsTable->StartAddressOfRawData); + W.printHex("EndAddressOfRawData", TlsTable->EndAddressOfRawData); + W.printHex("AddressOfIndex", TlsTable->AddressOfIndex); + W.printHex("AddressOfCallBacks", TlsTable->AddressOfCallBacks); + W.printHex("SizeOfZeroFill", TlsTable->SizeOfZeroFill); + W.printFlags("Characteristics", TlsTable->Characteristics, + makeArrayRef(ImageSectionCharacteristics), + COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK)); +} diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h index 57477606d6e8e..72f8497c8299f 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -78,6 +78,7 @@ class ObjDumper { virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } virtual void printCOFFDebugDirectory() { } + virtual void printCOFFTLSDirectory() {} virtual void printCOFFResources() {} virtual void printCOFFLoadConfig() { } virtual void printCodeViewDebugInfo() { } diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index b9c6ad2256ae2..4d1a494eeb8f3 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -265,6 +265,10 @@ namespace opts { COFFDebugDirectory("coff-debug-directory", cl::desc("Display the PE/COFF debug directory")); + // --coff-tls-directory + cl::opt COFFTLSDirectory("coff-tls-directory", + cl::desc("Display the PE/COFF TLS directory")); + // --coff-resources cl::opt COFFResources("coff-resources", cl::desc("Display the PE/COFF .rsrc section")); @@ -524,6 +528,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, Dumper->printCOFFBaseReloc(); if (opts::COFFDebugDirectory) Dumper->printCOFFDebugDirectory(); + if (opts::COFFTLSDirectory) + Dumper->printCOFFTLSDirectory(); if (opts::COFFResources) Dumper->printCOFFResources(); if (opts::COFFLoadConfig)