From a8febf2283921157da1539c079cd74a55bf89a5a Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Wed, 30 Apr 2014 16:25:02 +0000 Subject: [PATCH] ELFObjectWriter: deduplicate suffices in strtab We already do this for shstrtab, so might as well do it for strtab. This extracts the string table building code into a separate class. The idea is to use it for other object formats too. I mostly wanted to do this for the general principle, but it does save a little bit on object file size. I tried this on a clang bootstrap and saved 0.54% on the sum of object file sizes (1.14 MB out of 212 MB for a release build). Differential Revision: http://reviews.llvm.org/D3533 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207670 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/StringTableBuilder.h | 59 ++++++++++ lib/MC/ELFObjectWriter.cpp | 118 ++++++-------------- lib/Object/CMakeLists.txt | 1 + lib/Object/StringTableBuilder.cpp | 51 +++++++++ test/MC/AArch64/tls-relocs.s | 2 +- test/MC/ARM64/tls-relocs.s | 2 +- test/MC/ELF/comdat.s | 6 +- test/MC/ELF/common.s | 12 +- test/MC/ELF/file-double.s | 8 +- test/MC/ELF/lcomm.s | 4 +- test/MC/ELF/many-sections-2.s | 6 +- test/MC/ELF/pic-diff.s | 2 +- test/MC/ELF/pr9292.s | 4 +- test/MC/ELF/set.s | 4 +- test/MC/ELF/strtab-suffix-opt.s | 21 ++++ test/MC/ELF/tls-i386.s | 28 ++--- test/MC/ELF/tls.s | 14 +-- test/MC/ELF/type.s | 24 ++-- test/MC/ELF/weakref.s | 34 +++--- tools/yaml2obj/yaml2elf.cpp | 6 +- unittests/Object/CMakeLists.txt | 1 + unittests/Object/StringTableBuilderTest.cpp | 40 +++++++ 22 files changed, 282 insertions(+), 165 deletions(-) create mode 100644 include/llvm/Object/StringTableBuilder.h create mode 100644 lib/Object/StringTableBuilder.cpp create mode 100644 test/MC/ELF/strtab-suffix-opt.s create mode 100644 unittests/Object/StringTableBuilderTest.cpp diff --git a/include/llvm/Object/StringTableBuilder.h b/include/llvm/Object/StringTableBuilder.h new file mode 100644 index 00000000000..c61e216bdf9 --- /dev/null +++ b/include/llvm/Object/StringTableBuilder.h @@ -0,0 +1,59 @@ +//===-- StringTableBuilder.h - String table building utility ------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_STRINGTABLE_BUILDER_H +#define LLVM_OBJECT_STRINGTABLE_BUILDER_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include + +namespace llvm { + +/// \brief Utility for building string tables with deduplicated suffixes. +class StringTableBuilder { + SmallString<256> StringTable; + StringMap StringIndexMap; + +public: + /// \brief Add a string to the builder. Returns a StringRef to the internal + /// copy of s. Can only be used before the table is finalized. + StringRef add(StringRef s) { + assert(!isFinalized()); + return StringIndexMap.GetOrCreateValue(s, 0).getKey(); + } + + /// \brief Analyze the strings and build the final table. No more strings can + /// be added after this point. + void finalize(); + + /// \brief Retrieve the string table data. Can only be used after the table + /// is finalized. + StringRef data() { + assert(isFinalized()); + return StringTable; + } + + /// \brief Get the offest of a string in the string table. Can only be used + /// after the table is finalized. + size_t getOffset(StringRef s) { + assert(isFinalized()); + assert(StringIndexMap.count(s) && "String is not in table!"); + return StringIndexMap[s]; + } + +private: + bool isFinalized() { + return !StringTable.empty(); + } +}; + +} // end llvm namespace + +#endif diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 2e07e22dc33..ebcc691f0ae 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCValue.h" +#include "llvm/Object/StringTableBuilder.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" @@ -132,11 +133,11 @@ class ELFObjectWriter : public MCObjectWriter { MCSymbolData *SymbolData; uint64_t StringIndex; uint32_t SectionIndex; + StringRef Name; // Support lexicographic sorting. bool operator<(const ELFSymbolData &RHS) const { - return SymbolData->getSymbol().getName() < - RHS.SymbolData->getSymbol().getName(); + return Name < RHS.Name; } }; @@ -149,13 +150,13 @@ class ELFObjectWriter : public MCObjectWriter { llvm::DenseMap> Relocations; - DenseMap SectionStringTableIndex; + StringTableBuilder ShStrTabBuilder; /// @} /// @name Symbol Table Data /// @{ - SmallString<256> StringTable; + StringTableBuilder StrTabBuilder; std::vector FileSymbolData; std::vector LocalSymbolData; std::vector ExternalSymbolData; @@ -676,7 +677,6 @@ void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, SectionIndexMapTy &SectionIndexMap) { // The string table must be emitted first because we need the index // into the string table for all the symbol names. - assert(StringTable.size() && "Missing string table"); // FIXME: Make sure the start of the symbol table is aligned. @@ -1031,27 +1031,6 @@ ELFObjectWriter::computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, MCELF::SetBinding(Data, ELF::STB_GLOBAL); } - // Index 0 is always the empty string. - StringMap StringIndexMap; - StringTable += '\x00'; - - // FIXME: We could optimize suffixes in strtab in the same way we - // optimize them in shstrtab. - - for (MCAssembler::const_file_name_iterator it = Asm.file_names_begin(), - ie = Asm.file_names_end(); - it != ie; - ++it) { - StringRef Name = *it; - uint64_t &Entry = StringIndexMap[Name]; - if (!Entry) { - Entry = StringTable.size(); - StringTable += Name; - StringTable += '\x00'; - } - FileSymbolData.push_back(Entry); - } - // Add the data for the symbols. for (MCSymbolData &SD : Asm.symbols()) { const MCSymbol &Symbol = SD.getSymbol(); @@ -1102,7 +1081,6 @@ ELFObjectWriter::computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, // @@ in defined ones. StringRef Name = Symbol.getName(); SmallString<32> Buf; - size_t Pos = Name.find("@@@"); if (Pos != StringRef::npos) { Buf += Name.substr(0, Pos); @@ -1110,14 +1088,8 @@ ELFObjectWriter::computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, Buf += Name.substr(Pos + Skip); Name = Buf; } + MSD.Name = StrTabBuilder.add(Name); - uint64_t &Entry = StringIndexMap[Name]; - if (!Entry) { - Entry = StringTable.size(); - StringTable += Name; - StringTable += '\x00'; - } - MSD.StringIndex = Entry; if (MSD.SectionIndex == ELF::SHN_UNDEF) UndefinedSymbolData.push_back(MSD); else if (Local) @@ -1126,6 +1098,21 @@ ELFObjectWriter::computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout, ExternalSymbolData.push_back(MSD); } + for (auto i = Asm.file_names_begin(), e = Asm.file_names_end(); i != e; ++i) + StrTabBuilder.add(*i); + + StrTabBuilder.finalize(); + + for (auto i = Asm.file_names_begin(), e = Asm.file_names_end(); i != e; ++i) + FileSymbolData.push_back(StrTabBuilder.getOffset(*i)); + + for (ELFSymbolData& MSD : LocalSymbolData) + MSD.StringIndex = StrTabBuilder.getOffset(MSD.Name); + for (ELFSymbolData& MSD : ExternalSymbolData) + MSD.StringIndex = StrTabBuilder.getOffset(MSD.Name); + for (ELFSymbolData& MSD : UndefinedSymbolData) + MSD.StringIndex = StrTabBuilder.getOffset(MSD.Name); + // Symbols are required to be in lexicographic order. array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); @@ -1436,23 +1423,6 @@ void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm, } } -static int compareBySuffix(const MCSectionELF *const *a, - const MCSectionELF *const *b) { - const StringRef &NameA = (*a)->getSectionName(); - const StringRef &NameB = (*b)->getSectionName(); - const unsigned sizeA = NameA.size(); - const unsigned sizeB = NameB.size(); - const unsigned len = std::min(sizeA, sizeB); - for (unsigned int i = 0; i < len; ++i) { - char ca = NameA[sizeA - i - 1]; - char cb = NameB[sizeB - i - 1]; - if (ca != cb) - return cb - ca; - } - - return sizeB - sizeA; -} - void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, SectionIndexMapTy &SectionIndexMap, @@ -1493,45 +1463,20 @@ void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, WriteSymbolTable(F, Asm, Layout, SectionIndexMap); F = new MCDataFragment(&StrtabSD); - F->getContents().append(StringTable.begin(), StringTable.end()); + F->getContents().append(StrTabBuilder.data().begin(), + StrTabBuilder.data().end()); F = new MCDataFragment(&ShstrtabSD); - std::vector Sections; - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { + // Section header string table. + for (auto it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionELF &Section = static_cast(it->getSection()); - Sections.push_back(&Section); - } - array_pod_sort(Sections.begin(), Sections.end(), compareBySuffix); - - // Section header string table. - // - // The first entry of a string table holds a null character so skip - // section 0. - uint64_t Index = 1; - F->getContents().push_back('\x00'); - - for (unsigned int I = 0, E = Sections.size(); I != E; ++I) { - const MCSectionELF &Section = *Sections[I]; - - StringRef Name = Section.getSectionName(); - if (I != 0) { - StringRef PreviousName = Sections[I - 1]->getSectionName(); - if (PreviousName.endswith(Name)) { - SectionStringTableIndex[&Section] = Index - Name.size() - 1; - continue; - } - } - // Remember the index into the string table so we can write it - // into the sh_name field of the section header table. - SectionStringTableIndex[&Section] = Index; - - Index += Name.size() + 1; - F->getContents().append(Name.begin(), Name.end()); - F->getContents().push_back('\x00'); + ShStrTabBuilder.add(Section.getSectionName()); } + ShStrTabBuilder.finalize(); + F->getContents().append(ShStrTabBuilder.data().begin(), + ShStrTabBuilder.data().end()); } void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm, @@ -1599,7 +1544,7 @@ void ELFObjectWriter::WriteSection(MCAssembler &Asm, switch(Section.getType()) { case ELF::SHT_DYNAMIC: - sh_link = SectionStringTableIndex[&Section]; + sh_link = ShStrTabBuilder.getOffset(Section.getSectionName()); sh_info = 0; break; @@ -1680,7 +1625,8 @@ void ELFObjectWriter::WriteSection(MCAssembler &Asm, } } - WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(), + WriteSecHdrEntry(ShStrTabBuilder.getOffset(Section.getSectionName()), + Section.getType(), Section.getFlags(), 0, Offset, Size, sh_link, sh_info, Alignment, Section.getEntrySize()); } diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index dc182966ae6..cd8c9efe7b0 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -12,6 +12,7 @@ add_llvm_library(LLVMObject MachOUniversal.cpp Object.cpp ObjectFile.cpp + StringTableBuilder.cpp SymbolicFile.cpp YAML.cpp ) diff --git a/lib/Object/StringTableBuilder.cpp b/lib/Object/StringTableBuilder.cpp new file mode 100644 index 00000000000..9152834a296 --- /dev/null +++ b/lib/Object/StringTableBuilder.cpp @@ -0,0 +1,51 @@ +//===-- StringTableBuilder.cpp - String table building utility ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Object/StringTableBuilder.h" + +using namespace llvm; + +static bool compareBySuffix(StringRef a, StringRef b) { + size_t sizeA = a.size(); + size_t sizeB = b.size(); + size_t len = std::min(sizeA, sizeB); + for (size_t i = 0; i < len; ++i) { + char ca = a[sizeA - i - 1]; + char cb = b[sizeB - i - 1]; + if (ca != cb) + return ca > cb; + } + return sizeA > sizeB; +} + +void StringTableBuilder::finalize() { + SmallVector Strings; + for (auto i = StringIndexMap.begin(), e = StringIndexMap.end(); i != e; ++i) + Strings.push_back(i->getKey()); + + std::sort(Strings.begin(), Strings.end(), compareBySuffix); + + // FIXME: Starting with a null byte is ELF specific. Generalize this so we + // can use the class with other object formats. + StringTable += '\x00'; + + StringRef Previous; + for (StringRef s : Strings) { + if (Previous.endswith(s)) { + StringIndexMap[s] = StringTable.size() - 1 - s.size(); + continue; + } + + StringIndexMap[s] = StringTable.size(); + StringTable += s; + StringTable += '\x00'; + Previous = s; + } +} diff --git a/test/MC/AArch64/tls-relocs.s b/test/MC/AArch64/tls-relocs.s index 6fc7244aed0..5b2e9887599 100644 --- a/test/MC/AArch64/tls-relocs.s +++ b/test/MC/AArch64/tls-relocs.s @@ -543,7 +543,7 @@ // CHECK-ELF: Symbols [ // CHECK-ELF: Symbol { -// CHECK-ELF: Name: var (6) +// CHECK-ELF: Name: var // CHECK-ELF-NEXT: Value: // CHECK-ELF-NEXT: Size: // CHECK-ELF-NEXT: Binding: Global diff --git a/test/MC/ARM64/tls-relocs.s b/test/MC/ARM64/tls-relocs.s index 28c8ad9ef2a..681f616d909 100644 --- a/test/MC/ARM64/tls-relocs.s +++ b/test/MC/ARM64/tls-relocs.s @@ -313,7 +313,7 @@ // CHECK-ELF: Symbols [ // CHECK-ELF: Symbol { -// CHECK-ELF: Name: var (6) +// CHECK-ELF: Name: var // CHECK-ELF-NEXT: Value: // CHECK-ELF-NEXT: Size: // CHECK-ELF-NEXT: Binding: Global diff --git a/test/MC/ELF/comdat.s b/test/MC/ELF/comdat.s index 05d08e14816..68b0f328f9b 100644 --- a/test/MC/ELF/comdat.s +++ b/test/MC/ELF/comdat.s @@ -49,7 +49,7 @@ // Test that g1 and g2 are local, but g3 is an undefined global. // CHECK: Symbol { -// CHECK: Name: g1 (1) +// CHECK: Name: g1 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -58,7 +58,7 @@ // CHECK-NEXT: Section: .foo (0x7) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: g2 (4) +// CHECK-NEXT: Name: g2 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -68,7 +68,7 @@ // CHECK-NEXT: } // CHECK: Symbol { -// CHECK: Name: g3 (7) +// CHECK: Name: g3 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/common.s b/test/MC/ELF/common.s index 9cff927ba55..bd96564a5ca 100644 --- a/test/MC/ELF/common.s +++ b/test/MC/ELF/common.s @@ -9,7 +9,7 @@ .comm common1,1,1 // CHECK: Symbol { -// CHECK: Name: common1 (1) +// CHECK: Name: common1 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 1 // CHECK-NEXT: Binding: Local @@ -25,7 +25,7 @@ .comm common2,1,1 // CHECK: Symbol { -// CHECK: Name: common2 (9) +// CHECK: Name: common2 // CHECK-NEXT: Value: 0x1 // CHECK-NEXT: Size: 1 // CHECK-NEXT: Binding: Local @@ -39,7 +39,7 @@ .comm common6,8,16 // CHECK: Symbol { -// CHECK: Name: common6 (17) +// CHECK: Name: common6 // CHECK-NEXT: Value: 0x10 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Binding: Local @@ -54,7 +54,7 @@ .comm common3,4,4 // CHECK: Symbol { -// CHECK: Name: common3 (25) +// CHECK: Name: common3 // CHECK-NEXT: Value: 0x4 // CHECK-NEXT: Size: 4 // CHECK-NEXT: Binding: Global @@ -76,7 +76,7 @@ foo: .comm common4,40,16 // CHECK: Symbol { -// CHECK: Name: common4 (37) +// CHECK: Name: common4 // CHECK-NEXT: Value: 0x10 // CHECK-NEXT: Size: 40 // CHECK-NEXT: Binding: Global @@ -89,7 +89,7 @@ foo: .comm common5,4,4 // CHECK: Symbol { -// CHECK: Name: common5 (45) +// CHECK: Name: common5 // CHECK-NEXT: Value: 0x4 // CHECK-NEXT: Size: 4 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/file-double.s b/test/MC/ELF/file-double.s index f9b91edd6fe..b5da8c5a858 100644 --- a/test/MC/ELF/file-double.s +++ b/test/MC/ELF/file-double.s @@ -11,7 +11,7 @@ foo.c: bar.c: // CHECK: Symbol { -// CHECK: Name: foo.c (1) +// CHECK: Name: foo.c // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -19,7 +19,7 @@ bar.c: // CHECK-NEXT: Other: 0 // CHECK-NEXT: Section: Absolute (0xFFF1) // CHECK-NEXT: } -// CHECK: Name: bar.c (7) +// CHECK: Name: bar.c // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -28,7 +28,7 @@ bar.c: // CHECK-NEXT: Section: Absolute (0xFFF1) // CHECK-NEXT: } // CHECK: Symbol { -// CHECK: Name: bar.c (7) +// CHECK: Name: bar.c // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -37,7 +37,7 @@ bar.c: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK: Symbol { -// CHECK: Name: foo.c (1) +// CHECK: Name: foo.c // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/lcomm.s b/test/MC/ELF/lcomm.s index 430b79b54b0..7d8ac3fcafa 100644 --- a/test/MC/ELF/lcomm.s +++ b/test/MC/ELF/lcomm.s @@ -4,7 +4,7 @@ .lcomm B, 32 << 20 // CHECK: Symbol { -// CHECK: Name: A (1) +// CHECK: Name: A // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 5 // CHECK-NEXT: Binding: Local @@ -13,7 +13,7 @@ // CHECK-NEXT: Section: .bss (0x3) // CHECK-NEXT: } // CHECK: Symbol { -// CHECK: Name: B (3) +// CHECK: Name: B // CHECK-NEXT: Value: 0x5 // CHECK-NEXT: Size: 33554432 // CHECK-NEXT: Binding: Local diff --git a/test/MC/ELF/many-sections-2.s b/test/MC/ELF/many-sections-2.s index d1f9d008f54..88a4822c386 100644 --- a/test/MC/ELF/many-sections-2.s +++ b/test/MC/ELF/many-sections-2.s @@ -12,7 +12,7 @@ // Test that both a and b show up in the correct section. -// SYMBOLS: Name: a (1) +// SYMBOLS: Name: a // SYMBOLS-NEXT: Value: 0x0 // SYMBOLS-NEXT: Size: 0 // SYMBOLS-NEXT: Binding: Local (0x0) @@ -21,7 +21,7 @@ // SYMBOLS-NEXT: Section: last (0xFF00) // SYMBOLS-NEXT: } // SYMBOLS-NEXT: Symbol { -// SYMBOLS-NEXT: Name: b (3) +// SYMBOLS-NEXT: Name: b // SYMBOLS-NEXT: Value: 0x1 // SYMBOLS-NEXT: Size: 0 // SYMBOLS-NEXT: Binding: Local (0x0) @@ -32,7 +32,7 @@ // Test that this file has one section too many. -// SYMBOLS: Name: last (0) +// SYMBOLS: Name: last // SYMBOLS-NEXT: Value: 0x0 // SYMBOLS-NEXT: Size: 0 // SYMBOLS-NEXT: Binding: Local (0x0) diff --git a/test/MC/ELF/pic-diff.s b/test/MC/ELF/pic-diff.s index 30c92780f13..5f0b1459ba2 100644 --- a/test/MC/ELF/pic-diff.s +++ b/test/MC/ELF/pic-diff.s @@ -7,7 +7,7 @@ // CHECK-NEXT: ] // CHECK: Symbol { -// CHECK: Name: baz (5) +// CHECK: Name: baz // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/pr9292.s b/test/MC/ELF/pr9292.s index a433650bc69..1e01194c701 100644 --- a/test/MC/ELF/pr9292.s +++ b/test/MC/ELF/pr9292.s @@ -8,7 +8,7 @@ mov %eax,bar // CHECK: Symbol { -// CHECK: Name: bar (5) +// CHECK: Name: bar // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -17,7 +17,7 @@ mov %eax,bar // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo (1) +// CHECK-NEXT: Name: foo // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/set.s b/test/MC/ELF/set.s index 80e7e5380a7..b4f77f5a090 100644 --- a/test/MC/ELF/set.s +++ b/test/MC/ELF/set.s @@ -5,7 +5,7 @@ .set kernbase,0xffffffff80000000 // CHECK: Symbol { -// CHECK: Name: kernbase (1) +// CHECK: Name: kernbase // CHECK-NEXT: Value: 0xFFFFFFFF80000000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -26,7 +26,7 @@ // Test that there is an undefined reference to bar // CHECK: Symbol { -// CHECK: Name: bar (10) +// CHECK: Name: bar // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/strtab-suffix-opt.s b/test/MC/ELF/strtab-suffix-opt.s new file mode 100644 index 00000000000..eb5da8a0155 --- /dev/null +++ b/test/MC/ELF/strtab-suffix-opt.s @@ -0,0 +1,21 @@ +// RUN: llvm-mc -filetype=obj -triple i686-pc-linux-gnu %s -o - | llvm-readobj -symbols | FileCheck %s + + .text + .globl foobar + .align 16, 0x90 + .type foobar,@function +foobar: + pushl %ebp + movl %esp, %ebp + subl $8, %esp + calll foo + calll bar + addl $8, %esp + popl %ebp + retl +.Ltmp3: + .size foobar, .Ltmp3-foobar + +// CHECK: Name: foobar (1) +// CHECK: Name: bar (4) +// CHECK: Name: foo (8) diff --git a/test/MC/ELF/tls-i386.s b/test/MC/ELF/tls-i386.s index 88e96ff6673..5ee36681e2d 100644 --- a/test/MC/ELF/tls-i386.s +++ b/test/MC/ELF/tls-i386.s @@ -18,7 +18,7 @@ .long fooE@INDNTPOFF // CHECK: Symbol { -// CHECK: Name: foo1 (1) +// CHECK: Name: foo1 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -27,7 +27,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo2 (6) +// CHECK-NEXT: Name: foo2 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -36,7 +36,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo3 (11) +// CHECK-NEXT: Name: foo3 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -45,7 +45,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo4 (16) +// CHECK-NEXT: Name: foo4 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -54,7 +54,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo5 (21) +// CHECK-NEXT: Name: foo5 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -63,7 +63,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo6 (26) +// CHECK-NEXT: Name: foo6 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -72,7 +72,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo7 (31) +// CHECK-NEXT: Name: foo7 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -81,7 +81,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo8 (36) +// CHECK-NEXT: Name: foo8 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -90,7 +90,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo9 (41) +// CHECK-NEXT: Name: foo9 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -99,7 +99,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: fooA (46) +// CHECK-NEXT: Name: fooA // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -108,7 +108,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: fooB (51) +// CHECK-NEXT: Name: fooB // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -117,7 +117,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: fooC (56) +// CHECK-NEXT: Name: fooC // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -126,7 +126,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: fooD (61) +// CHECK-NEXT: Name: fooD // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -135,7 +135,7 @@ // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: fooE (66) +// CHECK-NEXT: Name: fooE // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/tls.s b/test/MC/ELF/tls.s index 6d4b703ace4..79865cd17be 100644 --- a/test/MC/ELF/tls.s +++ b/test/MC/ELF/tls.s @@ -13,7 +13,7 @@ foobar: .long 43 // CHECK: Symbol { -// CHECK: Name: foobar (31) +// CHECK: Name: foobar // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -23,7 +23,7 @@ foobar: // CHECK-NEXT: } // CHECK: Symbol { -// CHECK: Name: foo1 (1) +// CHECK: Name: foo1 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -32,7 +32,7 @@ foobar: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo2 (6) +// CHECK-NEXT: Name: foo2 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -41,7 +41,7 @@ foobar: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo3 (11) +// CHECK-NEXT: Name: foo3 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -50,7 +50,7 @@ foobar: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo4 (16) +// CHECK-NEXT: Name: foo4 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -59,7 +59,7 @@ foobar: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo5 (21) +// CHECK-NEXT: Name: foo5 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -68,7 +68,7 @@ foobar: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: foo6 (26) +// CHECK-NEXT: Name: foo6 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/test/MC/ELF/type.s b/test/MC/ELF/type.s index 638d8286991..c82d3006cfe 100644 --- a/test/MC/ELF/type.s +++ b/test/MC/ELF/type.s @@ -176,7 +176,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym1 (54) +// CHECK-NEXT: Name: sym1 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -185,7 +185,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym10 (162) +// CHECK-NEXT: Name: sym10 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -194,7 +194,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym11 (176) +// CHECK-NEXT: Name: sym11 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -203,7 +203,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym12 (190) +// CHECK-NEXT: Name: sym12 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -212,7 +212,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym2 (66) +// CHECK-NEXT: Name: sym2 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -221,7 +221,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym3 (78) +// CHECK-NEXT: Name: sym3 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -230,7 +230,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym4 (90) +// CHECK-NEXT: Name: sym4 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -239,7 +239,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym5 (102) +// CHECK-NEXT: Name: sym5 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -248,7 +248,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym6 (114) +// CHECK-NEXT: Name: sym6 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -257,7 +257,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym7 (126) +// CHECK-NEXT: Name: sym7 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -266,7 +266,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym8 (138) +// CHECK-NEXT: Name: sym8 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) @@ -275,7 +275,7 @@ alias12: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: sym9 (150) +// CHECK-NEXT: Name: sym9 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) diff --git a/test/MC/ELF/weakref.s b/test/MC/ELF/weakref.s index cf2228d8f76..2288264bd6c 100644 --- a/test/MC/ELF/weakref.s +++ b/test/MC/ELF/weakref.s @@ -80,7 +80,7 @@ bar15: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar6 (21) +// CHECK-NEXT: Name: bar6 // CHECK-NEXT: Value: 0x18 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -89,7 +89,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar7 (26) +// CHECK-NEXT: Name: bar7 // CHECK-NEXT: Value: 0x18 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -98,7 +98,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar8 (31) +// CHECK-NEXT: Name: bar8 // CHECK-NEXT: Value: 0x1C // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -107,7 +107,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar9 (36) +// CHECK-NEXT: Name: bar9 // CHECK-NEXT: Value: 0x20 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -116,7 +116,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: .text (0) +// CHECK-NEXT: Name: .text // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -125,7 +125,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: .data (0) +// CHECK-NEXT: Name: .data // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -134,7 +134,7 @@ bar15: // CHECK-NEXT: Section: .data (0x3) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: .bss (0) +// CHECK-NEXT: Name: .bss // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local @@ -143,7 +143,7 @@ bar15: // CHECK-NEXT: Section: .bss (0x4) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar10 (41) +// CHECK-NEXT: Name: bar10 // CHECK-NEXT: Value: 0x28 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -152,7 +152,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar11 (47) +// CHECK-NEXT: Name: bar11 // CHECK-NEXT: Value: 0x30 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -161,7 +161,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar12 (53) +// CHECK-NEXT: Name: bar12 // CHECK-NEXT: Value: 0x30 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -170,7 +170,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar13 (59) +// CHECK-NEXT: Name: bar13 // CHECK-NEXT: Value: 0x34 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -179,7 +179,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar14 (65) +// CHECK-NEXT: Name: bar14 // CHECK-NEXT: Value: 0x38 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -188,7 +188,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar15 (71) +// CHECK-NEXT: Name: bar15 // CHECK-NEXT: Value: 0x40 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -197,7 +197,7 @@ bar15: // CHECK-NEXT: Section: .text (0x1) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar2 (1) +// CHECK-NEXT: Name: bar2 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -206,7 +206,7 @@ bar15: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar3 (6) +// CHECK-NEXT: Name: bar3 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Weak @@ -215,7 +215,7 @@ bar15: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar4 (11) +// CHECK-NEXT: Name: bar4 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global @@ -224,7 +224,7 @@ bar15: // CHECK-NEXT: Section: Undefined (0x0) // CHECK-NEXT: } // CHECK-NEXT: Symbol { -// CHECK-NEXT: Name: bar5 (16) +// CHECK-NEXT: Name: bar5 // CHECK-NEXT: Value: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index acbac9c6057..c78e1dbe774 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -30,10 +30,8 @@ using namespace llvm; // This class has a deliberately small interface, since a lot of // implementation variation is possible. // -// TODO: Use an ordered container with a suffix-based comparison in order -// to deduplicate suffixes. std::map<> with a custom comparator is likely -// to be the simplest implementation, but a suffix trie could be more -// suitable for the job. +// TODO: Use the StringTable builder from lib/Object instead, since it +// will deduplicate suffixes. namespace { class StringTableBuilder { /// \brief Indices of strings currently present in `Buf`. diff --git a/unittests/Object/CMakeLists.txt b/unittests/Object/CMakeLists.txt index 6dd66ce75bd..580a894362d 100644 --- a/unittests/Object/CMakeLists.txt +++ b/unittests/Object/CMakeLists.txt @@ -4,5 +4,6 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(ObjectTests + StringTableBuilderTest.cpp YAMLTest.cpp ) diff --git a/unittests/Object/StringTableBuilderTest.cpp b/unittests/Object/StringTableBuilderTest.cpp new file mode 100644 index 00000000000..130eb4a3d73 --- /dev/null +++ b/unittests/Object/StringTableBuilderTest.cpp @@ -0,0 +1,40 @@ +//===----------- StringTableBuilderTest.cpp -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/Object/StringTableBuilder.h" +#include + +using namespace llvm; + +namespace { + +TEST(StringTableBuilderTest, Basic) { + StringTableBuilder B; + + B.add("foo"); + B.add("bar"); + B.add("foobar"); + + B.finalize(); + + std::string Expected; + Expected += '\x00'; + Expected += "foobar"; + Expected += '\x00'; + Expected += "foo"; + Expected += '\x00'; + + EXPECT_EQ(Expected, B.data()); + EXPECT_EQ(1U, B.getOffset("foobar")); + EXPECT_EQ(4U, B.getOffset("bar")); + EXPECT_EQ(8U, B.getOffset("foo")); +} + +}