mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
[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
This commit is contained in:
@@ -97,6 +97,76 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user