[Openmp-commits] [openmp] [libomptarget] Support BE ELF files in plugins-nextgen (PR #83976)
Ulrich Weigand via Openmp-commits
openmp-commits at lists.llvm.org
Wed Mar 6 11:19:44 PST 2024
https://github.com/uweigand updated https://github.com/llvm/llvm-project/pull/83976
>From bb2e42a71032ab8cc03e413a8d0c23fb634ae761 Mon Sep 17 00:00:00 2001
From: Ulrich Weigand <ulrich.weigand at de.ibm.com>
Date: Tue, 5 Mar 2024 09:52:14 +0100
Subject: [PATCH] [libomptarget] Support BE ELF files in plugins-nextgen
Code in plugins-nextgen reading ELF files is currently hard-coded
to assume a 64-bit little-endian ELF format. Unfortunately, this
assumption is even embedded in the interface between GlobalHandler
and Utils/ELF routines, which use ELF64LE types.
To fix this, I've refactored the interface to push all ELF specific
types into Utils/ELF. Specifically, this patch removes both the
getSymbol and getSymbolAddress routines and replaces them with a
single findSymbolInImage, which gets a MemoryBufferRef identifying
the raw object file image as input, and returns a StringRef covering
the data addressed by the symbol (address and size) if found, or an
empty StringRef otherwise.
This allows properly templating over multiple ELF format variants
inside Utils/ELF; specifically, this patch adds support for 64-bit
big-endian ELF files in addition to 64-bit little-endian files.
---
.../common/include/GlobalHandler.h | 3 -
.../common/include/Utils/ELF.h | 16 ++--
.../common/src/GlobalHandler.cpp | 46 ++-------
.../plugins-nextgen/common/src/Utils/ELF.cpp | 95 +++++++++++++++----
4 files changed, 89 insertions(+), 71 deletions(-)
diff --git a/openmp/libomptarget/plugins-nextgen/common/include/GlobalHandler.h b/openmp/libomptarget/plugins-nextgen/common/include/GlobalHandler.h
index 5c767995126b77..57d93b88afcaa9 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<ELF64LEObjectFile> 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 140a6b6b84aa12..2268e4b6c4af6b 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<bool> checkMachine(llvm::StringRef Object, uint16_t EMachine);
-/// Returns a pointer to the given \p Symbol inside of an ELF object.
-llvm::Expected<const void *> getSymbolAddress(
- const llvm::object::ELFObjectFile<llvm::object::ELF64LE> &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<const typename llvm::object::ELF64LE::Sym *>
-getSymbol(const llvm::object::ELFObjectFile<llvm::object::ELF64LE> &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<std::optional<llvm::StringRef>>
+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 d398f60c55bd13..2269f27e460205 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<ELF64LEObjectFile>
-GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) {
- assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) &&
- "Input is not an ELF file");
-
- Expected<ELF64LEObjectFile> 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<void *>(*AddrOrErr));
- ImageGlobal.setSize((*SymOrErr)->st_size);
+ auto Symbol = **SymOrErr;
+ ImageGlobal.setPtr(static_cast<void *>(const_cast<char *>(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 c84c3bad5def0a..2e446b8c74490d 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<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) {
- assert(isELF(Object) && "Input is not an ELF!");
-
- Expected<ELF64LEObjectFile> 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 <class ELFT>
+static Expected<bool>
+checkMachineImpl(const object::ELFObjectFile<ELFT> &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<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) {
return Header.e_machine == EMachine;
}
+Expected<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) {
+ assert(isELF(Object) && "Input is not an ELF!");
+
+ Expected<std::unique_ptr<ObjectFile>> ElfOrErr =
+ ObjectFile::createELFObjectFile(
+ MemoryBufferRef(Object, /*Identifier=*/""),
+ /*InitContent=*/false);
+ if (!ElfOrErr)
+ return ElfOrErr.takeError();
+
+ if (const ELF64LEObjectFile *ELFObj =
+ dyn_cast<ELF64LEObjectFile>(&**ElfOrErr))
+ return checkMachineImpl(*ELFObj, EMachine);
+ if (const ELF64BEObjectFile *ELFObj =
+ dyn_cast<ELF64BEObjectFile>(&**ElfOrErr))
+ return checkMachineImpl(*ELFObj, EMachine);
+ return createError("Only 64-bit ELF files are supported");
+}
+
template <class ELFT>
static Expected<const typename ELFT::Sym *>
getSymbolFromGnuHashTable(StringRef Name, const typename ELFT::GnuHash &HashTab,
@@ -231,8 +242,9 @@ getSymTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
return nullptr;
}
-Expected<const typename ELF64LE::Sym *>
-utils::elf::getSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
+template <class ELFT>
+static Expected<const typename ELFT::Sym *>
+getSymbol(const ELFObjectFile<ELFT> &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<ELF64LE> &ELFObj, StringRef Name) {
auto HashTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
if (!HashTabOrErr)
return HashTabOrErr.takeError();
- return getHashTableSymbol<ELF64LE>(ELFObj.getELFFile(), **HashTabOrErr,
- Name);
+ return getHashTableSymbol<ELFT>(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<ELF64LE> &ELFObj, StringRef Name) {
auto SymTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
if (!SymTabOrErr)
return SymTabOrErr.takeError();
- return getSymTableSymbol<ELF64LE>(ELFObj.getELFFile(), **SymTabOrErr, Name);
+ return getSymTableSymbol<ELFT>(ELFObj.getELFFile(), **SymTabOrErr, Name);
}
return nullptr;
}
-Expected<const void *> utils::elf::getSymbolAddress(
- const object::ELFObjectFile<object::ELF64LE> &ELFObj,
- const object::ELF64LE::Sym &Symbol) {
- const ELFFile<ELF64LE> &ELFFile = ELFObj.getELFFile();
+template <class ELFT>
+static Expected<const void *>
+getSymbolAddress(const object::ELFObjectFile<ELFT> &ELFObj,
+ const typename ELFT::Sym &Symbol) {
+ const ELFFile<ELFT> &ELFFile = ELFObj.getELFFile();
auto SecOrErr = ELFFile.getSection(Symbol.st_shndx);
if (!SecOrErr)
@@ -283,3 +295,44 @@ Expected<const void *> utils::elf::getSymbolAddress(
return ELFFile.base() + Offset;
}
+
+template <class ELFT>
+static Expected<std::optional<StringRef>>
+findSymbolInImageImpl(const object::ELFObjectFile<ELFT> &ELFObj,
+ StringRef Name) {
+ // Search for the symbol by name.
+ auto SymOrErr = getSymbol(ELFObj, Name);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+ // If symbol not found, return std::nullopt.
+ if (!*SymOrErr)
+ return std::nullopt;
+
+ // Retrieve the symbol address within the object's memory image.
+ auto AddrOrErr = getSymbolAddress(ELFObj, **SymOrErr);
+ if (!AddrOrErr)
+ return AddrOrErr.takeError();
+
+ // Return a StringRef covering the symbol's data, based on
+ // its address and size.
+ return StringRef(static_cast<const char *>(*AddrOrErr), (*SymOrErr)->st_size);
+}
+
+Expected<std::optional<StringRef>>
+utils::elf::findSymbolInImage(StringRef Obj, StringRef Name) {
+ assert(isELF(Obj) && "Input is not an ELF!");
+
+ Expected<std::unique_ptr<ObjectFile>> ElfOrErr =
+ ObjectFile::createELFObjectFile(MemoryBufferRef(Obj, /*Identifier=*/""),
+ /*InitContent=*/false);
+ if (!ElfOrErr)
+ return ElfOrErr.takeError();
+
+ if (const ELF64LEObjectFile *ELFObj =
+ dyn_cast<ELF64LEObjectFile>(&**ElfOrErr))
+ return findSymbolInImageImpl(*ELFObj, Name);
+ if (const ELF64BEObjectFile *ELFObj =
+ dyn_cast<ELF64BEObjectFile>(&**ElfOrErr))
+ return findSymbolInImageImpl(*ELFObj, Name);
+ return createError("Only 64-bit ELF files are supported");
+}
More information about the Openmp-commits
mailing list