[llvm] r311974 - Reland "[llvm] Add symbol table support to llvm-objcopy"

Petr Hosek via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 28 19:12:03 PDT 2017


Author: phosek
Date: Mon Aug 28 19:12:03 2017
New Revision: 311974

URL: http://llvm.org/viewvc/llvm-project?rev=311974&view=rev
Log:
Reland "[llvm] Add symbol table support to llvm-objcopy"

This change adds support for SHT_SYMTAB sections.

Patch by Jake Ehrlich

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

Added:
    llvm/trunk/test/tools/llvm-objcopy/symbol-copy.test
Modified:
    llvm/trunk/tools/llvm-objcopy/Object.cpp
    llvm/trunk/tools/llvm-objcopy/Object.h

Added: llvm/trunk/test/tools/llvm-objcopy/symbol-copy.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/symbol-copy.test?rev=311974&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/symbol-copy.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/symbol-copy.test Mon Aug 28 19:12:03 2017
@@ -0,0 +1,93 @@
+# RUN: yaml2obj %s > %t
+# RUN: llvm-objcopy %t %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x0000000000000010
+    Content:         "0000000000000000"
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2000
+    AddressAlign:    0x0000000000000010
+    Content:         "0000000000000000"
+Symbols:
+  Global:
+    - Name:     _start
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0x1000
+      Size:     4
+    - Name:     foo
+      Type:     STT_FUNC
+      Section:  .text
+      Section:  .text
+      Value:    0x1004
+    - Name:     bar
+      Type:     STT_OBJECT
+      Section:  .data
+      Value:    0x2000
+      Size:     4
+    - Name:     baz
+      Type:     STT_OBJECT
+      Section:  .data
+      Value:    0x2004
+      Size:     4
+
+#CHECK: Symbols [
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name:
+#CHECK-NEXT:    Value: 0x0
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Local
+#CHECK-NEXT:    Type: None
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: Undefined
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: _start
+#CHECK-NEXT:    Value: 0x1000
+#CHECK-NEXT:    Size: 4
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Function
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .text
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: foo
+#CHECK-NEXT:    Value: 0x1004
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Function
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .text
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: bar
+#CHECK-NEXT:    Value: 0x2000
+#CHECK-NEXT:    Size: 4
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Object
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .data
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: baz
+#CHECK-NEXT:    Value: 0x2004
+#CHECK-NEXT:    Size: 4
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Object
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .data
+#CHECK-NEXT:  }
+#CHECK-NEXT:]

Modified: llvm/trunk/tools/llvm-objcopy/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.cpp?rev=311974&r1=311973&r2=311974&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.cpp Mon Aug 28 19:12:03 2017
@@ -90,6 +90,70 @@ void StringTableSection::writeSection(Fi
   StrTabBuilder.write(Out.getBufferStart() + Offset);
 }
 
+void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, uint8_t Type,
+                                   SectionBase *DefinedIn, uint64_t Value,
+                                   uint64_t Sz) {
+  Symbol Sym;
+  Sym.Name = Name;
+  Sym.Binding = Bind;
+  Sym.Type = Type;
+  Sym.DefinedIn = DefinedIn;
+  Sym.Value = Value;
+  Sym.Size = Sz;
+  Sym.Index = Symbols.size();
+  Symbols.emplace_back(llvm::make_unique<Symbol>(Sym));
+  Size += this->EntrySize;
+}
+
+void SymbolTableSection::finalize() {
+  // Make sure SymbolNames is finalized before getting name indexes.
+  SymbolNames->finalize();
+
+  uint32_t MaxLocalIndex = 0;
+  for (auto &Sym : Symbols) {
+    Sym->NameIndex = SymbolNames->findIndex(Sym->Name);
+    if (Sym->Binding == STB_LOCAL)
+      MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index);
+  }
+  // Now we need to set the Link and Info fields.
+  Link = SymbolNames->Index;
+  Info = MaxLocalIndex + 1;
+}
+
+void SymbolTableSection::addSymbolNames() {
+  // Add all of our strings to SymbolNames so that SymbolNames has the right
+  // size before layout is decided.
+  for (auto &Sym : Symbols)
+    SymbolNames->addString(Sym->Name);
+}
+
+const Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) const {
+  if (Symbols.size() <= Index)
+    error("Invalid symbol index: " + Twine(Index));
+  return Symbols[Index].get();
+}
+
+template <class ELFT>
+void SymbolTableSectionImpl<ELFT>::writeSection(
+    llvm::FileOutputBuffer &Out) const {
+  uint8_t *Buf = Out.getBufferStart();
+  Buf += Offset;
+  typename ELFT::Sym *Sym = reinterpret_cast<typename ELFT::Sym *>(Buf);
+  // Loop though symbols setting each entry of the symbol table.
+  for (auto &Symbol : Symbols) {
+    Sym->st_name = Symbol->NameIndex;
+    Sym->st_value = Symbol->Value;
+    Sym->st_size = Symbol->Size;
+    Sym->setBinding(Symbol->Binding);
+    Sym->setType(Symbol->Type);
+    if (Symbol->DefinedIn)
+      Sym->st_shndx = Symbol->DefinedIn->Index;
+    else
+      Sym->st_shndx = SHN_UNDEF;
+    ++Sym;
+  }
+}
+
 // Returns true IFF a section is wholly inside the range of a segment
 static bool sectionWithinSegment(const SectionBase &Section,
                                  const Segment &Segment) {
@@ -133,6 +197,40 @@ void Object<ELFT>::readProgramHeaders(co
 }
 
 template <class ELFT>
+void Object<ELFT>::initSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
+                                   SymbolTableSection *SymTab) {
+
+  SymTab->Size = 0;
+  if (SymbolTable->Link - 1 >= Sections.size())
+    error("Symbol table has link index of " + Twine(SymbolTable->Link) +
+          " which is not a valid index");
+
+  if (auto StrTab =
+          dyn_cast<StringTableSection>(Sections[SymbolTable->Link - 1].get()))
+    SymTab->setStrTab(StrTab);
+  else
+    error("Symbol table has link index of " + Twine(SymbolTable->Link) +
+          "which is not a string table");
+
+  const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index));
+  StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr));
+
+  for (const auto &Sym : unwrapOrError(ElfFile.symbols(&Shdr))) {
+    SectionBase *DefSection = nullptr;
+    StringRef Name = unwrapOrError(Sym.getName(StrTabData));
+    if (Sym.st_shndx != SHN_UNDEF) {
+      if (Sym.st_shndx >= Sections.size())
+        error("Symbol '" + Name +
+              "' is defined in invalid section with index " +
+              Twine(Sym.st_shndx));
+      DefSection = Sections[Sym.st_shndx - 1].get();
+    }
+    SymTab->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection,
+                      Sym.getValue(), Sym.st_size);
+  }
+}
+
+template <class ELFT>
 std::unique_ptr<SectionBase>
 Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
                           const Elf_Shdr &Shdr) {
@@ -140,6 +238,11 @@ Object<ELFT>::makeSection(const llvm::ob
   switch (Shdr.sh_type) {
   case SHT_STRTAB:
     return llvm::make_unique<StringTableSection>();
+  case SHT_SYMTAB: {
+    auto SymTab = llvm::make_unique<SymbolTableSectionImpl<ELFT>>();
+    SymbolTable = SymTab.get();
+    return std::move(SymTab);
+  }
   case SHT_NOBITS:
     return llvm::make_unique<Section>(Data);
   default:
@@ -171,6 +274,11 @@ void Object<ELFT>::readSectionHeaders(co
     Sec->Index = Index++;
     Sections.push_back(std::move(Sec));
   }
+
+  // Now that all of the sections have been added we can fill out some extra
+  // details about symbol tables.
+  if (SymbolTable)
+    initSymbolTable(ElfFile, SymbolTable);
 }
 
 template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {
@@ -315,9 +423,12 @@ template <class ELFT> void ELFObject<ELF
 }
 
 template <class ELFT> void ELFObject<ELFT>::finalize() {
+  // Make sure we add the names of all the sections.
   for (const auto &Section : this->Sections) {
     this->SectionNames->addString(Section->Name);
   }
+  // Make sure we add the names of all the symbols.
+  this->SymbolTable->addSymbolNames();
 
   sortSections();
   assignOffsets();

Modified: llvm/trunk/tools/llvm-objcopy/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.h?rev=311974&r1=311973&r2=311974&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.h Mon Aug 28 19:12:03 2017
@@ -113,6 +113,39 @@ public:
   }
 };
 
+struct Symbol {
+  uint8_t Binding;
+  SectionBase *DefinedIn;
+  uint32_t Index;
+  llvm::StringRef Name;
+  uint32_t NameIndex;
+  uint64_t Size;
+  uint8_t Type;
+  uint64_t Value;
+};
+
+class SymbolTableSection : public SectionBase {
+protected:
+  std::vector<std::unique_ptr<Symbol>> Symbols;
+  StringTableSection *SymbolNames;
+
+public:
+  void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; }
+  void addSymbol(llvm::StringRef Name, uint8_t Bind, uint8_t Type,
+                 SectionBase *DefinedIn, uint64_t Value, uint64_t Sz);
+  void addSymbolNames();
+  const Symbol *getSymbolByIndex(uint32_t Index) const;
+  void finalize() override;
+  static bool classof(const SectionBase *S) {
+    return S->Type == llvm::ELF::SHT_SYMTAB;
+  }
+};
+
+// Only writeSection depends on the ELF type so we implement it in a subclass.
+template <class ELFT> class SymbolTableSectionImpl : public SymbolTableSection {
+  void writeSection(llvm::FileOutputBuffer &Out) const override;
+};
+
 template <class ELFT> class Object {
 private:
   typedef std::unique_ptr<SectionBase> SecPtr;
@@ -122,6 +155,8 @@ private:
   typedef typename ELFT::Ehdr Elf_Ehdr;
   typedef typename ELFT::Phdr Elf_Phdr;
 
+  void initSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
+                       SymbolTableSection *SymTab);
   SecPtr makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
                      const Elf_Shdr &Shdr);
   void readProgramHeaders(const llvm::object::ELFFile<ELFT> &ElfFile);
@@ -129,6 +164,7 @@ private:
 
 protected:
   StringTableSection *SectionNames;
+  SymbolTableSection *SymbolTable;
   std::vector<SecPtr> Sections;
   std::vector<SegPtr> Segments;
 




More information about the llvm-commits mailing list