Skip to content

Commit 2210c85

Browse files
committed
Reapply [libomptarget] Support BE ELF files in plugins-nextgen (#85246)
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 use generic types, in particular by using (a unique_ptr to) ObjectFile instead of ELF64LEObjectFile, and ELFSymbolRef instead of ELF64LE::Sym. 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 bb9ca8a commit 2210c85

File tree

5 files changed

+95
-51
lines changed

5 files changed

+95
-51
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class GenericGlobalHandlerTy {
104104
virtual ~GenericGlobalHandlerTy() {}
105105

106106
/// Helper function for getting an ELF from a device image.
107-
Expected<ELF64LEObjectFile> getELFObjectFile(DeviceImageTy &Image);
107+
Expected<std::unique_ptr<ObjectFile>> getELFObjectFile(DeviceImageTy &Image);
108108

109109
/// Returns whether the symbol named \p SymName is present in the given \p
110110
/// Image.

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,15 @@ bool isELF(llvm::StringRef Buffer);
2828
llvm::Expected<bool> checkMachine(llvm::StringRef Object, uint16_t EMachine);
2929

3030
/// 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);
31+
llvm::Expected<const void *>
32+
getSymbolAddress(const llvm::object::ELFSymbolRef &Symbol);
3433

3534
/// Returns the symbol associated with the \p Name in the \p ELFObj. It will
3635
/// first search for the hash sections to identify symbols from the hash table.
3736
/// If that fails it will fall back to a linear search in the case of an
3837
/// 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);
38+
llvm::Expected<std::optional<llvm::object::ELFSymbolRef>>
39+
getSymbol(const llvm::object::ObjectFile &ELFObj, llvm::StringRef Name);
4240

4341
} // namespace elf
4442
} // namespace utils

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,12 @@ using namespace omp;
2525
using namespace target;
2626
using namespace plugin;
2727

28-
Expected<ELF64LEObjectFile>
28+
Expected<std::unique_ptr<ObjectFile>>
2929
GenericGlobalHandlerTy::getELFObjectFile(DeviceImageTy &Image) {
3030
assert(utils::elf::isELF(Image.getMemoryBuffer().getBuffer()) &&
3131
"Input is not an ELF file");
3232

33-
Expected<ELF64LEObjectFile> ElfOrErr =
34-
ELF64LEObjectFile::create(Image.getMemoryBuffer());
35-
return ElfOrErr;
33+
return ELFObjectFileBase::createELFObjectFile(Image.getMemoryBuffer());
3634
}
3735

3836
Error GenericGlobalHandlerTy::moveGlobalBetweenDeviceAndHost(
@@ -91,13 +89,13 @@ bool GenericGlobalHandlerTy::isSymbolInImage(GenericDeviceTy &Device,
9189
}
9290

9391
// Search the ELF symbol using the symbol name.
94-
auto SymOrErr = utils::elf::getSymbol(*ELFObjOrErr, SymName);
92+
auto SymOrErr = utils::elf::getSymbol(**ELFObjOrErr, SymName);
9593
if (!SymOrErr) {
9694
consumeError(SymOrErr.takeError());
9795
return false;
9896
}
9997

100-
return *SymOrErr;
98+
return SymOrErr->has_value();
10199
}
102100

103101
Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
@@ -110,17 +108,17 @@ Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
110108
return ELFObj.takeError();
111109

112110
// Search the ELF symbol using the symbol name.
113-
auto SymOrErr = utils::elf::getSymbol(*ELFObj, ImageGlobal.getName());
111+
auto SymOrErr = utils::elf::getSymbol(**ELFObj, ImageGlobal.getName());
114112
if (!SymOrErr)
115113
return Plugin::error("Failed ELF lookup of global '%s': %s",
116114
ImageGlobal.getName().data(),
117115
toString(SymOrErr.takeError()).data());
118116

119-
if (!*SymOrErr)
117+
if (!SymOrErr->has_value())
120118
return Plugin::error("Failed to find global symbol '%s' in the ELF image",
121119
ImageGlobal.getName().data());
122120

123-
auto AddrOrErr = utils::elf::getSymbolAddress(*ELFObj, **SymOrErr);
121+
auto AddrOrErr = utils::elf::getSymbolAddress(**SymOrErr);
124122
// Get the section to which the symbol belongs.
125123
if (!AddrOrErr)
126124
return Plugin::error("Failed to get ELF symbol from global '%s': %s",
@@ -129,7 +127,7 @@ Error GenericGlobalHandlerTy::getGlobalMetadataFromImage(
129127

130128
// Setup the global symbol's address and size.
131129
ImageGlobal.setPtr(const_cast<void *>(*AddrOrErr));
132-
ImageGlobal.setSize((*SymOrErr)->st_size);
130+
ImageGlobal.setSize((*SymOrErr)->getSize());
133131

134132
return Plugin::success();
135133
}

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

Lines changed: 81 additions & 33 deletions
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,25 @@ 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+
if (const ELF64LEObjectFile *ELFObj =
77+
dyn_cast<ELF64LEObjectFile>(&**ElfOrErr))
78+
return checkMachineImpl(*ELFObj, EMachine);
79+
if (const ELF64BEObjectFile *ELFObj =
80+
dyn_cast<ELF64BEObjectFile>(&**ElfOrErr))
81+
return checkMachineImpl(*ELFObj, EMachine);
82+
return createError("Only 64-bit ELF files are supported");
83+
}
84+
7485
template <class ELFT>
7586
static Expected<const typename ELFT::Sym *>
7687
getSymbolFromGnuHashTable(StringRef Name, const typename ELFT::GnuHash &HashTab,
@@ -138,9 +149,10 @@ getSymbolFromSysVHashTable(StringRef Name, const typename ELFT::Hash &HashTab,
138149
}
139150

140151
template <class ELFT>
141-
static Expected<const typename ELFT::Sym *>
142-
getHashTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
143-
StringRef Name) {
152+
static Expected<std::optional<ELFSymbolRef>>
153+
getHashTableSymbol(const ELFObjectFile<ELFT> &ELFObj,
154+
const typename ELFT::Shdr &Sec, StringRef Name) {
155+
const ELFFile<ELFT> &Elf = ELFObj.getELFFile();
144156
if (Sec.sh_type != ELF::SHT_HASH && Sec.sh_type != ELF::SHT_GNU_HASH)
145157
return createError(
146158
"invalid sh_type for hash table, expected SHT_HASH or SHT_GNU_HASH");
@@ -179,7 +191,12 @@ getHashTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
179191
sizeof(typename ELFT::Word) * HashTab->nbuckets +
180192
sizeof(typename ELFT::Word) * (SymTab.size() - HashTab->symndx))
181193
return createError("section has invalid sh_size: " + Twine(Sec.sh_size));
182-
return getSymbolFromGnuHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
194+
auto Sym = getSymbolFromGnuHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
195+
if (!Sym)
196+
return Sym.takeError();
197+
if (!*Sym)
198+
return std::nullopt;
199+
return ELFObj.toSymbolRef(*SymTabOrErr, *Sym - &SymTab[0]);
183200
}
184201

185202
// If this is a Sys-V hash table we verify its size and search the symbol
@@ -197,16 +214,22 @@ getHashTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
197214
sizeof(typename ELFT::Word) * HashTab->nchain)
198215
return createError("section has invalid sh_size: " + Twine(Sec.sh_size));
199216

200-
return getSymbolFromSysVHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
217+
auto Sym = getSymbolFromSysVHashTable<ELFT>(Name, *HashTab, SymTab, StrTab);
218+
if (!Sym)
219+
return Sym.takeError();
220+
if (!*Sym)
221+
return std::nullopt;
222+
return ELFObj.toSymbolRef(*SymTabOrErr, *Sym - &SymTab[0]);
201223
}
202224

203-
return nullptr;
225+
return std::nullopt;
204226
}
205227

206228
template <class ELFT>
207-
static Expected<const typename ELFT::Sym *>
208-
getSymTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
209-
StringRef Name) {
229+
static Expected<std::optional<ELFSymbolRef>>
230+
getSymTableSymbol(const ELFObjectFile<ELFT> &ELFObj,
231+
const typename ELFT::Shdr &Sec, StringRef Name) {
232+
const ELFFile<ELFT> &Elf = ELFObj.getELFFile();
210233
if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM)
211234
return createError(
212235
"invalid sh_type for hash table, expected SHT_SYMTAB or SHT_DYNSYM");
@@ -226,13 +249,14 @@ getSymTableSymbol(const ELFFile<ELFT> &Elf, const typename ELFT::Shdr &Sec,
226249

227250
for (const typename ELFT::Sym &Sym : SymTab)
228251
if (StrTab.drop_front(Sym.st_name).data() == Name)
229-
return &Sym;
252+
return ELFObj.toSymbolRef(&Sec, &Sym - &SymTab[0]);
230253

231-
return nullptr;
254+
return std::nullopt;
232255
}
233256

234-
Expected<const typename ELF64LE::Sym *>
235-
utils::elf::getSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
257+
template <class ELFT>
258+
static Expected<std::optional<ELFSymbolRef>>
259+
getSymbolImpl(const ELFObjectFile<ELFT> &ELFObj, StringRef Name) {
236260
// First try to look up the symbol via the hash table.
237261
for (ELFSectionRef Sec : ELFObj.sections()) {
238262
if (Sec.getType() != SHT_HASH && Sec.getType() != SHT_GNU_HASH)
@@ -241,8 +265,7 @@ utils::elf::getSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
241265
auto HashTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
242266
if (!HashTabOrErr)
243267
return HashTabOrErr.takeError();
244-
return getHashTableSymbol<ELF64LE>(ELFObj.getELFFile(), **HashTabOrErr,
245-
Name);
268+
return getHashTableSymbol<ELFT>(ELFObj, **HashTabOrErr, Name);
246269
}
247270

248271
// If this is an executable file check the entire standard symbol table.
@@ -253,16 +276,31 @@ utils::elf::getSymbol(const ELFObjectFile<ELF64LE> &ELFObj, StringRef Name) {
253276
auto SymTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex());
254277
if (!SymTabOrErr)
255278
return SymTabOrErr.takeError();
256-
return getSymTableSymbol<ELF64LE>(ELFObj.getELFFile(), **SymTabOrErr, Name);
279+
return getSymTableSymbol<ELFT>(ELFObj, **SymTabOrErr, Name);
257280
}
258281

259-
return nullptr;
282+
return std::nullopt;
260283
}
261284

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();
285+
Expected<std::optional<ELFSymbolRef>>
286+
utils::elf::getSymbol(const ObjectFile &Obj, StringRef Name) {
287+
if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(&Obj))
288+
return getSymbolImpl(*ELFObj, Name);
289+
if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(&Obj))
290+
return getSymbolImpl(*ELFObj, Name);
291+
return createError("Only 64-bit ELF files are supported");
292+
}
293+
294+
template <class ELFT>
295+
static Expected<const void *>
296+
getSymbolAddressImpl(const ELFObjectFile<ELFT> &ELFObj,
297+
const ELFSymbolRef &SymRef) {
298+
const ELFFile<ELFT> &ELFFile = ELFObj.getELFFile();
299+
300+
auto SymOrErr = ELFObj.getSymbol(SymRef.getRawDataRefImpl());
301+
if (!SymOrErr)
302+
return SymOrErr.takeError();
303+
const auto &Symbol = **SymOrErr;
266304

267305
auto SecOrErr = ELFFile.getSection(Symbol.st_shndx);
268306
if (!SecOrErr)
@@ -283,3 +321,13 @@ Expected<const void *> utils::elf::getSymbolAddress(
283321

284322
return ELFFile.base() + Offset;
285323
}
324+
325+
Expected<const void *>
326+
utils::elf::getSymbolAddress(const ELFSymbolRef &SymRef) {
327+
const ObjectFile *Obj = SymRef.getObject();
328+
if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
329+
return getSymbolAddressImpl(*ELFObj, SymRef);
330+
if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
331+
return getSymbolAddressImpl(*ELFObj, SymRef);
332+
return createError("Only 64-bit ELF files are supported");
333+
}

openmp/libomptarget/plugins-nextgen/cuda/src/rtl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,7 @@ struct CUDADeviceTy : public GenericDeviceTy {
11661166

11671167
// Search for all symbols that contain a constructor or destructor.
11681168
SmallVector<std::pair<StringRef, uint16_t>> Funcs;
1169-
for (ELFSymbolRef Sym : ELFObjOrErr->symbols()) {
1169+
for (ELFSymbolRef Sym : (*ELFObjOrErr)->symbols()) {
11701170
auto NameOrErr = Sym.getName();
11711171
if (!NameOrErr)
11721172
return NameOrErr.takeError();

0 commit comments

Comments
 (0)