[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