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 @@ -226,6 +226,7 @@ // Poplulate dynamic table. size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0); size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0); + DynTab.Content.addValue(DT_STRSZ, DynSym.Size); for (const std::string &Lib : Stub.NeededLibs) DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib)); if (Stub.SoName) @@ -501,6 +502,70 @@ return Error::success(); } +/// Returns the StringRef to the DynStr from an ElfFile +/// @param ElfFile Reference to the ELFFile object. +/// @param DynEnt Reference to the DynamicEntries object. +template +static Expected getDynStr(const ELFFile &ElfFile, + const DynamicEntries &DynEnt) { + using Elf_Shdr_Range = typename ELFT::ShdrRange; + using Elf_Shdr = typename ELFT::Shdr; + + // Read offset from section headers. + Expected Shdrs = ElfFile.sections(); + if (!Shdrs) { + return Shdrs.takeError(); + } + if (Shdrs.get().size()) { + for (const Elf_Shdr &Sec : *Shdrs) { + if (Sec.sh_type == ELF::SHT_DYNSYM) { + // If multiple .dynsym presents, uses the first one. + // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize() + return ElfFile.getStringTableForSymtab(Sec, *Shdrs); + } + } + } + // Fallback to use offsets from .dynamic as there is no section header + // present. + Expected DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr); + if (!DynStrPtr) + return appendToError(DynStrPtr.takeError(), + "when locating .dynstr section contents"); + return StringRef(reinterpret_cast(*DynStrPtr), DynEnt.StrSize); +} + +/// Returns the in-memory pointer to the DynSym from an ElfFile +/// @param ElfFile Reference to the ELFFile object. +/// @param DynEnt Reference to the DynamicEntries object. +template +static Expected getDynSymPtr(const ELFFile &ElfFile, + const DynamicEntries &DynEnt) { + using Elf_Shdr_Range = typename ELFT::ShdrRange; + using Elf_Shdr = typename ELFT::Shdr; + + Expected Shdrs = ElfFile.sections(); + if (!Shdrs) { + return Shdrs.takeError(); + } + if (Shdrs.get().size()) { + for (const Elf_Shdr &Sec : *Shdrs) { + if (Sec.sh_type == ELF::SHT_DYNSYM) { + // If multiple .dynsym presents, uses the first one. + // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize() + return ElfFile.base() + Sec.sh_offset; + } + } + } + // Fallback to use offsets from .dynamic as there is no section header + // present. + Expected EDynSymPtr = + ElfFile.toMappedAddr(DynEnt.DynSymAddr); + if (!EDynSymPtr) + return appendToError(EDynSymPtr.takeError(), + "when locating .dynsym section contents"); + return EDynSymPtr.get(); +} + /// Returns a new IFSStub with all members populated from an ELFObjectFile. /// @param ElfObj Source ELFObjectFile. template @@ -508,6 +573,7 @@ buildStub(const ELFObjectFile &ElfObj) { using Elf_Dyn_Range = typename ELFT::DynRange; using Elf_Phdr_Range = typename ELFT::PhdrRange; + using Elf_Shdr_Range = typename ELFT::ShdrRange; using Elf_Sym_Range = typename ELFT::SymRange; using Elf_Sym = typename ELFT::Sym; std::unique_ptr DestStub = std::make_unique(); @@ -518,25 +584,16 @@ return DynTable.takeError(); } - // Fetch program headers. - Expected PHdrs = ElfFile.program_headers(); - if (!PHdrs) { - return PHdrs.takeError(); - } - // Collect relevant .dynamic entries. DynamicEntries DynEnt; if (Error Err = populateDynamic(DynEnt, *DynTable)) return std::move(Err); - // Get pointer to in-memory location of .dynstr section. - Expected DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr); - if (!DynStrPtr) - return appendToError(DynStrPtr.takeError(), - "when locating .dynstr section contents"); - - StringRef DynStr(reinterpret_cast(DynStrPtr.get()), - DynEnt.StrSize); + Expected EDynStr = getDynStr(ElfFile, DynEnt); + if (!EDynStr) { + return EDynStr.takeError(); + } + StringRef DynStr = EDynStr.get(); // Populate Arch from ELF header. DestStub->Target.Arch = static_cast(ElfFile.getHeader().e_machine); @@ -572,8 +629,7 @@ return SymCount.takeError(); if (*SymCount > 0) { // Get pointer to in-memory location of .dynsym section. - Expected DynSymPtr = - ElfFile.toMappedAddr(DynEnt.DynSymAddr); + Expected DynSymPtr = getDynSymPtr(ElfFile, DynEnt); if (!DynSymPtr) return appendToError(DynSymPtr.takeError(), "when locating .dynsym section contents"); diff --git a/llvm/test/tools/llvm-ifs/ifs-elf-conversion.test b/llvm/test/tools/llvm-ifs/ifs-elf-conversion.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ifs/ifs-elf-conversion.test @@ -0,0 +1,25 @@ +## Test writing stub ELF from IFS and read stub ELF to regenerate IFS. + +# RUN: llvm-ifs --output-elf=%t.elf64l --arch=x86_64 --bitwidth=64 --endianness=little %s + +# RUN: llvm-ifs --output-ifs=- --strip-ifs-target %t.elf64l | FileCheck %s + +--- !ifs-v1 +IfsVersion: 3.0 +NeededLibs: + - libc.so.6 +Symbols: + - { Name: bar, Type: Object, Size: 42 } + - { Name: baz, Type: TLS, Size: 3 } + - { Name: plus, Type: Func } +... + +# CHECK: --- !ifs-v1 +# CHECK-NEXT: IfsVersion: 3.0 +# CHECK-NEXT: NeededLibs: +# CHECK-NEXT: - libc.so.6 +# CHECK-NEXT: Symbols: +# CHECK-NEXT: - { Name: bar, Type: Object, Size: 42 } +# CHECK-NEXT: - { Name: baz, Type: TLS, Size: 3 } +# CHECK-NEXT: - { Name: plus, Type: Func } +# CHECK-NEXT: ... diff --git a/llvm/test/tools/llvm-ifs/write-stub.test b/llvm/test/tools/llvm-ifs/write-stub.test --- a/llvm/test/tools/llvm-ifs/write-stub.test +++ b/llvm/test/tools/llvm-ifs/write-stub.test @@ -142,10 +142,11 @@ # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } -# CHECK: DynamicSection [ (4 entries) +# CHECK: DynamicSection [ (5 entries) # CHECK-NEXT: Tag Type Name/Value # CHECK-NEXT: 0x[[DYNTABZ]]0000006 SYMTAB # CHECK-NEXT: 0x[[DYNTABZ]]0000005 STRTAB +# CHECK-NEXT: 0x[[DYNTABZ]]000000A STRSZ # CHECK-NEXT: 0x[[DYNTABZ]]0000001 NEEDED Shared library: [libc.so.6] # CHECK-NEXT: 0x[[DYNTABZ]]0000000 NULL # CHECK-NEXT: ]