diff --git a/openmp/libomptarget/plugins-nextgen/common/include/GlobalHandler.h b/openmp/libomptarget/plugins-nextgen/common/include/GlobalHandler.h index 5c767995126b7..57d93b88afcaa 100644 --- a/openmp/libomptarget/plugins-nextgen/common/include/GlobalHandler.h +++ b/openmp/libomptarget/plugins-nextgen/common/include/GlobalHandler.h @@ -103,9 +103,6 @@ class GenericGlobalHandlerTy { public: virtual ~GenericGlobalHandlerTy() {} - /// Helper function for getting an ELF from a device image. - Expected getELFObjectFile(DeviceImageTy &Image); - /// Returns whether the symbol named \p SymName is present in the given \p /// Image. bool isSymbolInImage(GenericDeviceTy &Device, DeviceImageTy &Image, diff --git a/openmp/libomptarget/plugins-nextgen/common/include/Utils/ELF.h b/openmp/libomptarget/plugins-nextgen/common/include/Utils/ELF.h index 140a6b6b84aa1..2268e4b6c4af6 100644 --- a/openmp/libomptarget/plugins-nextgen/common/include/Utils/ELF.h +++ b/openmp/libomptarget/plugins-nextgen/common/include/Utils/ELF.h @@ -27,18 +27,14 @@ bool isELF(llvm::StringRef Buffer); /// Checks if the given \p Object is a valid ELF matching the e_machine value. llvm::Expected checkMachine(llvm::StringRef Object, uint16_t EMachine); -/// Returns a pointer to the given \p Symbol inside of an ELF object. -llvm::Expected getSymbolAddress( - const llvm::object::ELFObjectFile &ELFObj, - const llvm::object::ELF64LE::Sym &Symbol); - -/// Returns the symbol associated with the \p Name in the \p ELFObj. It will +/// Returns the symbol associated with the \p Name in the \p Obj. It will /// first search for the hash sections to identify symbols from the hash table. /// If that fails it will fall back to a linear search in the case of an -/// executable file without a hash table. -llvm::Expected -getSymbol(const llvm::object::ELFObjectFile &ELFObj, - llvm::StringRef Name); +/// executable file without a hash table. If the symbol is found, it returns +/// a StringRef covering the symbol's data in the Obj buffer, based on its +/// address and size; otherwise, it returns std::nullopt. +llvm::Expected> +findSymbolInImage(const llvm::StringRef Obj, llvm::StringRef Name); } // namespace elf } // namespace utils diff --git a/openmp/libomptarget/plugins-nextgen/common/src/GlobalHandler.cpp b/openmp/libomptarget/plugins-nextgen/common/src/GlobalHandler.cpp index d398f60c55bd1..2269f27e46020 100644 --- a/openmp/libomptarget/plugins-nextgen/common/src/GlobalHandler.cpp +++ b/openmp/libomptarget/plugins-nextgen/common/src/GlobalHandler.cpp @@ -25,16 +25,6 @@ using namespace omp; using namespace target; using namespace plugin; -Expected -GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) { - assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) && - "Input is not an ELF file"); - - Expected ElfOrErr = - ELF64LEObjectFile::create(Image.getMemoryBuffer()); - return ElfOrErr; -} - Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost( GenericDeviceTy &Device, DeviceImageTy &Image, const GlobalTy &HostGlobal, bool Device2Host) { @@ -81,55 +71,37 @@ Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost( bool GenericGlobalHandlerTy::isSymbolInImage(GenericDeviceTy &Device, DeviceImageTy &Image, StringRef SymName) { - // Get the ELF object file for the image. Notice the ELF object may already - // be created in previous calls, so we can reuse it. If this is unsuccessful - // just return false as we couldn't find it. - auto ELFObjOrErr = getELFObjectFile(Image); - if (!ELFObjOrErr) { - consumeError(ELFObjOrErr.takeError()); - return false; - } // Search the ELF symbol using the symbol name. - auto SymOrErr = utils::elf::getSymbol(*ELFObjOrErr, SymName); + auto SymOrErr = utils::elf::findSymbolInImage( + Image.getMemoryBuffer().getBuffer(), SymName); if (!SymOrErr) { consumeError(SymOrErr.takeError()); return false; } - return *SymOrErr; + return SymOrErr->has_value(); } Error GenericGlobalHandlerTy::getGlobalMetadataFromImage( GenericDeviceTy &Device, DeviceImageTy &Image, GlobalTy &ImageGlobal) { - // Get the ELF object file for the image. Notice the ELF object may already - // be created in previous calls, so we can reuse it. - auto ELFObj = getELFObjectFile(Image); - if (!ELFObj) - return ELFObj.takeError(); - // Search the ELF symbol using the symbol name. - auto SymOrErr = utils::elf::getSymbol(*ELFObj, ImageGlobal.getName()); + auto SymOrErr = utils::elf::findSymbolInImage( + Image.getMemoryBuffer().getBuffer(), ImageGlobal.getName()); if (!SymOrErr) return Plugin::error("Failed ELF lookup of global '%s': %s", ImageGlobal.getName().data(), toString(SymOrErr.takeError()).data()); - if (!*SymOrErr) + if (!SymOrErr->has_value()) return Plugin::error("Failed to find global symbol '%s' in the ELF image", ImageGlobal.getName().data()); - auto AddrOrErr = utils::elf::getSymbolAddress(*ELFObj, **SymOrErr); - // Get the section to which the symbol belongs. - if (!AddrOrErr) - return Plugin::error("Failed to get ELF symbol from global '%s': %s", - ImageGlobal.getName().data(), - toString(AddrOrErr.takeError()).data()); - // Setup the global symbol's address and size. - ImageGlobal.setPtr(const_cast(*AddrOrErr)); - ImageGlobal.setSize((*SymOrErr)->st_size); + auto Symbol = **SymOrErr; + ImageGlobal.setPtr(static_cast(const_cast(Symbol.data()))); + ImageGlobal.setSize(Symbol.size()); return Plugin::success(); } diff --git a/openmp/libomptarget/plugins-nextgen/common/src/Utils/ELF.cpp b/openmp/libomptarget/plugins-nextgen/common/src/Utils/ELF.cpp index c84c3bad5def0..88bb097165ef7 100644 --- a/openmp/libomptarget/plugins-nextgen/common/src/Utils/ELF.cpp +++ b/openmp/libomptarget/plugins-nextgen/common/src/Utils/ELF.cpp @@ -36,18 +36,10 @@ bool utils::elf::isELF(StringRef Buffer) { } } -Expected utils::elf::checkMachine(StringRef Object, uint16_t EMachine) { - assert(isELF(Object) && "Input is not an ELF!"); - - Expected ElfOrErr = - ELF64LEObjectFile::create(MemoryBufferRef(Object, /*Identifier=*/""), - /*InitContent=*/false); - if (!ElfOrErr) - return ElfOrErr.takeError(); - - const auto Header = ElfOrErr->getELFFile().getHeader(); - if (Header.e_ident[EI_CLASS] != ELFCLASS64) - return createError("Only 64-bit ELF files are supported"); +template +static Expected +checkMachineImpl(const object::ELFObjectFile &ELFObj, uint16_t EMachine) { + const auto Header = ELFObj.getELFFile().getHeader(); if (Header.e_type != ET_EXEC && Header.e_type != ET_DYN) return createError("Only executable ELF files are supported"); @@ -71,6 +63,25 @@ Expected utils::elf::checkMachine(StringRef Object, uint16_t EMachine) { return Header.e_machine == EMachine; } +Expected utils::elf::checkMachine(StringRef Object, uint16_t EMachine) { + assert(isELF(Object) && "Input is not an ELF!"); + + Expected> ElfOrErr = + ObjectFile::createELFObjectFile( + MemoryBufferRef(Object, /*Identifier=*/""), + /*InitContent=*/false); + if (!ElfOrErr) + return ElfOrErr.takeError(); + + if (const ELF64LEObjectFile *ELFObj = + dyn_cast(&**ElfOrErr)) + return checkMachineImpl(*ELFObj, EMachine); + if (const ELF64BEObjectFile *ELFObj = + dyn_cast(&**ElfOrErr)) + return checkMachineImpl(*ELFObj, EMachine); + return createError("Only 64-bit ELF files are supported"); +} + template static Expected getSymbolFromGnuHashTable(StringRef Name, const typename ELFT::GnuHash &HashTab, @@ -231,8 +242,9 @@ getSymTableSymbol(const ELFFile &Elf, const typename ELFT::Shdr &Sec, return nullptr; } -Expected -utils::elf::getSymbol(const ELFObjectFile &ELFObj, StringRef Name) { +template +static Expected +getSymbol(const ELFObjectFile &ELFObj, StringRef Name) { // First try to look up the symbol via the hash table. for (ELFSectionRef Sec : ELFObj.sections()) { if (Sec.getType() != SHT_HASH && Sec.getType() != SHT_GNU_HASH) @@ -241,8 +253,7 @@ utils::elf::getSymbol(const ELFObjectFile &ELFObj, StringRef Name) { auto HashTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex()); if (!HashTabOrErr) return HashTabOrErr.takeError(); - return getHashTableSymbol(ELFObj.getELFFile(), **HashTabOrErr, - Name); + return getHashTableSymbol(ELFObj.getELFFile(), **HashTabOrErr, Name); } // If this is an executable file check the entire standard symbol table. @@ -253,16 +264,17 @@ utils::elf::getSymbol(const ELFObjectFile &ELFObj, StringRef Name) { auto SymTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex()); if (!SymTabOrErr) return SymTabOrErr.takeError(); - return getSymTableSymbol(ELFObj.getELFFile(), **SymTabOrErr, Name); + return getSymTableSymbol(ELFObj.getELFFile(), **SymTabOrErr, Name); } return nullptr; } -Expected utils::elf::getSymbolAddress( - const object::ELFObjectFile &ELFObj, - const object::ELF64LE::Sym &Symbol) { - const ELFFile &ELFFile = ELFObj.getELFFile(); +template +static Expected +getSymbolAddress(const object::ELFObjectFile &ELFObj, + const typename ELFT::Sym &Symbol) { + const ELFFile &ELFFile = ELFObj.getELFFile(); auto SecOrErr = ELFFile.getSection(Symbol.st_shndx); if (!SecOrErr) @@ -283,3 +295,40 @@ Expected utils::elf::getSymbolAddress( return ELFFile.base() + Offset; } + +template +static Expected> +findSymbolInImageImpl(const object::ELFObjectFile &ELFObj, + StringRef Name) { + auto SymOrErr = getSymbol(ELFObj, Name); + if (!SymOrErr) + return SymOrErr.takeError(); + if (!*SymOrErr) + return std::nullopt; + + // If the symbol was found, return a StringRef covering the associated data, + // based on the symbol's address and size. + auto AddrOrErr = getSymbolAddress(ELFObj, **SymOrErr); + if (!AddrOrErr) + return AddrOrErr.takeError(); + return StringRef(static_cast(*AddrOrErr), (*SymOrErr)->st_size); +} + +Expected> +utils::elf::findSymbolInImage(StringRef Obj, StringRef Name) { + assert(isELF(Obj) && "Input is not an ELF!"); + + Expected> ElfOrErr = + ObjectFile::createELFObjectFile(MemoryBufferRef(Obj, /*Identifier=*/""), + /*InitContent=*/false); + if (!ElfOrErr) + return ElfOrErr.takeError(); + + if (const ELF64LEObjectFile *ELFObj = + dyn_cast(&**ElfOrErr)) + return findSymbolInImageImpl(*ELFObj, Name); + if (const ELF64BEObjectFile *ELFObj = + dyn_cast(&**ElfOrErr)) + return findSymbolInImageImpl(*ELFObj, Name); + return createError("Only 64-bit ELF files are supported"); +}