summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Object/StringTableBuilder.h59
-rw-r--r--lib/MC/ELFObjectWriter.cpp118
-rw-r--r--lib/Object/CMakeLists.txt1
-rw-r--r--lib/Object/StringTableBuilder.cpp51
-rw-r--r--test/MC/AArch64/tls-relocs.s2
-rw-r--r--test/MC/ARM64/tls-relocs.s2
-rw-r--r--test/MC/ELF/comdat.s6
-rw-r--r--test/MC/ELF/common.s12
-rw-r--r--test/MC/ELF/file-double.s8
-rw-r--r--test/MC/ELF/lcomm.s4
-rw-r--r--test/MC/ELF/many-sections-2.s6
-rw-r--r--test/MC/ELF/pic-diff.s2
-rw-r--r--test/MC/ELF/pr9292.s4
-rw-r--r--test/MC/ELF/set.s4
-rw-r--r--test/MC/ELF/strtab-suffix-opt.s21
-rw-r--r--test/MC/ELF/tls-i386.s28
-rw-r--r--test/MC/ELF/tls.s14
-rw-r--r--test/MC/ELF/type.s24
-rw-r--r--test/MC/ELF/weakref.s34
-rw-r--r--tools/yaml2obj/yaml2elf.cpp6
-rw-r--r--unittests/Object/CMakeLists.txt1
-rw-r--r--unittests/Object/StringTableBuilderTest.cpp40
22 files changed, 282 insertions, 165 deletions
diff --git a/include/llvm/Object/StringTableBuilder.h b/include/llvm/Object/StringTableBuilder.h
new file mode 100644
index 0000000000..c61e216bdf
--- /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 <cassert>
+
+namespace llvm {
+
+/// \brief Utility for building string tables with deduplicated suffixes.
+class StringTableBuilder {
+ SmallString<256> StringTable;
+ StringMap<size_t> 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 2e07e22dc3..ebcc691f0a 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<const MCSectionData *, std::vector<ELFRelocationEntry>>
Relocations;
- DenseMap<const MCSection*, uint64_t> SectionStringTableIndex;
+ StringTableBuilder ShStrTabBuilder;
/// @}
/// @name Symbol Table Data
/// @{
- SmallString<256> StringTable;
+ StringTableBuilder StrTabBuilder;
std::vector<uint64_t> FileSymbolData;
std::vector<ELFSymbolData> LocalSymbolData;
std::vector<ELFSymbolData> 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<uint64_t> 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<const MCSectionELF*> 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<const MCSectionELF&>(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 dc182966ae..cd8c9efe7b 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 0000000000..9152834a29
--- /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<StringRef, 8> 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 6fc7244aed..5b2e988759 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 28c8ad9ef2..681f616d90 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 05d08e1481..68b0f328f9 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 9cff927ba5..bd96564a5c 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 f9b91edd6f..b5da8c5a85 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 430b79b54b..7d8ac3fcaf 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 d1f9d008f5..88a4822c38 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 30c92780f1..5f0b1459ba 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 a433650bc6..1e01194c70 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 80e7e5380a..b4f77f5a09 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 0000000000..eb5da8a015
--- /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 88e96ff667..5ee36681e2 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 6d4b703ace..79865cd17b 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 638d828699..c82d3006cf 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 cf2228d8f7..2288264bd6 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 acbac9c605..c78e1dbe77 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 6dd66ce75b..580a894362 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 0000000000..130eb4a3d7
--- /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 <string>
+
+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"));
+}
+
+}