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 @@ -502,6 +502,68 @@ 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 are present, use the first one. + // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize() + return ElfFile.getStringTableForSymtab(Sec, *Shdrs); + } + } + } + // Fallback to use offsets from .dynamic as .dynsym was not found. + 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 are present, use the first one. + // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize() + return ElfFile.base() + Sec.sh_offset; + } + } + } + // Fallback to use offsets from .dynamic as .dynsym was not found. + 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 @@ -519,25 +581,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"); + Expected EDynStr = getDynStr(ElfFile, DynEnt); + if (!EDynStr) + return EDynStr.takeError(); - StringRef DynStr(reinterpret_cast(DynStrPtr.get()), - DynEnt.StrSize); + StringRef DynStr = EDynStr.get(); // Populate Arch from ELF header. DestStub->Target.Arch = static_cast(ElfFile.getHeader().e_machine); @@ -573,8 +626,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: ...