Skip to content

Commit f4dee54

Browse files
[SYCL] Add identification for newer ZEBIN device binaries (#6344)
#6311 added support for ZEBIN executable binaries in the persistent device code cache by identifying them through their ELF header type. However, newer ZEBIN binaries do not have this header type and thus must be identified in another way. This commit adds identification of this format by looking for the .ze_info section that must be present in ZEBIN binaries. Signed-off-by: Larsen, Steffen <[email protected]>
1 parent 01589da commit f4dee54

File tree

1 file changed

+85
-7
lines changed

1 file changed

+85
-7
lines changed

sycl/source/detail/pi.cpp

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -687,19 +687,93 @@ DeviceBinaryImage::getProperty(const char *PropName) const {
687687
return *It;
688688
}
689689

690+
// Reads an integer value from ELF data.
691+
template <typename ResT>
692+
static ResT readELFValue(const unsigned char *Data, size_t NumBytes,
693+
bool IsBigEndian) {
694+
assert(NumBytes <= sizeof(ResT));
695+
ResT Result = 0;
696+
if (IsBigEndian) {
697+
for (size_t I = 0; I < NumBytes; ++I) {
698+
Result = (Result << 8) | static_cast<ResT>(Data[I]);
699+
}
700+
} else {
701+
std::copy(Data, Data + NumBytes, reinterpret_cast<char *>(&Result));
702+
}
703+
return Result;
704+
}
705+
706+
// Checks if an ELF image contains a section with a specified name.
707+
static bool checkELFSectionPresent(const std::string &ExpectedSectionName,
708+
const unsigned char *ImgData,
709+
size_t ImgSize) {
710+
// Check for 64bit and big-endian.
711+
bool Is64bit = ImgData[4] == 2;
712+
bool IsBigEndian = ImgData[5] == 2;
713+
714+
// Make offsets based on whether the ELF file is 64bit or not.
715+
size_t SectionHeaderOffsetInfoOffset = Is64bit ? 0x28 : 0x20;
716+
size_t SectionHeaderSizeInfoOffset = Is64bit ? 0x3A : 0x2E;
717+
size_t SectionHeaderNumInfoOffset = Is64bit ? 0x3C : 0x30;
718+
size_t SectionStringsHeaderIndexInfoOffset = Is64bit ? 0x3E : 0x32;
719+
720+
// if the image doesn't contain enough data for the header values, end early.
721+
if (ImgSize < SectionStringsHeaderIndexInfoOffset + 2)
722+
return false;
723+
724+
// Read the e_shoff, e_shentsize, e_shnum, and e_shstrndx entries in the
725+
// header.
726+
uint64_t SectionHeaderOffset = readELFValue<uint64_t>(
727+
ImgData + SectionHeaderOffsetInfoOffset, Is64bit ? 8 : 4, IsBigEndian);
728+
uint16_t SectionHeaderSize = readELFValue<uint16_t>(
729+
ImgData + SectionHeaderSizeInfoOffset, 2, IsBigEndian);
730+
uint16_t SectionHeaderNum = readELFValue<uint16_t>(
731+
ImgData + SectionHeaderNumInfoOffset, 2, IsBigEndian);
732+
uint16_t SectionStringsHeaderIndex = readELFValue<uint16_t>(
733+
ImgData + SectionStringsHeaderIndexInfoOffset, 2, IsBigEndian);
734+
735+
// End early if we do not have the expected number of section headers or
736+
// if the read section string header index is out-of-range.
737+
if (ImgSize < SectionHeaderOffset + SectionHeaderNum * SectionHeaderSize ||
738+
SectionStringsHeaderIndex >= SectionHeaderNum)
739+
return false;
740+
741+
// Get the location of the section string data.
742+
size_t SectionStringsInfoOffset = Is64bit ? 0x18 : 0x10;
743+
const unsigned char *SectionStringsHeaderData =
744+
ImgData + SectionHeaderOffset +
745+
SectionStringsHeaderIndex * SectionHeaderSize;
746+
uint64_t SectionStrings = readELFValue<uint64_t>(
747+
SectionStringsHeaderData + SectionStringsInfoOffset, Is64bit ? 8 : 4,
748+
IsBigEndian);
749+
const unsigned char *SectionStringsData = ImgData + SectionStrings;
750+
751+
// For each section, check the name against the expected section and return
752+
// true if we find it.
753+
for (size_t I = 0; I < SectionHeaderNum; ++I) {
754+
// Get the offset into the section string data of this sections name.
755+
const unsigned char *HeaderData =
756+
ImgData + SectionHeaderOffset + I * SectionHeaderSize;
757+
uint32_t SectionNameOffset =
758+
readELFValue<uint32_t>(HeaderData, 4, IsBigEndian);
759+
760+
// Read the section name and check if it is the same as the name we are
761+
// looking for.
762+
const char *SectionName =
763+
reinterpret_cast<const char *>(SectionStringsData + SectionNameOffset);
764+
if (SectionName == ExpectedSectionName)
765+
return true;
766+
}
767+
return false;
768+
}
769+
690770
// Returns the e_type field from an ELF image.
691771
static uint16_t getELFHeaderType(const unsigned char *ImgData, size_t ImgSize) {
692772
(void)ImgSize;
693773
assert(ImgSize >= 18 && "Not enough bytes to have an ELF header type.");
694774

695775
bool IsBigEndian = ImgData[5] == 2;
696-
if (IsBigEndian)
697-
return (static_cast<uint16_t>(ImgData[16]) << 8) |
698-
static_cast<uint16_t>(ImgData[17]);
699-
uint16_t HdrType = 0;
700-
std::copy(ImgData + 16, ImgData + 16 + sizeof(HdrType),
701-
reinterpret_cast<char *>(&HdrType));
702-
return HdrType;
776+
return readELFValue<uint16_t>(ImgData + 16, 2, IsBigEndian);
703777
}
704778

705779
RT::PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData,
@@ -738,6 +812,10 @@ RT::PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData,
738812
if (HdrType == ELFFmt.Magic)
739813
return ELFFmt.Fmt;
740814
}
815+
// Newer ZEBIN format does not have a special header type, but can instead
816+
// be identified by having a required .ze_info section.
817+
if (checkELFSectionPresent(".ze_info", ImgData, ImgSize))
818+
return PI_DEVICE_BINARY_TYPE_NATIVE;
741819
}
742820
}
743821
return PI_DEVICE_BINARY_TYPE_NONE;

0 commit comments

Comments
 (0)