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 @@ -97,6 +97,76 @@ ELFStringTableBuilder() : StringTableBuilder(StringTableBuilder::ELF) {} }; +template 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 Symbols; +}; + +template 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 Entries; +}; + template class ELFStubBuilder { public: using Elf_Ehdr = typename ELFT::Ehdr; @@ -110,15 +180,25 @@ 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 *> Sections = {&DynStr, &ShStrTab}; + std::vector *> Sections = {&DynSym, &DynStr, &DynTab, + &ShStrTab}; const OutputSection *LastSection = Sections.back(); // Now set the Index and put sections names into ".shstrtab". uint64_t Index = 1; @@ -130,6 +210,28 @@ 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 *Sec : Sections) { @@ -137,9 +239,15 @@ 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(ElfHeader, Stub.Arch); ElfHeader.e_shstrndx = ShStrTab.Index; @@ -154,9 +262,13 @@ 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 @@ Elf_Ehdr ElfHeader; ContentSection DynStr; ContentSection ShStrTab; + ContentSection, ELFT> DynSym; + ContentSection, ELFT> DynTab; template static void write(uint8_t *Data, const T &Value) { *reinterpret_cast(Data) = Value; @@ -182,7 +296,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->DynStr.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->DynStr.Index; + } uint64_t shdrOffset(const OutputSection &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 --- 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 @@ # 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 @@ # 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 @@ # 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 @@ # 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