OSDN Git Service

[llvm-objcopy] Add support for .dynamic, .dynsym, and .dynstr
authorJake Ehrlich <jakehehrlich@google.com>
Tue, 19 Sep 2017 19:21:09 +0000 (19:21 +0000)
committerJake Ehrlich <jakehehrlich@google.com>
Tue, 19 Sep 2017 19:21:09 +0000 (19:21 +0000)
This change adds support for sections involved in dynamic loading such
as SHT_DYNAMIC, SHT_DYNSYM, and allocated string tables.

The two added binaries used for tests can be downloaded [[
https://drive.google.com/file/d/0B3gtIAmiMwZXOXE3T0RobFg4ZTg/view?usp=sharing
| here ]] and [[
https://drive.google.com/file/d/0B3gtIAmiMwZXTFJSQUJZMGxNSXc/view?usp=sharing
| here ]]

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@313663 91177308-0d34-0410-b5e6-96231b3b80d8

test/tools/llvm-objcopy/Inputs/dynamic.so [new file with mode: 0755]
test/tools/llvm-objcopy/Inputs/dynsym.so [new file with mode: 0755]
test/tools/llvm-objcopy/dynamic.test [new file with mode: 0644]
test/tools/llvm-objcopy/dynstr.test [new file with mode: 0644]
test/tools/llvm-objcopy/dynsym.test [new file with mode: 0644]
tools/llvm-objcopy/Object.cpp
tools/llvm-objcopy/Object.h

diff --git a/test/tools/llvm-objcopy/Inputs/dynamic.so b/test/tools/llvm-objcopy/Inputs/dynamic.so
new file mode 100755 (executable)
index 0000000..cf5757d
Binary files /dev/null and b/test/tools/llvm-objcopy/Inputs/dynamic.so differ
diff --git a/test/tools/llvm-objcopy/Inputs/dynsym.so b/test/tools/llvm-objcopy/Inputs/dynsym.so
new file mode 100755 (executable)
index 0000000..2f62627
Binary files /dev/null and b/test/tools/llvm-objcopy/Inputs/dynsym.so differ
diff --git a/test/tools/llvm-objcopy/dynamic.test b/test/tools/llvm-objcopy/dynamic.test
new file mode 100644 (file)
index 0000000..3e9ea20
--- /dev/null
@@ -0,0 +1,27 @@
+# RUN: llvm-objcopy %p/Inputs/dynamic.so %t
+# RUN: llvm-readobj -dynamic-table %t | FileCheck %s
+# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=LINK %s
+
+#CHECK: DynamicSection [
+#CHECK-NEXT:  Tag                Type                 Name/Value
+#CHECK-NEXT:  0x0000000000000006 SYMTAB               0x1C8
+#CHECK-NEXT:  0x000000000000000B SYMENT               24
+#CHECK-NEXT:  0x0000000000000005 STRTAB               0x210
+#CHECK-NEXT:  0x000000000000000A STRSZ                5
+#CHECK-NEXT:  0x0000000000000004 HASH                 0x1F8
+#CHECK-NEXT:  0x0000000000000000 NULL                 0x0
+#CHECK-NEXT:]
+
+#LINK:         Index: 3
+#LINK-NEXT:    Name: .dynstr
+
+#LINK:         Name: .dynamic
+#LINK-NEXT:    Type: SHT_DYNAMIC
+#LINK-NEXT:    Flags [
+#LINK-NEXT:      SHF_ALLOC
+#LINK-NEXT:      SHF_WRITE
+#LINK-NEXT:    ]
+#LINK-NEXT:    Address:
+#LINK-NEXT:    Offset:
+#LINK-NEXT:    Size:
+#LINK-NEXT:    Link: 3
diff --git a/test/tools/llvm-objcopy/dynstr.test b/test/tools/llvm-objcopy/dynstr.test
new file mode 100644 (file)
index 0000000..6e19306
--- /dev/null
@@ -0,0 +1,32 @@
+# RUN: yaml2obj %s > %t
+# RUN: llvm-objcopy %t %t2
+# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .dynstr
+    Type:            SHT_STRTAB
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1000
+    Content:         "002EDEADBEEF002EBAADF00D00"
+
+#CHECK:         Name: .dynstr
+#CHECK-NEXT:    Type: SHT_STRTAB
+#CHECK-NEXT:    Flags [
+#CHECK-NEXT:      SHF_ALLOC
+#CHECK-NEXT:    ]
+#CHECK-NEXT:    Address: 0x1000
+#CHECK-NEXT:    Offset:
+#CHECK-NEXT:    Size: 13
+#CHECK-NEXT:    Link:
+#CHECK-NEXT:    Info:
+#CHECK-NEXT:    AddressAlignment:
+#CHECK-NEXT:    EntrySize:
+#CHECK-NEXT:    SectionData (
+#CHECK-NEXT:      0000: 002EDEAD BEEF002E BAADF00D 00
+#CHECK-NEXT:    )
diff --git a/test/tools/llvm-objcopy/dynsym.test b/test/tools/llvm-objcopy/dynsym.test
new file mode 100644 (file)
index 0000000..b7d0953
--- /dev/null
@@ -0,0 +1,64 @@
+# RUN: llvm-objcopy %p/Inputs/dynsym.so %t
+# RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
+# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=LINK %s
+
+#LINK:         Name: .dynsym
+#LINK-NEXT:    Type: SHT_DYNSYM
+#LINK-NEXT:    Flags [
+#LINK-NEXT:      SHF_ALLOC
+#LINK-NEXT:    ]
+#LINK-NEXT:    Address:
+#LINK-NEXT:    Offset:
+#LINK-NEXT:    Size:
+#LINK-NEXT:    Link: 3
+
+#LINK:         Index: 3
+#LINK-NEXT:    Name: .dynstr
+
+#CHECK: DynamicSymbols [
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: @ (0)
+#CHECK-NEXT:    Value: 0x0
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Local
+#CHECK-NEXT:    Type: None (0x0)
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: Undefined (0x0)
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: bang@ (1)
+#CHECK-NEXT:    Value: 0x4000
+#CHECK-NEXT:    Size: 8
+#CHECK-NEXT:    Binding: Global (0x1)
+#CHECK-NEXT:    Type: Object (0x1)
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .bss (0x7)
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: bar@ (6)
+#CHECK-NEXT:    Value: 0x1001
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Global (0x1)
+#CHECK-NEXT:    Type: Function (0x2)
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .text (0x4)
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: baz@ (10)
+#CHECK-NEXT:    Value: 0x2000
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Global (0x1)
+#CHECK-NEXT:    Type: Object (0x1)
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .data (0x5)
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: foo@ (14)
+#CHECK-NEXT:    Value: 0x1000
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Global (0x1)
+#CHECK-NEXT:    Type: Function (0x2)
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .text (0x4)
+#CHECK-NEXT:  }
+#CHECK-NEXT:]
index 16bfdfd..28323f4 100644 (file)
@@ -228,6 +228,12 @@ void RelocationSection<ELFT>::writeSection(llvm::FileOutputBuffer &Out) const {
     writeRel(reinterpret_cast<Elf_Rela *>(Buf));
 }
 
+bool SectionWithStrTab::classof(const SectionBase *S) {
+  return isa<DynamicSymbolTableSection>(S) || isa<DynamicSection>(S);
+}
+
+void SectionWithStrTab::finalize() { this->Link = StrTab->Index; }
+
 // Returns true IFF a section is wholly inside the range of a segment
 static bool sectionWithinSegment(const SectionBase &Section,
                                  const Segment &Segment) {
@@ -308,16 +314,12 @@ 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");
+  SymTab->setStrTab(getSectionOfType<StringTableSection>(
+      SymbolTable->Link,
+      "Symbol table has link index of " + Twine(SymTab->Link) +
+          " which is not a valid index",
+      "Symbol table has link index of " + Twine(SymTab->Link) +
+          " which is not a string table"));
 
   const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index));
   StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr));
@@ -325,6 +327,7 @@ void Object<ELFT>::initSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
   for (const auto &Sym : unwrapOrError(ElfFile.symbols(&Shdr))) {
     SectionBase *DefSection = nullptr;
     StringRef Name = unwrapOrError(Sym.getName(StrTabData));
+
     if (Sym.st_shndx >= SHN_LORESERVE) {
       if (!isValidReservedSectionIndex(Sym.st_shndx, Machine)) {
         error(
@@ -333,12 +336,12 @@ void Object<ELFT>::initSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
             Twine(Sym.st_shndx));
       }
     } else if (Sym.st_shndx != SHN_UNDEF) {
-      if (Sym.st_shndx >= Sections.size())
-        error("Symbol '" + Name +
-              "' is defined in invalid section with index " +
+      DefSection = getSection(
+          Sym.st_shndx,
+          "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_shndx, Sym.st_size);
   }
@@ -366,6 +369,22 @@ void initRelocations(RelocationSection<ELFT> *Relocs,
 }
 
 template <class ELFT>
+SectionBase *Object<ELFT>::getSection(uint16_t Index, Twine ErrMsg) {
+  if (Index == SHN_UNDEF || Index > Sections.size())
+    error(ErrMsg);
+  return Sections[Index - 1].get();
+}
+
+template <class ELFT>
+template <class T>
+T *Object<ELFT>::getSectionOfType(uint16_t Index, Twine IndexErrMsg,
+                                  Twine TypeErrMsg) {
+  if (T *TSec = llvm::dyn_cast<T>(getSection(Index, IndexErrMsg)))
+    return TSec;
+  error(TypeErrMsg);
+}
+
+template <class ELFT>
 std::unique_ptr<SectionBase>
 Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
                           const Elf_Shdr &Shdr) {
@@ -375,7 +394,26 @@ Object<ELFT>::makeSection(const llvm::object::ELFFile<ELFT> &ElfFile,
   case SHT_RELA:
     return llvm::make_unique<RelocationSection<ELFT>>();
   case SHT_STRTAB:
+    // If a string table is allocated we don't want to mess with it. That would
+    // mean altering the memory image. There are no special link types or
+    // anything so we can just use a Section.
+    if (Shdr.sh_flags & SHF_ALLOC) {
+      Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
+      return llvm::make_unique<Section>(Data);
+    }
     return llvm::make_unique<StringTableSection>();
+  case SHT_HASH:
+  case SHT_GNU_HASH:
+    // Hash tables should refer to SHT_DYNSYM which we're not going to change.
+    // Because of this we don't need to mess with the hash tables either.
+    Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
+    return llvm::make_unique<Section>(Data);
+  case SHT_DYNSYM:
+    Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
+    return llvm::make_unique<DynamicSymbolTableSection>(Data);
+  case SHT_DYNAMIC:
+    Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
+    return llvm::make_unique<DynamicSection>(Data);
   case SHT_SYMTAB: {
     auto SymTab = llvm::make_unique<SymbolTableSectionImpl<ELFT>>();
     SymbolTable = SymTab.get();
@@ -423,28 +461,35 @@ void Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
   // relocation sections.
   for (auto &Section : Sections) {
     if (auto RelSec = dyn_cast<RelocationSection<ELFT>>(Section.get())) {
-      if (RelSec->Link - 1 >= Sections.size() || RelSec->Link == 0) {
-        error("Link field value " + Twine(RelSec->Link) + " in section " +
-              RelSec->Name + " is invalid");
-      }
-      if (RelSec->Info - 1 >= Sections.size() || RelSec->Info == 0) {
-        error("Info field value " + Twine(RelSec->Link) + " in section " +
-              RelSec->Name + " is invalid");
-      }
-      auto SymTab =
-          dyn_cast<SymbolTableSection>(Sections[RelSec->Link - 1].get());
-      if (SymTab == nullptr) {
-        error("Link field of relocation section " + RelSec->Name +
-              " is not a symbol table");
-      }
+
+      auto SymTab = getSectionOfType<SymbolTableSection>(
+          RelSec->Link,
+          "Link field value " + Twine(RelSec->Link) + " in section " +
+              RelSec->Name + " is invalid",
+          "Link field value " + Twine(RelSec->Link) + " in section " +
+              RelSec->Name + " is not a symbol table");
       RelSec->setSymTab(SymTab);
-      RelSec->setSection(Sections[RelSec->Info - 1].get());
+
+      RelSec->setSection(getSection(RelSec->Info,
+                                    "Info field value " + Twine(RelSec->Link) +
+                                        " in section " + RelSec->Name +
+                                        " is invalid"));
+
       auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index;
       if (RelSec->Type == SHT_REL)
         initRelocations(RelSec, SymTab, unwrapOrError(ElfFile.rels(Shdr)));
       else
         initRelocations(RelSec, SymTab, unwrapOrError(ElfFile.relas(Shdr)));
     }
+
+    if (auto Sec = dyn_cast<SectionWithStrTab>(Section.get())) {
+      Sec->setStrTab(getSectionOfType<StringTableSection>(
+          Sec->Link,
+          "Link field value " + Twine(Sec->Link) + " in section " + Sec->Name +
+              " is invalid",
+          "Link field value " + Twine(Sec->Link) + " in section " + Sec->Name +
+              " is not a string table"));
+    }
   }
 }
 
@@ -462,8 +507,12 @@ template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {
   readSectionHeaders(ElfFile);
   readProgramHeaders(ElfFile);
 
-  SectionNames =
-      dyn_cast<StringTableSection>(Sections[Ehdr.e_shstrndx - 1].get());
+  SectionNames = getSectionOfType<StringTableSection>(
+      Ehdr.e_shstrndx,
+      "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + " in elf header " +
+          " is invalid",
+      "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + " in elf header " +
+          " is not a string table");
 }
 
 template <class ELFT>
index 1b7127e..7a6f013 100644 (file)
@@ -194,6 +194,34 @@ public:
   }
 };
 
+class SectionWithStrTab : public Section {
+private:
+  StringTableSection *StrTab;
+
+public:
+  SectionWithStrTab(llvm::ArrayRef<uint8_t> Data) : Section(Data) {}
+  void setStrTab(StringTableSection *StringTable) { StrTab = StringTable; }
+  void finalize() override;
+  static bool classof(const SectionBase *S);
+};
+
+class DynamicSymbolTableSection : public SectionWithStrTab {
+public:
+  DynamicSymbolTableSection(llvm::ArrayRef<uint8_t> Data)
+      : SectionWithStrTab(Data) {}
+  static bool classof(const SectionBase *S) {
+    return S->Type == llvm::ELF::SHT_DYNSYM;
+  }
+};
+
+class DynamicSection : public SectionWithStrTab {
+public:
+  DynamicSection(llvm::ArrayRef<uint8_t> Data) : SectionWithStrTab(Data) {}
+  static bool classof(const SectionBase *S) {
+    return S->Type == llvm::ELF::SHT_DYNAMIC;
+  }
+};
+
 template <class ELFT> class Object {
 private:
   typedef std::unique_ptr<SectionBase> SecPtr;
@@ -210,6 +238,12 @@ private:
   void readProgramHeaders(const llvm::object::ELFFile<ELFT> &ElfFile);
   void readSectionHeaders(const llvm::object::ELFFile<ELFT> &ElfFile);
 
+  SectionBase *getSection(uint16_t Index, llvm::Twine ErrMsg);
+
+  template <class T>
+  T *getSectionOfType(uint16_t Index, llvm::Twine IndexErrMsg,
+                      llvm::Twine TypeErrMsg);
+
 protected:
   StringTableSection *SectionNames;
   SymbolTableSection *SymbolTable;