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,86 @@ ELFStringTableBuilder() : StringTableBuilder(StringTableBuilder::ELF) {} }; +template class ELFSymbolTableBuilder { +public: + using Elf_Sym = typename ELFT::Sym; + + ELFSymbolTableBuilder() { + Elf_Sym S{}; + Symbols.push_back(S); + } + + 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 Symbols; +}; + +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 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)); + } +}; + template class ELFStubBuilder { public: using Elf_Ehdr = typename ELFT::Ehdr; @@ -116,6 +196,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 +215,32 @@ StrTab.Shdr.sh_entsize = 0; StrTab.Shdr.sh_link = 0; } + void fillSymTabShdr(ContentSection, 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->StrTab.Index; + } + void fillDynTabShdr( + ContentSection, 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->StrTab.Index; + } uint64_t shdrOffset(const OutputSection &Sec) const { return ElfHeader.e_shoff + Sec.Index * sizeof(Elf_Shdr); } @@ -144,17 +252,27 @@ ELFStubBuilder(const ELFStubBuilder &) = delete; ELFStubBuilder(ELFStubBuilder &&) = default; explicit ELFStubBuilder(const ELFStub &Stub) { - // populate string tables. - ShStrTab.Name = ".shstrtab"; - ShStrTab.Align = 0; + DynSym.Name = ".dynsym"; + DynSym.Align = sizeof(Elf_Addr); StrTab.Name = ".dynstr"; StrTab.Align = 0; - for (const auto &Sym : Stub.Symbols) { + DynTab.Name = ".dynamic"; + DynTab.Align = sizeof(Elf_Addr); + ShStrTab.Name = ".shstrtab"; + ShStrTab.Align = 0; + + // Populate string tables. + for (const auto &Sym : Stub.Symbols) StrTab.Content.add(Sym.Name); - } - std::vector *> Sections; - Sections.push_back(&ShStrTab); + 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(&DynSym); Sections.push_back(&StrTab); + Sections.push_back(&DynTab); + Sections.push_back(&ShStrTab); const OutputSection *LastSection = Sections.back(); // Now set the Index and put sections names into .shstrtab . uint64_t Index = 1; @@ -167,6 +285,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.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 auto &Lib : Stub.NeededLibs) + DynTab.Content.addValue(DT_NEEDED, StrTab.Content.getOffset(Lib)); + if (Stub.SoName) + DynTab.Content.addValue(DT_SONAME, + StrTab.Content.getOffset(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 +324,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; @@ -206,10 +349,14 @@ } void write(uint8_t *Data) const { write(Data, ElfHeader); - ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset); + DynSym.Content.write(Data + DynSym.Shdr.sh_offset); StrTab.Content.write(Data + StrTab.Shdr.sh_offset); - writeShdr(Data, ShStrTab); + DynTab.Content.write(Data + DynTab.Shdr.sh_offset); + ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset); + writeShdr(Data, DynSym); writeShdr(Data, StrTab); + writeShdr(Data, DynTab); + writeShdr(Data, ShStrTab); } }; /// 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,18 +3,22 @@ # 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: StringTableSectionIndex: 1 +# ELFHEADER: SectionHeaderCount: 5 +# ELFHEADER: StringTableSectionIndex: 4 # SECTIONS: Section { # SECTIONS-NEXT: Index: 0 @@ -30,11 +34,27 @@ # SECTIONS-NEXT: AddressAlignment: 0 # SECTIONS-NEXT: EntrySize: 0 # SECTIONS-NEXT: } +# SECTIONS-NEXT: Section { +# SECTIONS-NEXT: Index: 1 +# 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: 1 -# SECTIONS-NEXT: Name: .shstrtab +# SECTIONS-NEXT: Index: 2 +# SECTIONS-NEXT: Name: .dynstr # SECTIONS-NEXT: Type: SHT_STRTAB # SECTIONS-NEXT: Flags [ +# SECTIONS-NEXT: SHF_ALLOC # SECTIONS-NEXT: ] # SECTIONS-NEXT: Address: # SECTIONS-NEXT: Offset: @@ -44,12 +64,26 @@ # SECTIONS-NEXT: AddressAlignment: 0 # SECTIONS-NEXT: EntrySize: 0 # SECTIONS-NEXT: } +# SECTIONS-NEXT: Section { +# SECTIONS-NEXT: Index: 3 +# SECTIONS-NEXT: Name: .dynamic +# SECTIONS-NEXT: Type: SHT_DYNAMIC +# 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: 0 +# SECTIONS-NEXT: AddressAlignment: 8 +# SECTIONS-NEXT: EntrySize: 16 +# SECTIONS-NEXT: } # SECTIONS-NEXT: Section { -# SECTIONS-NEXT: Index: 2 -# SECTIONS-NEXT: Name: .dynstr +# SECTIONS-NEXT: Index: 4 +# SECTIONS-NEXT: Name: .shstrtab # SECTIONS-NEXT: Type: SHT_STRTAB # SECTIONS-NEXT: Flags [ -# SECTIONS-NEXT: SHF_ALLOC # SECTIONS-NEXT: ] # SECTIONS-NEXT: Address: # SECTIONS-NEXT: Offset: @@ -62,8 +96,57 @@ # 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: ]