Skip to content

Commit 35cdcd7

Browse files
committed
[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.
1 parent ff66e9b commit 35cdcd7

File tree

4 files changed

+91
-70
lines changed

4 files changed

+91
-70
lines changed

openmp/libomptarget/plugins-nextgen/common/include/GlobalHandler.h

-3
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,6 @@ class GenericGlobalHandlerTy {
103103
public:
104104
virtual ~GenericGlobalHandlerTy() {}
105105

106-
/// Helper function for getting an ELF from a device image.
107-
Expected<ELF64LEObjectFile> getELFObjectFile(DeviceImageTy &Image);
108-
109106
/// Returns whether the symbol named \p SymName is present in the given \p
110107
/// Image.
111108
bool isSymbolInImage(GenericDeviceTy &Device, DeviceImageTy &Image,

openmp/libomptarget/plugins-nextgen/common/include/Utils/ELF.h

+6-10
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,14 @@ bool isELF(llvm::StringRef Buffer);
2727
/// Checks if the given \p Object is a valid ELF matching the e_machine value.
2828
llvm::Expected<bool> checkMachine(llvm::StringRef Object, uint16_t EMachine);
2929

30-
/// Returns a pointer to the given \p Symbol inside of an ELF object.
31-
llvm::Expected<const void *> getSymbolAddress(
32-
const llvm::object::ELFObjectFile<llvm::object::ELF64LE> &ELFObj,
33-
const llvm::object::ELF64LE::Sym &Symbol);
34-
35-
/// Returns the symbol associated with the \p Name in the \p ELFObj. It will
30+
/// Returns the symbol associated with the \p Name in the \p Obj. It will
3631
/// first search for the hash sections to identify symbols from the hash table.
3732
/// If that fails it will fall back to a linear search in the case of an
38-
/// executable file without a hash table.
39-
llvm::Expected<const typename llvm::object::ELF64LE::Sym *>
40-
getSymbol(const llvm::object::ELFObjectFile<llvm::object::ELF64LE> &ELFObj,
41-
llvm::StringRef Name);
33+
/// executable file without a hash table. If the symbol is not found, returns
34+
/// an empty StringRef; otherwise, returns a StringRef covering the symbol's
35+
/// data in the Obj buffer, based on its address and size
36+
llvm::Expected<llvm::StringRef>
37+
findSymbolInImage(const llvm::MemoryBufferRef Obj, llvm::StringRef Name);
4238

4339
} // namespace elf
4440
} // namespace utils

openmp/libomptarget/plugins-nextgen/common/src/GlobalHandler.cpp

+8-36
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,6 @@ using namespace omp;
2525
using namespace target;
2626
using namespace plugin;
2727

28-
Expected<ELF64LEObjectFile>
29-
GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) {
30-
assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) &&
31-
"Input is not an ELF file");
32-
33-
Expected<ELF64LEObjectFile> ElfOrErr =
34-
ELF64LEObjectFile::create(Image.getMemoryBuffer());
35-
return ElfOrErr;
36-
}
37-
3828
Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
3929
GenericDeviceTy &Device, DeviceImageTy &Image, const GlobalTy &HostGlobal,
4030
bool Device2Host) {
@@ -81,55 +71,37 @@ Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
8171
bool GenericGlobalHandlerTy::isSymbolInImage(GenericDeviceTy &Device,
8272
DeviceImageTy &Image,
8373
StringRef SymName) {
84-
// Get the ELF object file for the image. Notice the ELF object may already
85-
// be created in previous calls, so we can reuse it. If this is unsuccessful
86-
// just return false as we couldn't find it.
87-
auto ELFObjOrErr = getELFObjectFile(Image);
88-
if (!ELFObjOrErr) {
89-
consumeError(ELFObjOrErr.takeError());
90-
return false;
91-
}
9274

9375
// Search the ELF symbol using the symbol name.
94-
auto SymOrErr = utils::elf::getSymbol(*ELFObjOrErr, SymName);
76+
auto SymOrErr =
77+
utils::elf::findSymbolInImage(Image.getMemoryBuffer(), SymName);
9578
if (!SymOrErr) {
9679
consumeError(SymOrErr.takeError());
9780
return false;
9881
}
9982

100-
return *SymOrErr;
83+
return !SymOrErr->empty();
10184
}
10285

10386
Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
10487
GenericDeviceTy &Device, DeviceImageTy &Image, GlobalTy &ImageGlobal) {
10588

106-
// Get the ELF object file for the image. Notice the ELF object may already
107-
// be created in previous calls, so we can reuse it.
108-
auto ELFObj = getELFObjectFile(Image);
109-
if (!ELFObj)
110-
return ELFObj.takeError();
111-
11289
// Search the ELF symbol using the symbol name.
113-
auto SymOrErr = utils::elf::getSymbol(*ELFObj, ImageGlobal.getName());
90+
auto SymOrErr = utils::elf::findSymbolInImage(Image.getMemoryBuffer(),
91+
ImageGlobal.getName());
11492
if (!SymOrErr)
11593
return Plugin::error("Failed ELF lookup of global '%s': %s",
11694
ImageGlobal.getName().data(),
11795
toString(SymOrErr.takeError()).data());
11896

119-
if (!*SymOrErr)
97+
if (SymOrErr->empty())
12098
return Plugin::error("Failed to find global symbol '%s' in the ELF image",
12199
ImageGlobal.getName().data());
122100

123-
auto AddrOrErr = utils::elf::getSymbolAddress(*ELFObj, **SymOrErr);
124-
// Get the section to which the symbol belongs.
125-
if (!AddrOrErr)
126-
return Plugin::error("Failed to get ELF symbol from global '%s': %s",
127-
ImageGlobal.getName().data(),
128-
toString(AddrOrErr.takeError()).data());
129101

130102
// Setup the global symbol's address and size.
131-
ImageGlobal.setPtr(const_cast<void *>(*AddrOrErr));
132-
ImageGlobal.setSize((*SymOrErr)->st_size);
103+
ImageGlobal.setPtr((void *)(SymOrErr->data()));
104+
ImageGlobal.setSize(SymOrErr->size());
133105

134106
return Plugin::success();
135107
}

openmp/libomptarget/plugins-nextgen/common/src/Utils/ELF.cpp

+77-21
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,10 @@ bool utils::elf::isELF(StringRef Buffer) {
3636
}
3737
}
3838

39-
Expected<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) {
40-
assert(isELF(Object) && "Input is not an ELF!");
41-
42-
Expected<ELF64LEObjectFile> ElfOrErr =
43-
ELF64LEObjectFile::create(MemoryBufferRef(Object, /*Identifier=*/""),
44-
/*InitContent=*/false);
45-
if (!ElfOrErr)
46-
return ElfOrErr.takeError();
47-
48-
const auto Header = ElfOrErr->getELFFile().getHeader();
49-
if (Header.e_ident[EI_CLASS] != ELFCLASS64)
50-
return createError("Only 64-bit ELF files are supported");
39+
template <class ELFT>
40+
static Expected<bool>
41+
checkMachineImpl(const object::ELFObjectFile<ELFT> &ELFObj, uint16_t EMachine) {
42+
const auto Header = ELFObj.getELFFile().getHeader();
5143
if (Header.e_type != ET_EXEC && Header.e_type != ET_DYN)
5244
return createError("Only executable ELF files are supported");
5345

@@ -71,6 +63,27 @@ Expected<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) {
7163
return Header.e_machine == EMachine;
7264
}
7365

66+
Expected<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) {
67+
assert(isELF(Object) && "Input is not an ELF!");
68+
69+
Expected<std::unique_ptr<ObjectFile>> ElfOrErr =
70+
ObjectFile::createELFObjectFile(
71+
MemoryBufferRef(Object, /*Identifier=*/""),
72+
/*InitContent=*/false);
73+
if (!ElfOrErr)
74+
return ElfOrErr.takeError();
75+
76+
// Little-endian 64-bit
77+
if (const ELF64LEObjectFile *ELFObj =
78+
dyn_cast<ELF64LEObjectFile>(&**ElfOrErr))
79+
return checkMachineImpl(*ELFObj, EMachine);
80+
// Big-endian 64-bit
81+
if (const ELF64BEObjectFile *ELFObj =
82+
dyn_cast<ELF64BEObjectFile>(&**ElfOrErr))
83+
return checkMachineImpl(*ELFObj, EMachine);
84+
return createError("Only 64-bit ELF files are supported");
85+
}
86+
7487
template <class ELFT>
7588
static Expected<const typename ELFT::Sym *>
7689
getSymbolFromGnuHashTable(StringRef Name, const typename ELFT::GnuHash &HashTab,
@@ -231,8 +244,9 @@ getSymTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
231244
return nullptr;
232245
}
233246

234-
Expected<const typename ELF64LE::Sym *>
235-
utils::elf::getSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
247+
template <class ELFT>
248+
static Expected<const typename ELFT::Sym *>
249+
getSymbol(const ELFObjectFile<ELFT> &ELFObj, StringRef Name) {
236250
// First try to look up the symbol via the hash table.
237251
for (ELFSectionRef Sec : ELFObj.sections()) {
238252
if (Sec.getType() != SHT_HASH && Sec.getType() != SHT_GNU_HASH)
@@ -241,8 +255,7 @@ utils::elf::getSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
241255
auto HashTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
242256
if (!HashTabOrErr)
243257
return HashTabOrErr.takeError();
244-
return getHashTableSymbol<ELF64LE>(ELFObj.getELFFile(), **HashTabOrErr,
245-
Name);
258+
return getHashTableSymbol<ELFT>(ELFObj.getELFFile(), **HashTabOrErr, Name);
246259
}
247260

248261
// If this is an executable file check the entire standard symbol table.
@@ -253,16 +266,17 @@ utils::elf::getSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
253266
auto SymTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
254267
if (!SymTabOrErr)
255268
return SymTabOrErr.takeError();
256-
return getSymTableSymbol<ELF64LE>(ELFObj.getELFFile(), **SymTabOrErr, Name);
269+
return getSymTableSymbol<ELFT>(ELFObj.getELFFile(), **SymTabOrErr, Name);
257270
}
258271

259272
return nullptr;
260273
}
261274

262-
Expected<const void *> utils::elf::getSymbolAddress(
263-
const object::ELFObjectFile<object::ELF64LE> &ELFObj,
264-
const object::ELF64LE::Sym &Symbol) {
265-
const ELFFile<ELF64LE> &ELFFile = ELFObj.getELFFile();
275+
template <class ELFT>
276+
static Expected<const void *>
277+
getSymbolAddress(const object::ELFObjectFile<ELFT> &ELFObj,
278+
const typename ELFT::Sym &Symbol) {
279+
const ELFFile<ELFT> &ELFFile = ELFObj.getELFFile();
266280

267281
auto SecOrErr = ELFFile.getSection(Symbol.st_shndx);
268282
if (!SecOrErr)
@@ -283,3 +297,45 @@ Expected<const void *> utils::elf::getSymbolAddress(
283297

284298
return ELFFile.base() + Offset;
285299
}
300+
301+
template <class ELFT>
302+
static Expected<StringRef>
303+
findSymbolInImageImpl(const object::ELFObjectFile<ELFT> &ELFObj,
304+
StringRef Name) {
305+
// Search for the symbol by name.
306+
auto SymOrErr = getSymbol(ELFObj, Name);
307+
if (!SymOrErr)
308+
return SymOrErr.takeError();
309+
// If symbol not found, return an empty StringRef.
310+
if (!*SymOrErr)
311+
return StringRef();
312+
313+
// Retrieve the symbol address within the object's memory image.
314+
auto AddrOrErr = getSymbolAddress(ELFObj, **SymOrErr);
315+
if (!AddrOrErr)
316+
return AddrOrErr.takeError();
317+
318+
// Return a StringRef covering the symbol's data, based on
319+
// its address and size.
320+
return StringRef(static_cast<const char *>(*AddrOrErr), (*SymOrErr)->st_size);
321+
}
322+
323+
Expected<StringRef> utils::elf::findSymbolInImage(MemoryBufferRef Obj,
324+
StringRef Name) {
325+
assert(isELF(Obj.getBuffer()) && "Input is not an ELF!");
326+
327+
Expected<std::unique_ptr<ObjectFile>> ElfOrErr =
328+
ObjectFile::createELFObjectFile(Obj, /*InitContent=*/false);
329+
if (!ElfOrErr)
330+
return ElfOrErr.takeError();
331+
332+
// Little-endian 64-bit
333+
if (const ELF64LEObjectFile *ELFObj =
334+
dyn_cast<ELF64LEObjectFile>(&**ElfOrErr))
335+
return findSymbolInImageImpl(*ELFObj, Name);
336+
// Big-endian 64-bit
337+
if (const ELF64BEObjectFile *ELFObj =
338+
dyn_cast<ELF64BEObjectFile>(&**ElfOrErr))
339+
return findSymbolInImageImpl(*ELFObj, Name);
340+
return createError("Only 64-bit ELF files are supported");
341+
}

0 commit comments

Comments
 (0)