[llvm] 803745b - [llvm-elfabi] Emit ELF .dynsym, .dynamic sections

Haowei Wu via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 24 00:17:30 PST 2020


Author: Haowei Wu
Date: 2020-11-24T00:17:04-08:00
New Revision: 803745b945f46d32770ee8805ef0f458660c441e

URL: https://github.com/llvm/llvm-project/commit/803745b945f46d32770ee8805ef0f458660c441e
DIFF: https://github.com/llvm/llvm-project/commit/803745b945f46d32770ee8805ef0f458660c441e.diff

LOG: [llvm-elfabi] Emit ELF .dynsym, .dynamic sections

This change makes llvm-elfabi tool to emit .dynsym and .dynamic
sections.

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

Added: 
    

Modified: 
    llvm/lib/InterfaceStub/ELFObjHandler.cpp
    llvm/test/tools/llvm-elfabi/write-stub.test

Removed: 
    


################################################################################
diff  --git a/llvm/lib/InterfaceStub/ELFObjHandler.cpp b/llvm/lib/InterfaceStub/ELFObjHandler.cpp
index 76c637b88827..ba583b79571e 100644
--- a/llvm/lib/InterfaceStub/ELFObjHandler.cpp
+++ b/llvm/lib/InterfaceStub/ELFObjHandler.cpp
@@ -97,6 +97,76 @@ class ELFStringTableBuilder : public StringTableBuilder {
   ELFStringTableBuilder() : StringTableBuilder(StringTableBuilder::ELF) {}
 };
 
+template <class ELFT> class ELFSymbolTableBuilder {
+public:
+  using Elf_Sym = typename ELFT::Sym;
+
+  ELFSymbolTableBuilder() { Symbols.push_back({}); }
+
+  void add(size_t StNameOffset, uint64_t StSize, uint8_t StBind, uint8_t StType,
+           uint8_t StOther, uint16_t StShndx) {
+    Elf_Sym S{};
+    S.st_name = StNameOffset;
+    S.st_size = StSize;
+    S.st_info = (StBind << 4) | (StType & 0xf);
+    S.st_other = StOther;
+    S.st_shndx = StShndx;
+    Symbols.push_back(S);
+  }
+
+  size_t getSize() const { return Symbols.size() * sizeof(Elf_Sym); }
+
+  void write(uint8_t *Buf) const {
+    memcpy(Buf, Symbols.data(), sizeof(Elf_Sym) * Symbols.size());
+  }
+
+private:
+  llvm::SmallVector<Elf_Sym, 8> Symbols;
+};
+
+template <class ELFT> class ELFDynamicTableBuilder {
+public:
+  using Elf_Dyn = typename ELFT::Dyn;
+
+  size_t addAddr(uint64_t Tag, uint64_t Addr) {
+    Elf_Dyn Entry;
+    Entry.d_tag = Tag;
+    Entry.d_un.d_ptr = Addr;
+    Entries.push_back(Entry);
+    return Entries.size() - 1;
+  }
+
+  void modifyAddr(size_t Index, uint64_t Addr) {
+    Entries[Index].d_un.d_ptr = Addr;
+  }
+
+  size_t addValue(uint64_t Tag, uint64_t Value) {
+    Elf_Dyn Entry;
+    Entry.d_tag = Tag;
+    Entry.d_un.d_val = Value;
+    Entries.push_back(Entry);
+    return Entries.size() - 1;
+  }
+
+  void modifyValue(size_t Index, uint64_t Value) {
+    Entries[Index].d_un.d_val = Value;
+  }
+
+  size_t getSize() const {
+    // Add DT_NULL entry at the end.
+    return (Entries.size() + 1) * sizeof(Elf_Dyn);
+  }
+
+  void write(uint8_t *Buf) const {
+    memcpy(Buf, Entries.data(), sizeof(Elf_Dyn) * Entries.size());
+    // Add DT_NULL entry at the end.
+    memset(Buf + sizeof(Elf_Dyn) * Entries.size(), 0, sizeof(Elf_Dyn));
+  }
+
+private:
+  llvm::SmallVector<Elf_Dyn, 8> Entries;
+};
+
 template <class ELFT> class ELFStubBuilder {
 public:
   using Elf_Ehdr = typename ELFT::Ehdr;
@@ -110,15 +180,25 @@ template <class ELFT> class ELFStubBuilder {
   ELFStubBuilder(ELFStubBuilder &&) = default;
 
   explicit ELFStubBuilder(const ELFStub &Stub) {
-    // Populate string tables.
-    ShStrTab.Name = ".shstrtab";
-    ShStrTab.Align = 1;
+    DynSym.Name = ".dynsym";
+    DynSym.Align = sizeof(Elf_Addr);
     DynStr.Name = ".dynstr";
     DynStr.Align = 1;
+    DynTab.Name = ".dynamic";
+    DynTab.Align = sizeof(Elf_Addr);
+    ShStrTab.Name = ".shstrtab";
+    ShStrTab.Align = 1;
+
+    // Populate string tables.
     for (const ELFSymbol &Sym : Stub.Symbols)
       DynStr.Content.add(Sym.Name);
+    for (const std::string &Lib : Stub.NeededLibs)
+      DynStr.Content.add(Lib);
+    if (Stub.SoName)
+      DynStr.Content.add(Stub.SoName.getValue());
 
-    std::vector<OutputSection<ELFT> *> Sections = {&DynStr, &ShStrTab};
+    std::vector<OutputSection<ELFT> *> Sections = {&DynSym, &DynStr, &DynTab,
+                                                   &ShStrTab};
     const OutputSection<ELFT> *LastSection = Sections.back();
     // Now set the Index and put sections names into ".shstrtab".
     uint64_t Index = 1;
@@ -130,6 +210,28 @@ template <class ELFT> class ELFStubBuilder {
     ShStrTab.Size = ShStrTab.Content.getSize();
     DynStr.Content.finalize();
     DynStr.Size = DynStr.Content.getSize();
+
+    // Populate dynamic symbol table.
+    for (const ELFSymbol &Sym : Stub.Symbols) {
+      uint8_t Bind = Sym.Weak ? STB_WEAK : STB_GLOBAL;
+      // For non-undefined symbols, value of the shndx is not relevant at link
+      // time as long as it is not SHN_UNDEF. Set shndx to 1, which
+      // points to ".dynsym".
+      uint16_t Shndx = Sym.Undefined ? SHN_UNDEF : 1;
+      DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Sym.Size, Bind,
+                         (uint8_t)Sym.Type, 0, Shndx);
+    }
+    DynSym.Size = DynSym.Content.getSize();
+
+    // Poplulate dynamic table.
+    size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0);
+    size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0);
+    for (const std::string &Lib : Stub.NeededLibs)
+      DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib));
+    if (Stub.SoName)
+      DynTab.Content.addValue(DT_SONAME,
+                              DynStr.Content.getOffset(Stub.SoName.getValue()));
+    DynTab.Size = DynTab.Content.getSize();
     // Calculate sections' addresses and offsets.
     uint64_t CurrentOffset = sizeof(Elf_Ehdr);
     for (OutputSection<ELFT> *Sec : Sections) {
@@ -137,9 +239,15 @@ template <class ELFT> class ELFStubBuilder {
       Sec->Addr = Sec->Offset;
       CurrentOffset = Sec->Offset + Sec->Size;
     }
+    // Fill Addr back to dynamic table.
+    DynTab.Content.modifyAddr(DynSymIndex, DynSym.Addr);
+    DynTab.Content.modifyAddr(DynStrIndex, DynStr.Addr);
     // Write section headers of string tables.
+    fillSymTabShdr(DynSym, SHT_DYNSYM);
     fillStrTabShdr(DynStr, SHF_ALLOC);
+    fillDynTabShdr(DynTab);
     fillStrTabShdr(ShStrTab);
+
     // Finish initializing the ELF header.
     initELFHeader<ELFT>(ElfHeader, Stub.Arch);
     ElfHeader.e_shstrndx = ShStrTab.Index;
@@ -154,9 +262,13 @@ template <class ELFT> class ELFStubBuilder {
 
   void write(uint8_t *Data) const {
     write(Data, ElfHeader);
+    DynSym.Content.write(Data + DynSym.Shdr.sh_offset);
     DynStr.Content.write(Data + DynStr.Shdr.sh_offset);
+    DynTab.Content.write(Data + DynTab.Shdr.sh_offset);
     ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset);
+    writeShdr(Data, DynSym);
     writeShdr(Data, DynStr);
+    writeShdr(Data, DynTab);
     writeShdr(Data, ShStrTab);
   }
 
@@ -164,6 +276,8 @@ template <class ELFT> class ELFStubBuilder {
   Elf_Ehdr ElfHeader;
   ContentSection<ELFStringTableBuilder, ELFT> DynStr;
   ContentSection<ELFStringTableBuilder, ELFT> ShStrTab;
+  ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> DynSym;
+  ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> DynTab;
 
   template <class T> static void write(uint8_t *Data, const T &Value) {
     *reinterpret_cast<T *>(Data) = Value;
@@ -182,7 +296,32 @@ template <class ELFT> class ELFStubBuilder {
     StrTab.Shdr.sh_entsize = 0;
     StrTab.Shdr.sh_link = 0;
   }
-
+  void fillSymTabShdr(ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> &SymTab,
+                      uint32_t ShType) const {
+    SymTab.Shdr.sh_type = ShType;
+    SymTab.Shdr.sh_flags = SHF_ALLOC;
+    SymTab.Shdr.sh_addr = SymTab.Addr;
+    SymTab.Shdr.sh_offset = SymTab.Offset;
+    SymTab.Shdr.sh_info = SymTab.Size / sizeof(Elf_Sym) > 1 ? 1 : 0;
+    SymTab.Shdr.sh_size = SymTab.Size;
+    SymTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(SymTab.Name);
+    SymTab.Shdr.sh_addralign = SymTab.Align;
+    SymTab.Shdr.sh_entsize = sizeof(Elf_Sym);
+    SymTab.Shdr.sh_link = this->DynStr.Index;
+  }
+  void fillDynTabShdr(
+      ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> &DynTab) const {
+    DynTab.Shdr.sh_type = SHT_DYNAMIC;
+    DynTab.Shdr.sh_flags = SHF_ALLOC;
+    DynTab.Shdr.sh_addr = DynTab.Addr;
+    DynTab.Shdr.sh_offset = DynTab.Offset;
+    DynTab.Shdr.sh_info = 0;
+    DynTab.Shdr.sh_size = DynTab.Size;
+    DynTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(DynTab.Name);
+    DynTab.Shdr.sh_addralign = DynTab.Align;
+    DynTab.Shdr.sh_entsize = sizeof(Elf_Dyn);
+    DynTab.Shdr.sh_link = this->DynStr.Index;
+  }
   uint64_t shdrOffset(const OutputSection<ELFT> &Sec) const {
     return ElfHeader.e_shoff + Sec.Index * sizeof(Elf_Shdr);
   }

diff  --git a/llvm/test/tools/llvm-elfabi/write-stub.test b/llvm/test/tools/llvm-elfabi/write-stub.test
index b2053da409fa..837c508b4858 100644
--- a/llvm/test/tools/llvm-elfabi/write-stub.test
+++ b/llvm/test/tools/llvm-elfabi/write-stub.test
@@ -1,23 +1,26 @@
 ## Test writing stub elf with minimal sections.
 
 # RUN: llvm-elfabi %s --output-target=elf32-little %t.elf32l
-# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab %t.elf32l | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="LittleEndian (0x1)" -DHS=52 -DPHES=32 -DSHES=40
+# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf32l | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="LittleEndian (0x1)" -DHS=52 -DPHES=32 -DSHES=40 -DDYNSYMAL=4 -DDYNSYMES=16 -DDYNAMICAL=4 -DDYNAMICES=8 -DDYNTABZ=0
 
 # RUN: llvm-elfabi %s --output-target=elf32-big %t.elf32b
-# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab %t.elf32b | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="BigEndian (0x2)" -DHS=52 -DPHES=32 -DSHES=40
+# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf32b | FileCheck %s -DCLASS="32-bit (0x1)" -DDE="BigEndian (0x2)" -DHS=52 -DPHES=32 -DSHES=40 -DDYNSYMAL=4 -DDYNSYMES=16 -DDYNAMICAL=4 -DDYNAMICES=8 -DDYNTABZ=0
 
 # RUN: llvm-elfabi %s --output-target=elf64-little %t.elf64l
-# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab %t.elf64l | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64
+# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64l | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="LittleEndian (0x1)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000
 
 # RUN: llvm-elfabi %s --output-target=elf64-big %t.elf64b
-# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab %t.elf64b | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="BigEndian (0x2)" -DHS=64 -DPHES=56 -DSHES=64
+# RUN: llvm-readobj -h -S --string-dump .dynstr --string-dump .shstrtab --dyn-symbols --dynamic-table %t.elf64b | FileCheck %s -DCLASS="64-bit (0x2)" -DDE="BigEndian (0x2)" -DHS=64 -DPHES=56 -DSHES=64 -DDYNSYMAL=8 -DDYNSYMES=24 -DDYNAMICAL=8 -DDYNAMICES=16 -DDYNTABZ=000000000
 
 --- !tapi-tbe
 TbeVersion: 1.0
 Arch: x86_64
+NeededLibs:
+  - libc.so.6
 Symbols:
   bar: { Type: Object, Size: 42 }
   baz: { Type: TLS, Size: 3 }
+  plus: { Type: Func }
 ...
 
 # CHECK:      ElfHeader {
@@ -39,8 +42,8 @@ Symbols:
 # CHECK-NEXT:   HeaderSize: [[HS]]
 # CHECK-NEXT:   ProgramHeaderEntrySize: [[PHES]]
 # CHECK:        SectionHeaderEntrySize: [[SHES]]
-# CHECK:        SectionHeaderCount: 3
-# CHECK:        StringTableSectionIndex: 2
+# CHECK:        SectionHeaderCount: 5
+# CHECK:        StringTableSectionIndex: 4
 
 # CHECK:      Section {
 # CHECK-NEXT:   Index: 0
@@ -58,6 +61,21 @@ Symbols:
 # CHECK-NEXT: }
 # CHECK-NEXT: Section {
 # CHECK-NEXT:   Index: 1
+# CHECK-NEXT:   Name: .dynsym
+# CHECK-NEXT:   Type: SHT_DYNSYM
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link: 2
+# CHECK-NEXT:   Info: 1
+# CHECK-NEXT:   AddressAlignment: [[DYNSYMAL]]
+# CHECK-NEXT:   EntrySize: [[DYNSYMES]]
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 2
 # CHECK-NEXT:   Name: .dynstr
 # CHECK-NEXT:   Type: SHT_STRTAB
 # CHECK-NEXT:   Flags [
@@ -72,7 +90,22 @@ Symbols:
 # CHECK-NEXT:   EntrySize: 0
 # CHECK-NEXT: }
 # CHECK-NEXT: Section {
-# CHECK-NEXT:   Index: 2
+# CHECK-NEXT:   Index: 3
+# CHECK-NEXT:   Name: .dynamic
+# CHECK-NEXT:   Type: SHT_DYNAMIC
+# CHECK-NEXT:   Flags [
+# CHECK-NEXT:     SHF_ALLOC
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   Address:
+# CHECK-NEXT:   Offset:
+# CHECK-NEXT:   Size:
+# CHECK-NEXT:   Link: 2
+# CHECK-NEXT:   Info: 0
+# CHECK-NEXT:   AddressAlignment: [[DYNAMICAL]]
+# CHECK-NEXT:   EntrySize: [[DYNAMICES]]
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT:   Index: 4
 # CHECK-NEXT:   Name: .shstrtab
 # CHECK-NEXT:   Type: SHT_STRTAB
 # CHECK-NEXT:   Flags [
@@ -86,10 +119,59 @@ Symbols:
 # CHECK-NEXT:   EntrySize: 0
 # CHECK-NEXT: }
 
+# CHECK:      DynamicSection [ (4 entries)
+# CHECK-NEXT:   Tag                Type   Name/Value
+# CHECK-NEXT:   0x[[DYNTABZ]]0000006 SYMTAB
+# CHECK-NEXT:   0x[[DYNTABZ]]0000005 STRTAB
+# CHECK-NEXT:   0x[[DYNTABZ]]0000001 NEEDED Shared library: [libc.so.6]
+# CHECK-NEXT:   0x[[DYNTABZ]]0000000 NULL
+# CHECK-NEXT: ]
+
+# CHECK:        Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: bar
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size: 42
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Object
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .dynsym
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: baz
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size: 3
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: TLS
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .dynsym
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: plus
+# CHECK-NEXT:     Value:
+# CHECK-NEXT:     Size:
+# CHECK-NEXT:     Binding: Global
+# CHECK-NEXT:     Type: Function
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .dynsym
+# CHECK-NEXT: }
+
 # CHECK:      String dump of section '.dynstr':
 # CHECK-NEXT: [     1] baz
-# CHECK-NEXT: [     5] bar
+# CHECK-NEXT: [     5] plus
+# CHECK-NEXT: [     a] bar
+# CHECK-NEXT: [     e] libc.so.6
 
 # CHECK:      String dump of section '.shstrtab':
 # CHECK-NEXT: [     1] .dynstr
-# CHECK-NEXT: [     9] .shstrtab
+# CHECK-NEXT: [     9] .dynsym
+# CHECK-NEXT: [    11] .dynamic
+# CHECK-NEXT: [    1a] .shstrtab


        


More information about the llvm-commits mailing list