feature: Adding elf rewriter utility

It will aid in various elf patching tasks both in ocloc
and UMD

Related-To: NEO-10190

Signed-off-by: Chodor, Jaroslaw <jaroslaw.chodor@intel.com>
This commit is contained in:
Chodor, Jaroslaw
2024-05-20 12:07:29 +00:00
committed by Compute-Runtime-Automation
parent bfc3e8fcf0
commit 90927135f9
12 changed files with 511 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2023 Intel Corporation
* Copyright (C) 2018-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -227,11 +227,11 @@ TEST_F(ClLinkProgramTests, GivenProgramsWithSpecConstantsThenSpecConstantsAreEmb
ASSERT_EQ(sizeof(ir2), elf.sectionHeaders[6].data.size());
ASSERT_EQ(sizeof(ir3), elf.sectionHeaders[7].data.size());
auto readSpecConstId = [](NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::SectionHeaderAndData &section, uint32_t offset) {
auto readSpecConstId = [](NEO::Elf::SectionHeaderAndData<NEO::Elf::EI_CLASS_64> &section, uint32_t offset) {
return *(reinterpret_cast<const uint32_t *>(section.data.begin()) + offset);
};
auto readSpecConstValue = [](NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::SectionHeaderAndData &section, uint32_t offset) {
auto readSpecConstValue = [](NEO::Elf::SectionHeaderAndData<NEO::Elf::EI_CLASS_64> &section, uint32_t offset) {
return *(reinterpret_cast<const uint64_t *>(section.data.begin()) + offset);
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -8,6 +8,7 @@
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/elf/elf.h"
#include "shared/source/helpers/aligned_memory.h"
#include "shared/source/helpers/ptr_math.h"
#include <string.h>
@@ -16,6 +17,30 @@ namespace NEO {
namespace Elf {
template <ElfIdentifierClass numBits>
bool decodeNoteSection(ArrayRef<const uint8_t> sectionData, std::vector<DecodedNote> &out, std::string &outErrReason, std::string &outWarning) {
uint64_t pos = 0;
auto sectionSize = sectionData.size();
auto base = sectionData.begin();
while (pos < sectionSize) {
auto note = reinterpret_cast<const ElfNoteSection *>(base + pos);
auto alignedEntrySize = alignUp(sizeof(ElfNoteSection) + note->nameSize + note->descSize, 4);
if (pos + alignedEntrySize > sectionSize) {
outErrReason.append("Invalid elf note section - not enough data\n");
return false;
}
ConstStringRef name{reinterpret_cast<const char *>(note + 1), note->nameSize};
ConstStringRef desc{reinterpret_cast<const char *>(note + 1) + note->nameSize, note->descSize};
pos += alignedEntrySize;
out.push_back(DecodedNote{name, desc, note->type});
}
return true;
}
template bool decodeNoteSection<EI_CLASS_32>(ArrayRef<const uint8_t> sectionData, std::vector<DecodedNote> &out, std::string &outErrReason, std::string &outWarning);
template bool decodeNoteSection<EI_CLASS_64>(ArrayRef<const uint8_t> sectionData, std::vector<DecodedNote> &out, std::string &outErrReason, std::string &outWarning);
template <ElfIdentifierClass numBits>
const ElfFileHeader<numBits> *decodeElfFileHeader(const ArrayRef<const uint8_t> binary) {
if (binary.size() < sizeof(ElfFileHeader<numBits>)) {
@@ -87,7 +112,7 @@ Elf<numBits> decodeElf(const ArrayRef<const uint8_t> binary, std::string &outErr
}
template <ElfIdentifierClass numBits>
bool Elf<numBits>::decodeSymTab(SectionHeaderAndData &sectionHeaderData, std::string &outError) {
bool Elf<numBits>::decodeSymTab(SectionHeaderAndData<numBits> &sectionHeaderData, std::string &outError) {
if (sectionHeaderData.header->type == SectionHeaderType::SHT_SYMTAB) {
auto symSize = sizeof(ElfSymbolEntry<numBits>);
if (symSize != sectionHeaderData.header->entsize) {
@@ -107,7 +132,7 @@ bool Elf<numBits>::decodeSymTab(SectionHeaderAndData &sectionHeaderData, std::st
}
template <ElfIdentifierClass numBits>
bool Elf<numBits>::decodeRelocations(SectionHeaderAndData &sectionHeaderData, std::string &outError) {
bool Elf<numBits>::decodeRelocations(SectionHeaderAndData<numBits> &sectionHeaderData, std::string &outError) {
if (sectionHeaderData.header->type == SectionHeaderType::SHT_RELA) {
auto relaSize = sizeof(ElfRela<numBits>);
if (relaSize != sectionHeaderData.header->entsize) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -22,18 +22,20 @@ enum class RelocationX8664Type : uint32_t {
relocation32 = 0xa
};
template <ElfIdentifierClass numBits = EI_CLASS_64>
struct ProgramHeaderAndData {
const ElfProgramHeader<numBits> *header = nullptr;
ArrayRef<const uint8_t> data;
};
template <ElfIdentifierClass numBits = EI_CLASS_64>
struct SectionHeaderAndData {
const ElfSectionHeader<numBits> *header;
ArrayRef<const uint8_t> data;
};
template <ElfIdentifierClass numBits = EI_CLASS_64>
struct Elf {
struct ProgramHeaderAndData {
const ElfProgramHeader<numBits> *header = nullptr;
ArrayRef<const uint8_t> data;
};
struct SectionHeaderAndData {
const ElfSectionHeader<numBits> *header;
ArrayRef<const uint8_t> data;
};
struct RelocationInfo {
int symbolSectionIndex;
int symbolTableIndex;
@@ -72,11 +74,15 @@ struct Elf {
}
}
MOCKABLE_VIRTUAL std::string getSymbolName(uint32_t nameOffset) const {
std::string getName(uint32_t nameOffset) const {
auto sectionHeaderNamesData = sectionHeaders[elfFileHeader->shStrNdx].data;
return std::string(reinterpret_cast<const char *>(sectionHeaderNamesData.begin()) + nameOffset);
}
MOCKABLE_VIRTUAL std::string getSymbolName(uint32_t nameOffset) const {
return getName(nameOffset);
}
decltype(ElfSymbolEntry<numBits>::value) getSymbolValue(uint32_t idx) const {
return symbolTable[idx].value;
}
@@ -98,12 +104,12 @@ struct Elf {
}
const ElfFileHeader<numBits> *elfFileHeader = nullptr;
StackVec<ProgramHeaderAndData, 32> programHeaders;
StackVec<SectionHeaderAndData, 32> sectionHeaders;
StackVec<ProgramHeaderAndData<numBits>, 32> programHeaders;
StackVec<SectionHeaderAndData<numBits>, 32> sectionHeaders;
protected:
bool decodeSymTab(SectionHeaderAndData &sectionHeaderData, std::string &outError);
bool decodeRelocations(SectionHeaderAndData &sectionHeaderData, std::string &outError);
bool decodeSymTab(SectionHeaderAndData<numBits> &sectionHeaderData, std::string &outError);
bool decodeRelocations(SectionHeaderAndData<numBits> &sectionHeaderData, std::string &outError);
bool isDebugDataRelocation(ConstStringRef sectionName);
SymbolsTable symbolTable;
@@ -111,6 +117,17 @@ struct Elf {
Relocations debugInfoRelocations;
};
struct DecodedNote {
ConstStringRef name;
ConstStringRef desc;
uint32_t type;
};
template <ElfIdentifierClass numBits = EI_CLASS_64>
bool decodeNoteSection(ArrayRef<const uint8_t> sectionData, std::vector<DecodedNote> &out, std::string &outErrReason, std::string &outWarning);
extern template bool decodeNoteSection<EI_CLASS_32>(ArrayRef<const uint8_t> sectionData, std::vector<DecodedNote> &out, std::string &outErrReason, std::string &outWarning);
extern template bool decodeNoteSection<EI_CLASS_64>(ArrayRef<const uint8_t> sectionData, std::vector<DecodedNote> &out, std::string &outErrReason, std::string &outWarning);
template <ElfIdentifierClass numBits = EI_CLASS_64>
const ElfFileHeader<numBits> *decodeElfFileHeader(const ArrayRef<const uint8_t> binary);
extern template const ElfFileHeader<EI_CLASS_32> *decodeElfFileHeader<EI_CLASS_32>(const ArrayRef<const uint8_t>);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -29,7 +29,7 @@ ElfEncoder<numBits>::ElfEncoder(bool addUndefSectionHeader, bool addHeaderSectio
}
template <ElfIdentifierClass numBits>
void ElfEncoder<numBits>::appendSection(const ElfSectionHeader<numBits> &sectionHeader, const ArrayRef<const uint8_t> sectionData) {
ElfSectionHeader<numBits> &ElfEncoder<numBits>::appendSection(const ElfSectionHeader<numBits> &sectionHeader, const ArrayRef<const uint8_t> sectionData) {
sectionHeaders.push_back(sectionHeader);
if ((SHT_NOBITS != sectionHeader.type) && (false == sectionData.empty())) {
auto sectionDataAlignment = std::min<uint64_t>(defaultDataAlignment, 8U);
@@ -42,10 +42,11 @@ void ElfEncoder<numBits>::appendSection(const ElfSectionHeader<numBits> &section
sectionHeaders.rbegin()->offset = static_cast<decltype(sectionHeaders.rbegin()->offset)>(alignedOffset);
sectionHeaders.rbegin()->size = static_cast<decltype(sectionHeaders.rbegin()->size)>(sectionData.size());
}
return *sectionHeaders.rbegin();
}
template <ElfIdentifierClass numBits>
void ElfEncoder<numBits>::appendSegment(const ElfProgramHeader<numBits> &programHeader, const ArrayRef<const uint8_t> segmentData) {
ElfProgramHeader<numBits> &ElfEncoder<numBits>::appendSegment(const ElfProgramHeader<numBits> &programHeader, const ArrayRef<const uint8_t> segmentData) {
maxDataAlignmentNeeded = std::max<uint64_t>(maxDataAlignmentNeeded, static_cast<uint64_t>(programHeader.align));
programHeaders.push_back(programHeader);
if (false == segmentData.empty()) {
@@ -59,6 +60,7 @@ void ElfEncoder<numBits>::appendSegment(const ElfProgramHeader<numBits> &program
programHeaders.rbegin()->offset = static_cast<decltype(programHeaders.rbegin()->offset)>(alignedOffset);
programHeaders.rbegin()->fileSz = static_cast<decltype(programHeaders.rbegin()->fileSz)>(segmentData.size());
}
return *programHeaders.rbegin();
}
template <ElfIdentifierClass numBits>
@@ -89,8 +91,7 @@ ElfSectionHeader<numBits> &ElfEncoder<numBits>::appendSection(SectionHeaderType
default:
break;
}
appendSection(section, sectionData);
return *sectionHeaders.rbegin();
return appendSection(section, sectionData);
}
template <ElfIdentifierClass numBits>
@@ -100,8 +101,7 @@ ElfProgramHeader<numBits> &ElfEncoder<numBits>::appendSegment(ProgramHeaderType
segment.flags = static_cast<decltype(segment.flags)>(PF_NONE);
segment.offset = 0U;
segment.align = static_cast<decltype(segment.align)>(defaultDataAlignment);
appendSegment(segment, segmentData);
return *programHeaders.rbegin();
return appendSegment(segment, segmentData);
}
template <ElfIdentifierClass numBits>
@@ -200,6 +200,37 @@ std::vector<uint8_t> ElfEncoder<numBits>::encode() const {
return ret;
}
template <ElfIdentifierClass numBits>
std::vector<uint8_t> encodeNoteSectionData(ArrayRef<const NoteToEncode> notes) {
std::vector<uint8_t> ret;
{
size_t dataSize = 0U;
for (auto &note : notes) {
dataSize += sizeof(ElfNoteSection);
dataSize += note.name.size();
dataSize += note.desc.size();
dataSize = alignUp(dataSize, 4);
}
ret.reserve(dataSize);
}
for (auto &note : notes) {
ElfNoteSection entry;
entry.nameSize = static_cast<uint32_t>(note.name.size());
entry.descSize = static_cast<uint32_t>(note.desc.size());
entry.type = note.type;
ret.insert(ret.end(), reinterpret_cast<uint8_t *>(&entry), reinterpret_cast<uint8_t *>((&entry) + 1));
ret.insert(ret.end(), reinterpret_cast<const uint8_t *>(note.name.c_str()), reinterpret_cast<const uint8_t *>(note.name.c_str() + note.name.size()));
ret.insert(ret.end(), reinterpret_cast<const uint8_t *>(note.desc.c_str()), reinterpret_cast<const uint8_t *>(note.desc.c_str() + note.desc.size()));
ret.resize(alignUp(ret.size(), 4), 0U);
}
return ret;
}
template std::vector<uint8_t> encodeNoteSectionData<EI_CLASS_64>(ArrayRef<const NoteToEncode> notes);
template std::vector<uint8_t> encodeNoteSectionData<EI_CLASS_32>(ArrayRef<const NoteToEncode> notes);
template struct ElfEncoder<EI_CLASS_32>;
template struct ElfEncoder<EI_CLASS_64>;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -13,6 +13,7 @@
#include <queue>
#include <string>
#include <vector>
namespace NEO {
@@ -54,8 +55,8 @@ struct ElfEncoder {
ElfEncoder(bool addUndefSectionHeader = true, bool addHeaderSectionNamesSection = true,
typename ElfSectionHeaderTypes<numBits>::AddrAlign defaultDataAlignment = 8U);
void appendSection(const ElfSectionHeader<numBits> &sectionHeader, const ArrayRef<const uint8_t> sectionData);
void appendSegment(const ElfProgramHeader<numBits> &programHeader, const ArrayRef<const uint8_t> segmentData);
ElfSectionHeader<numBits> &appendSection(const ElfSectionHeader<numBits> &sectionHeader, const ArrayRef<const uint8_t> sectionData);
ElfProgramHeader<numBits> &appendSegment(const ElfProgramHeader<numBits> &programHeader, const ArrayRef<const uint8_t> segmentData);
ElfSectionHeader<numBits> &appendSection(SectionHeaderType sectionType, ConstStringRef sectionLabel, const ArrayRef<const uint8_t> sectionData);
ElfProgramHeader<numBits> &appendSegment(ProgramHeaderType segmentType, const ArrayRef<const uint8_t> segmentData);
@@ -99,6 +100,17 @@ struct ElfEncoder {
uint32_t shStrTabNameOffset = 0;
};
struct NoteToEncode {
std::string name;
std::string desc;
uint32_t type;
};
template <ElfIdentifierClass numBits = EI_CLASS_64>
std::vector<uint8_t> encodeNoteSectionData(ArrayRef<const NoteToEncode> notes);
extern template std::vector<uint8_t> encodeNoteSectionData<EI_CLASS_64>(ArrayRef<const NoteToEncode> notes);
extern template std::vector<uint8_t> encodeNoteSectionData<EI_CLASS_32>(ArrayRef<const NoteToEncode> notes);
extern template struct ElfEncoder<EI_CLASS_32>;
extern template struct ElfEncoder<EI_CLASS_64>;

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/device_binary_format/elf/elf.h"
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/elf/elf_encoder.h"
#include "shared/source/utilities/arrayref.h"
#include "shared/source/utilities/stackvec.h"
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace NEO {
namespace Elf {
template <ElfIdentifierClass NumBits = NEO::Elf::EI_CLASS_64>
struct MutableSectionHeader {
MutableSectionHeader(const std::string &name, const NEO::Elf::ElfSectionHeader<NumBits> &header, const std::vector<uint8_t> &data)
: name(name), header(header), data(data) {
}
std::string name;
NEO::Elf::ElfSectionHeader<NumBits> header{};
std::vector<uint8_t> data;
};
template <ElfIdentifierClass NumBits = NEO::Elf::EI_CLASS_64>
struct MutableProgramHeader {
MutableProgramHeader(const NEO::Elf::ElfProgramHeader<NumBits> &header, const std::vector<uint8_t> &data)
: header(header), data(data) {
}
NEO::Elf::ElfProgramHeader<NumBits> header = {};
std::vector<uint8_t> data;
MutableSectionHeader<NumBits> *referencedSectionData = nullptr;
};
template <ElfIdentifierClass NumBits = NEO::Elf::EI_CLASS_64>
struct ElfRewriter {
using SectionId = uint32_t;
ElfRewriter(NEO::Elf::Elf<NumBits> &src) {
elfFileHeader = *src.elfFileHeader;
for (const auto &sh : src.sectionHeaders) {
this->sectionHeaders.push_back(std::make_unique<MutableSectionHeader<NumBits>>(src.getName(sh.header->name), *sh.header, std::vector<uint8_t>{sh.data.begin(), sh.data.end()}));
}
for (const auto &ph : src.programHeaders) {
this->programHeaders.push_back(std::make_unique<MutableProgramHeader<NumBits>>(*ph.header, std::vector<uint8_t>{ph.data.begin(), ph.data.end()}));
for (const auto &sh : this->sectionHeaders) {
if ((sh->header.offset == ph.header->offset) && (sh->header.size == ph.header->fileSz)) {
(*this->programHeaders.rbegin())->referencedSectionData = sh.get();
}
}
}
}
std::vector<uint8_t> encode() const {
NEO::Elf::ElfEncoder<NumBits> encoder;
encoder.getElfFileHeader() = elfFileHeader;
std::unordered_map<MutableSectionHeader<NumBits> *, decltype(NEO::Elf::ElfSectionHeader<NumBits>::offset)> encodedSectionsOffsets;
for (const auto &sh : this->sectionHeaders) {
if ((sh->header.type == SHT_NULL) || (sh->header.type == SHT_STRTAB)) {
continue;
}
auto nameIdx = encoder.appendSectionName(sh->name);
NEO::Elf::ElfSectionHeader<NumBits> header = sh->header;
header.name = nameIdx;
encodedSectionsOffsets[sh.get()] = encoder.appendSection(header, sh->data).offset;
}
for (const auto &ph : this->programHeaders) {
if (ph->referencedSectionData) {
auto &header = ph->header;
header.offset = encodedSectionsOffsets[ph->referencedSectionData];
encoder.appendSegment(ph->header, {});
} else {
encoder.appendSegment(ph->header, ph->data);
}
}
return encoder.encode();
}
StackVec<SectionId, 16> findSections(typename ElfSectionHeaderTypes<NumBits>::Type type, ConstStringRef name) {
StackVec<SectionId, 16> ret;
for (size_t i = 0; i < this->sectionHeaders.size(); i++) {
auto &section = this->sectionHeaders[i];
if ((type == section->header.type) && (name == section->name)) {
ret.push_back(static_cast<SectionId>(i));
}
}
return ret;
}
MutableSectionHeader<NumBits> &getSection(SectionId idx) {
return *sectionHeaders[idx];
}
void removeSection(SectionId idx) {
auto sectionHeaderToRemove = std::move(sectionHeaders[idx]);
for (auto it = idx + 1; it < sectionHeaders.size(); ++it) { // preserve order
sectionHeaders[it - 1] = std::move(sectionHeaders[it]);
}
sectionHeaders.pop_back();
for (auto &programHeader : programHeaders) {
if (sectionHeaderToRemove.get() == programHeader->referencedSectionData) {
programHeader->referencedSectionData = nullptr;
}
}
}
ElfFileHeader<NumBits> elfFileHeader = {};
protected:
StackVec<std::unique_ptr<MutableSectionHeader<NumBits>>, 32> sectionHeaders;
StackVec<std::unique_ptr<MutableProgramHeader<NumBits>>, 32> programHeaders;
};
} // namespace Elf
} // namespace NEO

View File

@@ -8,6 +8,7 @@
#pragma once
#include "shared/source/device_binary_format/device_binary_formats.h"
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/zebin/zebin_elf.h"
#include "shared/source/utilities/stackvec.h"
@@ -29,7 +30,7 @@ namespace Zebin {
template <Elf::ElfIdentifierClass numBits = Elf::EI_CLASS_64>
struct ZebinSections {
using SectionHeaderData = typename NEO::Elf::Elf<numBits>::SectionHeaderAndData;
using SectionHeaderData = NEO::Elf::SectionHeaderAndData<numBits>;
StackVec<SectionHeaderData *, 32> textKernelSections;
StackVec<SectionHeaderData *, 32> gtpinInfoSections;
StackVec<SectionHeaderData *, 1> zeInfoSections;

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2020-2022 Intel Corporation
# Copyright (C) 2020-2024 Intel Corporation
#
# SPDX-License-Identifier: MIT
#
@@ -15,6 +15,7 @@ target_sources(neo_shared_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/device_binary_formats_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_decoder_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_encoder_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_rewriter_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/elf/elf_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_decoder_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/patchtokens_dumper_tests.cpp
@@ -22,4 +23,4 @@ target_sources(neo_shared_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/yaml/yaml_parser_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zebin_debug_binary_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/zebin_decoder_tests.cpp
)
)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -309,7 +309,7 @@ TEST(PackDeviceBinaryOclElf, WhenPackingBinaryWitIntermediateRepresentationThenC
EXPECT_EQ(3U, elf.elfFileHeader->shNum);
auto spirVSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(),
[](const Elf<>::SectionHeaderAndData &section) { return section.header->type == NEO::Elf::SHT_OPENCL_SPIRV; });
[](const SectionHeaderAndData<> &section) { return section.header->type == NEO::Elf::SHT_OPENCL_SPIRV; });
ASSERT_NE(nullptr, spirVSection);
ASSERT_EQ(spirV.size(), spirVSection->data.size());
EXPECT_EQ(0, memcmp(spirV.begin(), spirVSection->data.begin(), spirV.size()));
@@ -338,7 +338,7 @@ TEST(PackDeviceBinaryOclElf, WhenPackingBinaryWitIntermediateRepresentationThenC
EXPECT_EQ(3U, elf.elfFileHeader->shNum);
auto llvmSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(),
[](const Elf<>::SectionHeaderAndData &section) { return section.header->type == NEO::Elf::SHT_OPENCL_LLVM_BINARY; });
[](const SectionHeaderAndData<> &section) { return section.header->type == NEO::Elf::SHT_OPENCL_LLVM_BINARY; });
ASSERT_NE(nullptr, llvmSection);
ASSERT_EQ(llvmBc.size(), llvmSection->data.size());
EXPECT_EQ(0, memcmp(llvmBc.begin(), llvmSection->data.begin(), llvmBc.size()));
@@ -372,16 +372,16 @@ TEST(PackDeviceBinaryOclElf, WhenPackingBinaryThenSectionsAreProperlyPopulated)
ASSERT_NE(nullptr, elf.elfFileHeader);
auto spirvSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(),
[](const Elf<>::SectionHeaderAndData &section) { return section.header->type == NEO::Elf::SHT_OPENCL_SPIRV; });
[](const SectionHeaderAndData<> &section) { return section.header->type == NEO::Elf::SHT_OPENCL_SPIRV; });
auto deviceBinarySection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(),
[](const Elf<>::SectionHeaderAndData &section) { return section.header->type == NEO::Elf::SHT_OPENCL_DEV_BINARY; });
[](const SectionHeaderAndData<> &section) { return section.header->type == NEO::Elf::SHT_OPENCL_DEV_BINARY; });
auto deviceDebugSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(),
[](const Elf<>::SectionHeaderAndData &section) { return section.header->type == NEO::Elf::SHT_OPENCL_DEV_DEBUG; });
[](const SectionHeaderAndData<> &section) { return section.header->type == NEO::Elf::SHT_OPENCL_DEV_DEBUG; });
auto buildOptionsSection = std::find_if(elf.sectionHeaders.begin(), elf.sectionHeaders.end(),
[](const Elf<>::SectionHeaderAndData &section) { return section.header->type == NEO::Elf::SHT_OPENCL_OPTIONS; });
[](const SectionHeaderAndData<> &section) { return section.header->type == NEO::Elf::SHT_OPENCL_OPTIONS; });
ASSERT_NE(nullptr, spirvSection);
ASSERT_EQ(spirV.size(), spirvSection->data.size());

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2023 Intel Corporation
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -8,6 +8,7 @@
#include "shared/source/device_binary_format/elf/elf.h"
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/elf/elf_encoder.h"
#include "shared/source/helpers/aligned_memory.h"
#include "shared/source/helpers/array_count.h"
#include "shared/source/helpers/file_io.h"
#include "shared/test/common/helpers/gtest_helpers.h"
@@ -16,6 +17,9 @@
#include "gtest/gtest.h"
#include <string>
#include <vector>
using namespace NEO::Elf;
using ELF_CLASS = NEO::Elf::ElfIdentifierClass;
@@ -812,3 +816,77 @@ TEST(ElfDecoder, GivenElfWithRelocationsWhenDecodedThenCorrectRelocationsAndSymo
EXPECT_EQ(SymbolTableType::STT_OBJECT, elf64.extractSymbolType(symbolTable[3]));
EXPECT_EQ(SymbolTableBind::STB_GLOBAL, elf64.extractSymbolBind(symbolTable[3]));
}
TEST(DecodeElfNoteSection, GivenEmptyDataSectionThenDecodeAsZeroEntries) {
std::vector<NEO::Elf::DecodedNote> decodedNotes;
std::string err, warn;
auto ret = NEO::Elf::decodeNoteSection(ArrayRef<const uint8_t>{}, decodedNotes, err, warn);
EXPECT_TRUE(ret);
EXPECT_TRUE(err.empty()) << err;
EXPECT_TRUE(warn.empty()) << warn;
EXPECT_TRUE(decodedNotes.empty());
}
TEST(DecodeElfNoteSection, GivenDataSectionWithInvalidSizeThenReturnError) {
std::vector<NEO::Elf::DecodedNote> decodedNotes;
std::string err, warn;
NEO::Elf::ElfNoteSection note;
note.nameSize = 5;
note.descSize = 7;
auto ret = NEO::Elf::decodeNoteSection(ArrayRef<const uint8_t>::fromAny(&note, 1), decodedNotes, err, warn);
EXPECT_FALSE(ret);
EXPECT_FALSE(err.empty());
EXPECT_TRUE(warn.empty()) << warn;
EXPECT_TRUE(decodedNotes.empty());
}
TEST(DecodeElfNoteSection, GivenValidNotesThenDecodeThem) {
std::string unalignedDescName = "note"
"Type";
std::string unalignedDesc = "some"
" Des"
"c ";
uint32_t unalignedDescNoteType = 3;
std::string unalignedNameName = "note"
"Ty";
std::string unalignedNameDesc = "so"
"me";
uint32_t unalignedNameNoteType = 5;
std::string alignedDescName = "some"
"Note";
std::string alignedDesc = "some"
"Desc";
uint32_t alignedDescNoteType = 7;
NEO::Elf::DecodedNote notes[] = {{unalignedDescName, unalignedDesc, unalignedDescNoteType},
{unalignedNameName, unalignedNameDesc, unalignedNameNoteType},
{alignedDescName, alignedDesc, alignedDescNoteType}};
std::vector<uint8_t> data;
for (const auto &note : notes) {
NEO::Elf::ElfNoteSection section;
section.nameSize = static_cast<uint32_t>(note.name.size());
section.descSize = static_cast<uint32_t>(note.desc.size());
section.type = note.type;
data.insert(data.end(), reinterpret_cast<const uint8_t *>(&section), reinterpret_cast<const uint8_t *>(&section + 1));
data.insert(data.end(), reinterpret_cast<const uint8_t *>(note.name.begin()), reinterpret_cast<const uint8_t *>(note.name.end()));
data.insert(data.end(), reinterpret_cast<const uint8_t *>(note.desc.begin()), reinterpret_cast<const uint8_t *>(note.desc.end()));
data.resize(alignUp(data.size(), 4));
}
std::vector<NEO::Elf::DecodedNote> decodedNotes;
std::string err, warn;
auto ret = NEO::Elf::decodeNoteSection(data, decodedNotes, err, warn);
EXPECT_TRUE(ret);
EXPECT_TRUE(err.empty()) << err;
EXPECT_TRUE(warn.empty()) << warn;
EXPECT_FALSE(decodedNotes.empty());
ASSERT_EQ(3U, decodedNotes.size());
for (int i = 0; i < 3; ++i) {
EXPECT_EQ(notes[i].type, decodedNotes[i].type);
EXPECT_EQ(notes[i].name, decodedNotes[i].name);
EXPECT_EQ(notes[i].desc, decodedNotes[i].desc);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2022 Intel Corporation
* Copyright (C) 2020-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -500,3 +500,55 @@ TEST(ElfEncoder, WhenGetSectionHeaderIndexIsCalledThenCorrectSectionIdxIsReturne
auto &sec1 = elfEncoder64.appendSection(SHT_PROGBITS, "", {});
EXPECT_EQ(1U, elfEncoder64.getSectionHeaderIndex(sec1));
}
TEST(DecodeElfNoteSection, givenZeroNotesToEncodeThenReturnsEmptyDataVector) {
auto encoded = NEO::Elf::encodeNoteSectionData({});
EXPECT_TRUE(encoded.empty());
}
TEST(DecodeElfNoteSection, givenValidNotesToEncodeThenReturnsProperlyEncodedData) {
std::string unalignedDescName = "note"
"Type";
std::string unalignedDesc = "some"
" Des"
"c ";
uint32_t unalignedDescNoteType = 3;
std::string unalignedNameName = "note"
"Ty";
std::string unalignedNameDesc = "so"
"me";
uint32_t unalignedNameNoteType = 5;
std::string alignedDescName = "some"
"Note";
std::string alignedDesc = "some"
"Desc";
uint32_t alignedDescNoteType = 7;
NEO::Elf::NoteToEncode notes[] = {{unalignedDescName, unalignedDesc, unalignedDescNoteType},
{unalignedNameName, unalignedNameDesc, unalignedNameNoteType},
{alignedDescName, alignedDesc, alignedDescNoteType}};
size_t expectedSize = 0;
for (const auto &note : notes) {
expectedSize += sizeof(NEO::Elf::ElfNoteSection);
expectedSize += note.name.size();
expectedSize += note.desc.size();
expectedSize = alignUp(expectedSize, 4);
}
auto encoded = NEO::Elf::encodeNoteSectionData({notes, 3});
ASSERT_EQ(expectedSize, encoded.size());
uint8_t *pos = encoded.data();
for (int i = 0; i < 3; ++i) {
auto header = reinterpret_cast<NEO::Elf::ElfNoteSection *>(pos);
EXPECT_EQ(notes[i].type, header->type);
EXPECT_EQ(notes[i].name.size(), header->nameSize);
EXPECT_EQ(notes[i].desc.size(), header->descSize);
EXPECT_EQ(notes[i].name, NEO::ConstStringRef(reinterpret_cast<const char *>((header + 1)), notes[i].name.size()));
EXPECT_EQ(notes[i].desc, NEO::ConstStringRef(reinterpret_cast<const char *>((header + 1)) + notes[i].name.size(), notes[i].desc.size()));
pos = alignUp(pos + sizeof(NEO::Elf::ElfNoteSection) + notes[i].name.size() + notes[i].desc.size(), 4);
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/device_binary_format/elf/elf.h"
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include "shared/source/device_binary_format/elf/elf_encoder.h"
#include "shared/source/device_binary_format/elf/elf_rewriter.h"
#include "gtest/gtest.h"
namespace NEO::Elf {
inline bool operator==(const ElfFileHeaderIdentity &lhs, const ElfFileHeaderIdentity &rhs) {
return (lhs.abiVersion == rhs.abiVersion) && (lhs.data == rhs.data) && (lhs.eClass == rhs.eClass) && (lhs.osAbi == rhs.osAbi) && (lhs.version == rhs.version) && (lhs.magic[0] == rhs.magic[0]) && (lhs.magic[1] == rhs.magic[1]) && (lhs.magic[2] == rhs.magic[2]) && (lhs.magic[3] == rhs.magic[3]);
}
template <ElfIdentifierClass NumBits>
inline bool operator==(const ElfFileHeader<NumBits> &lhs, const ElfFileHeader<NumBits> &rhs) {
return (lhs.identity == rhs.identity) && (lhs.type == rhs.type) && (lhs.machine == rhs.machine) && (lhs.version == rhs.version) && (lhs.entry == rhs.entry) && (lhs.phOff == rhs.phOff) && (lhs.shOff == rhs.shOff) && (lhs.flags == rhs.flags) && (lhs.ehSize == rhs.ehSize) && (lhs.phEntSize == rhs.phEntSize) && (lhs.phNum == rhs.phNum) && (lhs.shEntSize == rhs.shEntSize) && (lhs.shNum == rhs.shNum) && (lhs.shStrNdx == rhs.shStrNdx);
}
template <ElfIdentifierClass NumBits>
inline bool operator==(const SectionHeaderAndData<NumBits> &lhs, const SectionHeaderAndData<NumBits> &rhs) {
return (lhs.header->name == rhs.header->name) && (lhs.header->type == rhs.header->type) && (lhs.header->flags == rhs.header->flags) && (lhs.header->addr == rhs.header->addr) && (lhs.header->offset == rhs.header->offset) && (lhs.header->size == rhs.header->size) && (lhs.header->link == rhs.header->link) && (lhs.header->info == rhs.header->info) && (lhs.header->addralign == rhs.header->addralign) && (lhs.header->entsize == rhs.header->entsize) && (lhs.data.size() == rhs.data.size()) && ((lhs.data.size() == 0) || (0 == memcmp(lhs.data.begin(), rhs.data.begin(), lhs.data.size())));
}
template <ElfIdentifierClass NumBits>
inline bool operator==(const ProgramHeaderAndData<NumBits> &lhs, const ProgramHeaderAndData<NumBits> &rhs) {
return (lhs.header->type == rhs.header->type) && (lhs.header->offset == rhs.header->offset) && (lhs.header->vAddr == rhs.header->vAddr) && (lhs.header->pAddr == rhs.header->pAddr) && (lhs.header->fileSz == rhs.header->fileSz) && (lhs.header->memSz == rhs.header->memSz) && (lhs.header->flags == rhs.header->flags) && (lhs.header->align == rhs.header->align) && (lhs.data.size() == rhs.data.size()) && ((lhs.data.size() == 0) || (0 == memcmp(lhs.data.begin(), rhs.data.begin(), lhs.data.size())));
}
} // namespace NEO::Elf
TEST(ElfRewriter, GivenElfWhenNotModifiedThenOutputIsSameAsSource) {
NEO::Elf::ElfEncoder<> encoder;
std::vector<uint8_t> txtData;
txtData.resize(4096U, 7);
auto &txtSection = encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt", txtData);
encoder.appendProgramHeaderLoad(encoder.getSectionHeaderIndex(txtSection), 4096U, 4096U);
auto elfBinSrc = encoder.encode();
std::string err, warn;
auto decodedElfSrc = NEO::Elf::decodeElf(elfBinSrc, err, warn);
ASSERT_TRUE(err.empty()) << err;
ASSERT_TRUE(warn.empty()) << warn;
NEO::Elf::ElfRewriter<> rewriter{decodedElfSrc};
auto elfBinOut = rewriter.encode();
ASSERT_EQ(elfBinSrc.size(), elfBinOut.size());
auto decodedElfOut = NEO::Elf::decodeElf(elfBinOut, err, warn);
ASSERT_TRUE(err.empty()) << err;
ASSERT_TRUE(warn.empty()) << warn;
EXPECT_EQ(*decodedElfSrc.elfFileHeader, *decodedElfOut.elfFileHeader);
ASSERT_EQ(decodedElfSrc.sectionHeaders.size(), decodedElfOut.sectionHeaders.size());
for (size_t i = 0; i < decodedElfSrc.sectionHeaders.size(); ++i) {
EXPECT_EQ(decodedElfSrc.sectionHeaders[i], decodedElfOut.sectionHeaders[i]);
}
ASSERT_EQ(decodedElfSrc.programHeaders.size(), decodedElfOut.programHeaders.size());
for (size_t i = 0; i < decodedElfSrc.programHeaders.size(); ++i) {
EXPECT_EQ(decodedElfSrc.programHeaders[i], decodedElfOut.programHeaders[i]);
}
}
TEST(ElfRewriterFindSections, GivenSectionTypeAndNameThenReturnsMatchedSections) {
NEO::Elf::ElfEncoder<> encoder;
std::vector<uint8_t> txtData;
txtData.resize(4096U, 7);
encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt", txtData);
encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txtX", txtData);
encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt", txtData);
encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_STRTAB, ".txt", txtData);
auto elfBinSrc = encoder.encode();
std::string err, warn;
auto decodedElfSrc = NEO::Elf::decodeElf(elfBinSrc, err, warn);
ASSERT_TRUE(err.empty()) << err;
ASSERT_TRUE(warn.empty()) << warn;
NEO::Elf::ElfRewriter<> rewriter{decodedElfSrc};
auto foundSections = rewriter.findSections(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt");
ASSERT_EQ(2U, foundSections.size());
EXPECT_EQ(NEO::Elf::SectionHeaderType::SHT_PROGBITS, rewriter.getSection(foundSections[0]).header.type);
EXPECT_EQ(NEO::Elf::SectionHeaderType::SHT_PROGBITS, rewriter.getSection(foundSections[1]).header.type);
EXPECT_EQ(".txt", rewriter.getSection(foundSections[0]).name);
EXPECT_EQ(".txt", rewriter.getSection(foundSections[1]).name);
}
TEST(ElfRewriterRemoveSection, GivenSectionIndexThenRemovesThatSection) {
NEO::Elf::ElfEncoder<> encoder;
std::vector<uint8_t> txtData;
txtData.resize(4096U, 7);
auto &sectionWithLoad = encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt.0", txtData);
encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt.1", txtData);
encoder.appendProgramHeaderLoad(encoder.getSectionHeaderIndex(sectionWithLoad), 4096U, 4096U);
auto elfBinSrc = encoder.encode();
std::string err, warn;
auto decodedElfSrc = NEO::Elf::decodeElf(elfBinSrc, err, warn);
ASSERT_TRUE(err.empty()) << err;
ASSERT_TRUE(warn.empty()) << warn;
NEO::Elf::ElfRewriter<> rewriter{decodedElfSrc};
auto foundSections = rewriter.findSections(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt.0");
ASSERT_EQ(1U, foundSections.size());
EXPECT_EQ(NEO::Elf::SectionHeaderType::SHT_PROGBITS, rewriter.getSection(foundSections[0]).header.type);
EXPECT_EQ(".txt.0", rewriter.getSection(foundSections[0]).name);
rewriter.removeSection(foundSections[0]);
EXPECT_EQ(0U, rewriter.findSections(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt.0").size());
NEO::Elf::decodeElf(rewriter.encode(), err, warn);
EXPECT_TRUE(err.empty()) << err;
EXPECT_TRUE(warn.empty()) << warn;
foundSections = rewriter.findSections(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt.1");
ASSERT_EQ(1U, foundSections.size());
EXPECT_EQ(NEO::Elf::SectionHeaderType::SHT_PROGBITS, rewriter.getSection(foundSections[0]).header.type);
EXPECT_EQ(".txt.1", rewriter.getSection(foundSections[0]).name);
rewriter.removeSection(foundSections[0]);
EXPECT_EQ(0U, rewriter.findSections(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt.1").size());
NEO::Elf::decodeElf(rewriter.encode(), err, warn);
EXPECT_TRUE(err.empty()) << err;
EXPECT_TRUE(warn.empty()) << warn;
}