Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libomptarget] Support BE ELF files in plugins-nextgen #83976

Merged
merged 1 commit into from Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -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,
Expand Down
16 changes: 6 additions & 10 deletions openmp/libomptarget/plugins-nextgen/common/include/Utils/ELF.h
Expand Up @@ -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
Expand Down
46 changes: 9 additions & 37 deletions openmp/libomptarget/plugins-nextgen/common/src/GlobalHandler.cpp
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
}
Expand Down
91 changes: 70 additions & 21 deletions openmp/libomptarget/plugins-nextgen/common/src/Utils/ELF.cpp
Expand Up @@ -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");

Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -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.
Expand All @@ -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)
Expand All @@ -283,3 +295,40 @@ 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) {
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<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");
}