diff --git a/llvm/lib/InterfaceStub/ELFObjHandler.cpp b/llvm/lib/InterfaceStub/ELFObjHandler.cpp --- a/llvm/lib/InterfaceStub/ELFObjHandler.cpp +++ b/llvm/lib/InterfaceStub/ELFObjHandler.cpp @@ -103,6 +103,114 @@ ELFStringTableBuilder() : StringTableBuilder(StringTableBuilder::ELF) {} }; +template class ELFSymbolTableBuilder { +public: + using Elf_Sym = typename ELFT::Sym; + +private: + llvm::SmallVector Symbols; + +public: + ELFSymbolTableBuilder() { + Elf_Sym S; + S.st_name = 0; + S.st_value = 0; + S.st_size = 0; + S.st_info = 0; + S.st_other = 0; + S.st_shndx = SHN_UNDEF; + Symbols.push_back(S); + } + + void add(ELFStringTableBuilder &StrTabBuilder, StringRef StName, + uint64_t StSize, uint8_t StBind, uint8_t StType, uint8_t StOther, + uint16_t StShndx) { + Elf_Sym S; + S.st_name = StrTabBuilder.getOffset(StName); + // TODO: Implement a address generator. + S.st_value = 0; + 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 { + size_t Offset = 0; + for (const auto &Sym : Symbols) { + memcpy(Buf + Offset, &Sym, sizeof(Elf_Sym)); + Offset += sizeof(Elf_Sym); + } + } +}; + +template class ELFDynamicTableBuilder { +public: + using Elf_Dyn = typename ELFT::Dyn; + +private: + llvm::SmallVector Entries; + +public: + 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 Tag, uint64_t Addr) { + Elf_Dyn Entry; + Entry.d_tag = Tag; + Entry.d_un.d_ptr = Addr; + Entries[Index] = Entry; + } + + 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 Tag, uint64_t Value) { + Elf_Dyn Entry; + Entry.d_tag = Tag; + Entry.d_un.d_val = Value; + Entries[Index] = Entry; + } + + size_t addNeededLib(ContentSection &StrTab, + StringRef LibName) { + return this->addValue(DT_NEEDED, StrTab.Content.getOffset(LibName)); + } + size_t addSOName(ContentSection &StrTab, + StringRef SOName) { + return this->addValue(DT_SONAME, StrTab.Content.getOffset(SOName)); + } + size_t getSize() const { + // Add DT_NULL entry at the end. + return (Entries.size() + 1) * sizeof(Elf_Dyn); + } + + void write(uint8_t *Buf) const { + size_t Offset = 0; + for (const auto &Entry : Entries) { + memcpy(Buf + Offset, &Entry, sizeof(Elf_Dyn)); + Offset += sizeof(Elf_Dyn); + } + // Add DT_NULL entry at the end. + Elf_Dyn Terminator; + memset(&Terminator, 0, sizeof(Elf_Dyn)); + memcpy(Buf + Offset, &Terminator, sizeof(Elf_Dyn)); + } +}; + template class ELFStubBuilder { public: using Elf_Ehdr = typename ELFT::Ehdr; @@ -116,6 +224,8 @@ Elf_Ehdr ElfHeader; ContentSection StrTab; ContentSection ShStrTab; + ContentSection, ELFT> DynSym; + ContentSection, ELFT> DynTab; template static void write(uint8_t *Data, const T &Value) { *reinterpret_cast(Data) = Value; @@ -133,6 +243,33 @@ StrTab.Shdr.sh_entsize = 0; StrTab.Shdr.sh_link = 0; } + void fillSymTabShdr(ContentSection, ELFT> &SymTab, + uint32_t ShType) const { + SymTab.Shdr.sh_type = ShType; + // TODO: Verify if other flags are needed. + 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->StrTab.Index; + } + void fillDynTabShdr( + ContentSection, ELFT> &DynTab) const { + DynTab.Shdr.sh_type = SHT_DYNAMIC; + DynTab.Shdr.sh_flags = SHF_ALLOC | SHF_WRITE; + 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->StrTab.Index; + } uint64_t shdrOffset(const OutputSection &Sec) const { return ElfHeader.e_shoff + Sec.Index * sizeof(Elf_Shdr); } @@ -144,17 +281,29 @@ ELFStubBuilder(const ELFStubBuilder &) = delete; ELFStubBuilder(ELFStubBuilder &&) = default; explicit ELFStubBuilder(const ELFStub &Stub) { - // populate string tables. ShStrTab.Name = ".shstrtab"; ShStrTab.Align = 0; StrTab.Name = ".dynstr"; StrTab.Align = 0; + DynSym.Name = ".dynsym"; + DynSym.Align = sizeof(Elf_Sym) == 16 ? 4 : 8; + DynTab.Name = ".dynamic"; + DynTab.Align = sizeof(Elf_Dyn) == 8 ? 4 : 8; + + // populate string tables. for (const auto &Sym : Stub.Symbols) { StrTab.Content.add(Sym.Name); } - std::vector *> Sections; + for (const auto &Lib : Stub.NeededLibs) { + StrTab.Content.add(Lib); + } + if (Stub.SoName) + StrTab.Content.add(Stub.SoName.getValue()); + llvm::SmallVector *, 8> Sections; Sections.push_back(&ShStrTab); Sections.push_back(&StrTab); + Sections.push_back(&DynSym); + Sections.push_back(&DynTab); const OutputSection *LastSection = Sections.back(); // Now set the Index and put sections names into .shstrtab . uint64_t Index = 1; @@ -167,6 +316,26 @@ ShStrTab.Size = ShStrTab.Content.getSize(); StrTab.Content.finalize(); StrTab.Size = StrTab.Content.getSize(); + + // populate dynamic symbol table + for (const auto &Sym : Stub.Symbols) { + uint8_t Bind = Sym.Weak ? STB_WEAK : STB_GLOBAL; + // TODO: Points st_shndx to a dummy .text section. + uint16_t Shndx = Sym.Undefined ? SHN_UNDEF : 1; + DynSym.Content.add(StrTab.Content, 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 auto &Lib : Stub.NeededLibs) { + DynTab.Content.addNeededLib(StrTab, Lib); + } + if (Stub.SoName) + DynTab.Content.addSOName(StrTab, Stub.SoName.getValue()); + DynTab.Size = DynTab.Content.getSize(); // Calculate sections' addrs and offsets. const OutputSection *Prev = nullptr; uint64_t StartOffset = sizeof(Elf_Ehdr); @@ -186,9 +355,14 @@ Sec->Addr = alignTo(Prev->Addr + Prev->Size, Align); Prev = Sec; } + // Fill Addr back to dynamic table. + DynTab.Content.modifyAddr(DynSymIndex, DT_SYMTAB, DynSym.Addr); + DynTab.Content.modifyAddr(DynStrIndex, DT_STRTAB, StrTab.Addr); // Write Shdr of String tables fillStrTabShdr(StrTab, SHF_ALLOC); fillStrTabShdr(ShStrTab); + fillSymTabShdr(DynSym, SHT_DYNSYM); + fillDynTabShdr(DynTab); // Initilize ELFheader initELFHeader(ElfHeader, Stub.Arch); ElfHeader.e_shstrndx = ShStrTab.Index; @@ -208,8 +382,12 @@ write(Data, ElfHeader); ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset); StrTab.Content.write(Data + StrTab.Shdr.sh_offset); + DynSym.Content.write(Data + DynSym.Shdr.sh_offset); + DynTab.Content.write(Data + DynTab.Shdr.sh_offset); writeShdr(Data, ShStrTab); writeShdr(Data, StrTab); + writeShdr(Data, DynSym); + writeShdr(Data, DynTab); } }; /// This function behaves similarly to StringRef::substr(), but attempts to diff --git a/llvm/test/tools/llvm-elfabi/binary-write-sheaders.test b/llvm/test/tools/llvm-elfabi/binary-write-sheaders.test --- a/llvm/test/tools/llvm-elfabi/binary-write-sheaders.test +++ b/llvm/test/tools/llvm-elfabi/binary-write-sheaders.test @@ -3,17 +3,21 @@ # RUN: llvm-readobj -S %t | FileCheck %s --check-prefix=SECTIONS # RUN: llvm-readobj --string-dump .shstrtab %t | FileCheck %s --check-prefix=SHSTRTAB # RUN: llvm-readobj --string-dump .dynstr %t | FileCheck %s --check-prefix=DYNSTR - +# RUN: llvm-readobj --dyn-symbols %t | FileCheck %s --check-prefix=DYNSYM +# RUN: llvm-readobj --dynamic-table %t | FileCheck %s --check-prefix=DYNAMIC --- !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 } ... -# ELFHEADER: SectionHeaderCount: 3 +# ELFHEADER: SectionHeaderCount: 5 # ELFHEADER: StringTableSectionIndex: 1 # SECTIONS: Section { @@ -59,11 +63,91 @@ # SECTIONS-NEXT: AddressAlignment: 0 # SECTIONS-NEXT: EntrySize: 0 # SECTIONS-NEXT: } +# SECTIONS-NEXT: Section { +# SECTIONS-NEXT: Index: 3 +# SECTIONS-NEXT: Name: .dynsym +# SECTIONS-NEXT: Type: SHT_DYNSYM +# SECTIONS-NEXT: Flags [ +# SECTIONS-NEXT: SHF_ALLOC +# SECTIONS-NEXT: ] +# SECTIONS-NEXT: Address: +# SECTIONS-NEXT: Offset: +# SECTIONS-NEXT: Size: +# SECTIONS-NEXT: Link: 2 +# SECTIONS-NEXT: Info: 1 +# SECTIONS-NEXT: AddressAlignment: 8 +# SECTIONS-NEXT: EntrySize: 24 +# SECTIONS-NEXT: } +# SECTIONS-NEXT: Section { +# SECTIONS-NEXT: Index: 4 +# SECTIONS-NEXT: Name: .dynamic +# SECTIONS-NEXT: Type: SHT_DYNAMIC +# SECTIONS-NEXT: Flags [ +# SECTIONS-NEXT: SHF_ALLOC +# SECTIONS-NEXT: SHF_WRITE +# SECTIONS-NEXT: ] +# SECTIONS-NEXT: Address: +# SECTIONS-NEXT: Offset: +# SECTIONS-NEXT: Size: +# SECTIONS-NEXT: Link: 2 +# SECTIONS-NEXT: Info: 0 +# SECTIONS-NEXT: AddressAlignment: 8 +# SECTIONS-NEXT: EntrySize: 16 +# SECTIONS-NEXT: } # SHSTRTAB: String dump of section '.shstrtab': # SHSTRTAB-NEXT: [ 1] .dynstr -# SHSTRTAB-NEXT: [ 9] .shstrtab +# SHSTRTAB-NEXT: [ 9] .dynsym +# SHSTRTAB-NEXT: [ 11] .dynamic +# SHSTRTAB-NEXT: [ 1a] .shstrtab # DYNSTR: String dump of section '.dynstr': # DYNSTR-NEXT: [ 1] baz -# DYNSTR-NEXT: [ 5] bar +# DYNSTR-NEXT: [ 5] plus +# DYNSTR-NEXT: [ a] bar +# DYNSTR-NEXT: [ e] libc.so.6 + +# DYNSYM: Symbol { +# DYNSYM-NEXT: Name: +# DYNSYM-NEXT: Value: +# DYNSYM-NEXT: Size: +# DYNSYM-NEXT: Binding: Local +# DYNSYM-NEXT: Type: None +# DYNSYM-NEXT: Other: 0 +# DYNSYM-NEXT: Section: Undefined +# DYNSYM-NEXT: } +# DYNSYM-NEXT: Symbol { +# DYNSYM-NEXT: Name: bar +# DYNSYM-NEXT: Value: +# DYNSYM-NEXT: Size: 42 +# DYNSYM-NEXT: Binding: Global +# DYNSYM-NEXT: Type: Object +# DYNSYM-NEXT: Other: 0 +# DYNSYM-NEXT: Section: +# DYNSYM-NEXT: } +# DYNSYM-NEXT: Symbol { +# DYNSYM-NEXT: Name: baz +# DYNSYM-NEXT: Value: +# DYNSYM-NEXT: Size: 3 +# DYNSYM-NEXT: Binding: Global +# DYNSYM-NEXT: Type: TLS +# DYNSYM-NEXT: Other: 0 +# DYNSYM-NEXT: Section: +# DYNSYM-NEXT: } +# DYNSYM-NEXT: Symbol { +# DYNSYM-NEXT: Name: plus +# DYNSYM-NEXT: Value: +# DYNSYM-NEXT: Size: +# DYNSYM-NEXT: Binding: Global +# DYNSYM-NEXT: Type: Function +# DYNSYM-NEXT: Other: 0 +# DYNSYM-NEXT: Section: +# DYNSYM-NEXT: } + +# DYNAMIC: DynamicSection [ +# DYNAMIC-NEXT: Tag Type Name/Value +# DYNAMIC-NEXT: 0x0000000000000006 SYMTAB +# DYNAMIC-NEXT: 0x0000000000000005 STRTAB +# DYNAMIC-NEXT: 0x0000000000000001 NEEDED Shared library: [libc.so.6] +# DYNAMIC-NEXT: 0x0000000000000000 NULL +# DYNAMIC-NEXT: ]