Handle relocations from zeBin

Related-To: NEO-5323

Signed-off-by: Mateusz Hoppe <mateusz.hoppe@intel.com>
This commit is contained in:
Mateusz Hoppe
2021-01-19 17:29:20 +01:00
committed by Compute-Runtime-Automation
parent d19d8e0829
commit 5d2ea72db6
11 changed files with 798 additions and 8 deletions

View File

@@ -8,6 +8,7 @@
#include "level_zero/core/source/module/module_imp.h"
#include "shared/source/compiler_interface/intermediate_representations.h"
#include "shared/source/compiler_interface/linker.h"
#include "shared/source/device/device.h"
#include "shared/source/device_binary_format/device_binary_formats.h"
#include "shared/source/helpers/api_specific_config.h"
@@ -28,6 +29,7 @@
#include "program_debug_data.h"
#include <memory>
#include <unordered_map>
namespace L0 {
@@ -225,6 +227,18 @@ bool ModuleTranslationUnit::processUnpackedBinary() {
kernelInfo->apply(deviceInfoConstants);
}
if (programInfo.decodedElf.elfFileHeader) {
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
uint32_t id = 0;
for (auto &kernelInfo : this->programInfo.kernelInfos) {
nameToKernelId[kernelInfo->kernelDescriptor.kernelMetadata.kernelName] = id;
id++;
}
programInfo.prepareLinkerInputStorage();
programInfo.linkerInput->decodeElfSymbolTableAndRelocations(programInfo.decodedElf, nameToKernelId);
}
auto gfxCore = device->getNEODevice()->getHardwareInfo().platform.eRenderCoreFamily;
auto stepping = device->getNEODevice()->getHardwareInfo().platform.usRevId;

View File

@@ -725,6 +725,32 @@ HWTEST_F(ModuleTranslationUnitTest, WhenCreatingFromNativeBinaryThenSetsUpRequir
EXPECT_FALSE(success);
}
HWTEST_F(ModuleTranslationUnitTest, WhenCreatingFromZeBinaryThenLinkerInputIsCreated) {
std::string validZeInfo = std::string("version :\'") + toString(zeInfoDecoderVersion) + R"===('
kernels:
- name : some_kernel
execution_env :
simd_size : 8
- name : some_other_kernel
execution_env :
simd_size : 32
)===";
ZebinTestData::ValidEmptyProgram zebin;
zebin.removeSection(NEO::Elf::SHT_ZEBIN::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo);
zebin.appendSection(NEO::Elf::SHT_ZEBIN::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, ArrayRef<const uint8_t>::fromAny(validZeInfo.data(), validZeInfo.size()));
zebin.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "some_kernel", {});
zebin.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "some_other_kernel", {});
auto hwInfo = device->getNEODevice()->getHardwareInfo();
zebin.elfHeader->machine = hwInfo.platform.eProductFamily;
L0::ModuleTranslationUnit moduleTuValid(this->device);
bool success = moduleTuValid.createFromNativeBinary(reinterpret_cast<const char *>(zebin.storage.data()), zebin.storage.size());
EXPECT_TRUE(success);
EXPECT_NE(nullptr, moduleTuValid.programInfo.linkerInput.get());
}
HWTEST_F(ModuleTranslationUnitTest, WhenBuildOptionsAreNullThenReuseExistingOptions) {
struct MockCompilerInterface : CompilerInterface {
TranslationOutput::ErrorCode build(const NEO::Device &device,

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2020 Intel Corporation
* Copyright (C) 2017-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -9,6 +9,7 @@
#include "shared/source/compiler_interface/linker.inl"
#include "shared/source/device/device.h"
#include "shared/source/device_binary_format/elf/zebin_elf.h"
#include "shared/source/helpers/blit_commands_helper.h"
#include "shared/source/helpers/debug_helpers.h"
#include "shared/source/helpers/hw_helper.h"
@@ -23,6 +24,17 @@
namespace NEO {
SegmentType LinkerInput::getSegmentForSection(ConstStringRef name) {
if (name == NEO::Elf::SectionsNamesZebin::dataConst || name == NEO::Elf::SectionsNamesZebin::dataGlobalConst) {
return NEO::SegmentType::GlobalConstants;
} else if (name == NEO::Elf::SectionsNamesZebin::dataGlobal) {
return NEO::SegmentType::GlobalVariables;
} else if (name.startsWith(NEO::Elf::SpecialSectionNames::text.data())) {
return NEO::SegmentType::Instructions;
}
return NEO::SegmentType::Unknown;
}
bool LinkerInput::decodeGlobalVariablesSymbolTable(const void *data, uint32_t numEntries) {
auto symbolEntryIt = reinterpret_cast<const vISA::GenSymEntry *>(data);
auto symbolEntryEnd = symbolEntryIt + numEntries;
@@ -131,6 +143,103 @@ void LinkerInput::addDataRelocationInfo(const RelocationInfo &relocationInfo) {
this->dataRelocations.push_back(relocationInfo);
}
void LinkerInput::addElfTextSegmentRelocation(RelocationInfo relocationInfo, uint32_t instructionsSegmentId) {
this->traits.requiresPatchingOfInstructionSegments = true;
if (instructionsSegmentId >= relocations.size()) {
static_assert(std::is_nothrow_move_constructible<decltype(relocations[0])>::value, "");
relocations.resize(instructionsSegmentId + 1);
}
auto &outRelocInfo = relocations[instructionsSegmentId];
relocationInfo.symbolSegment = SegmentType::Unknown;
relocationInfo.relocationSegment = SegmentType::Instructions;
outRelocInfo.push_back(std::move(relocationInfo));
}
void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64> &elf, const SectionNameToSegmentIdMap &nameToSegmentId) {
for (auto &reloc : elf.getRelocations()) {
NEO::LinkerInput::RelocationInfo relocationInfo;
relocationInfo.offset = reloc.offset;
relocationInfo.symbolName = reloc.symbolName;
switch (reloc.relocType) {
case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_64):
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
break;
case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_32):
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
default:
break;
}
auto name = elf.getSectionName(reloc.targetSectionIndex);
ConstStringRef nameRef(name);
if (nameRef.startsWith(NEO::Elf::SectionsNamesZebin::textPrefix.data())) {
auto kernelName = name.substr(static_cast<int>(NEO::Elf::SectionsNamesZebin::textPrefix.length()));
auto segmentIdIter = nameToSegmentId.find(kernelName);
if (segmentIdIter != nameToSegmentId.end()) {
this->addElfTextSegmentRelocation(relocationInfo, segmentIdIter->second);
}
} else if (nameRef.startsWith(NEO::Elf::SpecialSectionNames::data.data())) {
auto symbolSectionName = elf.getSectionName(reloc.symbolSectionIndex);
auto symbolSegment = getSegmentForSection(symbolSectionName);
if (symbolSegment == NEO::SegmentType::GlobalConstants || symbolSegment == NEO::SegmentType::GlobalVariables) {
relocationInfo.symbolSegment = symbolSegment;
auto relocationSegment = getSegmentForSection(nameRef);
if (relocationSegment == NEO::SegmentType::GlobalConstants || relocationSegment == NEO::SegmentType::GlobalVariables) {
relocationInfo.relocationSegment = relocationSegment;
this->addDataRelocationInfo(relocationInfo);
}
} else {
DEBUG_BREAK_IF(true);
}
}
}
symbols.reserve(elf.getSymbols().size());
for (auto &symbol : elf.getSymbols()) {
auto bind = elf.extractSymbolBind(symbol);
if (bind == Elf::SYMBOL_TABLE_BIND::STB_GLOBAL) {
SymbolInfo &symbolInfo = symbols[elf.getSymbolName(symbol.name)];
symbolInfo.offset = static_cast<uint32_t>(symbol.value);
symbolInfo.size = static_cast<uint32_t>(symbol.size);
auto type = elf.extractSymbolType(symbol);
auto symbolSectionName = elf.getSectionName(symbol.shndx);
auto symbolSegment = getSegmentForSection(symbolSectionName);
switch (type) {
default:
DEBUG_BREAK_IF(true);
break;
case Elf::SYMBOL_TABLE_TYPE::STT_OBJECT:
symbolInfo.segment = symbolSegment;
traits.exportsGlobalVariables = symbolSegment == SegmentType::GlobalVariables;
traits.exportsGlobalConstants = symbolSegment == SegmentType::GlobalConstants;
break;
case Elf::SYMBOL_TABLE_TYPE::STT_FUNC: {
auto kernelName = symbolSectionName.substr(static_cast<int>(NEO::Elf::SectionsNamesZebin::textPrefix.length()));
auto segmentIdIter = nameToSegmentId.find(kernelName);
if (segmentIdIter != nameToSegmentId.end()) {
symbolInfo.segment = SegmentType::Instructions;
traits.exportsFunctions = true;
int32_t instructionsSegmentId = static_cast<int32_t>(segmentIdIter->second);
UNRECOVERABLE_IF((this->exportedFunctionsSegmentId != -1) && (this->exportedFunctionsSegmentId != instructionsSegmentId));
this->exportedFunctionsSegmentId = instructionsSegmentId;
}
} break;
}
}
}
}
bool Linker::processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions) {
relocatedSymbols.reserve(data.getSymbols().size());
for (auto &symbol : data.getSymbols()) {

View File

@@ -1,11 +1,12 @@
/*
* Copyright (C) 2017-2020 Intel Corporation
* Copyright (C) 2017-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/device_binary_format/elf/elf_decoder.h"
#include <cstdint>
#include <limits>
@@ -88,18 +89,23 @@ struct LinkerInput {
SegmentType relocationSegment = SegmentType::Unknown;
SegmentType symbolSegment = SegmentType::Unknown;
};
using SectionNameToSegmentIdMap = std::unordered_map<std::string, uint32_t>;
using Relocations = std::vector<RelocationInfo>;
using SymbolMap = std::unordered_map<std::string, SymbolInfo>;
using RelocationsPerInstSegment = std::vector<Relocations>;
virtual ~LinkerInput() = default;
static SegmentType getSegmentForSection(ConstStringRef name);
MOCKABLE_VIRTUAL bool decodeGlobalVariablesSymbolTable(const void *data, uint32_t numEntries);
MOCKABLE_VIRTUAL bool decodeExportedFunctionsSymbolTable(const void *data, uint32_t numEntries, uint32_t instructionsSegmentId);
MOCKABLE_VIRTUAL bool decodeRelocationTable(const void *data, uint32_t numEntries, uint32_t instructionsSegmentId);
void addDataRelocationInfo(const RelocationInfo &relocationInfo);
void addElfTextSegmentRelocation(RelocationInfo relocationInfo, uint32_t instructionsSegmentId);
void decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64> &elf, const SectionNameToSegmentIdMap &nameToSegmentId);
const Traits &getTraits() const {
return traits;
}

View File

@@ -63,12 +63,12 @@ struct Elf {
return (elfSymbol.info >> 4) & 0xf;
}
std::string getSectionName(uint32_t id) const {
MOCKABLE_VIRTUAL std::string getSectionName(uint32_t id) const {
auto sectionHeaderNamesData = sectionHeaders[elfFileHeader->shStrNdx].data;
return std::string(reinterpret_cast<const char *>(sectionHeaderNamesData.begin()) + sectionHeaders[id].header->name);
}
std::string getSymbolName(uint32_t nameOffset) const {
MOCKABLE_VIRTUAL std::string getSymbolName(uint32_t nameOffset) const {
auto sectionHeaderNamesData = sectionHeaders[elfFileHeader->shStrNdx].data;
return std::string(reinterpret_cast<const char *>(sectionHeaderNamesData.begin()) + nameOffset);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2020 Intel Corporation
* Copyright (C) 2019-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -32,6 +32,7 @@ enum SHT_ZEBIN : uint32_t {
namespace SectionsNamesZebin {
static constexpr ConstStringRef textPrefix = ".text.";
static constexpr ConstStringRef dataConst = ".data.const";
static constexpr ConstStringRef dataGlobalConst = ".data.global_const";
static constexpr ConstStringRef dataGlobal = ".data.global";
static constexpr ConstStringRef symtab = ".symtab";
static constexpr ConstStringRef relTablePrefix = ".rel.";

View File

@@ -29,6 +29,7 @@ DecodeError extractZebinSections(NEO::Elf::Elf<Elf::EI_CLASS_64> &elf, ZebinSect
outErrReason.append("DeviceBinaryFormat::Zebin : Invalid or missing shStrNdx in elf header\n");
return DecodeError::InvalidBinary;
}
auto sectionHeaderNamesData = elf.sectionHeaders[elf.elfFileHeader->shStrNdx].data;
ConstStringRef sectionHeaderNamesString(reinterpret_cast<const char *>(sectionHeaderNamesData.begin()), sectionHeaderNamesData.size());
@@ -43,7 +44,7 @@ DecodeError extractZebinSections(NEO::Elf::Elf<Elf::EI_CLASS_64> &elf, ZebinSect
out.textKernelSections.push_back(&elfSectionHeader);
} else if (sectionName == NEO::Elf::SectionsNamesZebin::dataConst) {
out.constDataSections.push_back(&elfSectionHeader);
} else if (sectionName == ".data.global_const") {
} else if (sectionName == NEO::Elf::SectionsNamesZebin::dataGlobalConst) {
outWarning.append("Misspelled section name : " + sectionName.str() + ", should be : " + NEO::Elf::SectionsNamesZebin::dataConst.str() + "\n");
out.constDataSections.push_back(&elfSectionHeader);
} else if (sectionName == NEO::Elf::SectionsNamesZebin::dataGlobal) {
@@ -65,6 +66,10 @@ DecodeError extractZebinSections(NEO::Elf::Elf<Elf::EI_CLASS_64> &elf, ZebinSect
case NEO::Elf::SHT_STRTAB:
// ignoring intentionally - section header names
continue;
case NEO::Elf::SHT_REL:
case NEO::Elf::SHT_RELA:
// ignoring intentionally - rel/rela sections handled by Elf decoder
continue;
case NEO::Elf::SHT_ZEBIN_GTPIN_INFO:
// ignoring intentionally - gtpin internal data
continue;
@@ -971,6 +976,8 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
return extractError;
}
dst.decodedElf = elf;
if (false == zebinSections.globalDataSections.empty()) {
dst.globalVariables.initData = zebinSections.globalDataSections[0]->data.begin();
dst.globalVariables.size = zebinSections.globalDataSections[0]->data.size();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 Intel Corporation
* Copyright (C) 2020-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -40,6 +40,7 @@ struct ProgramInfo {
std::unique_ptr<LinkerInput> linkerInput;
std::vector<KernelInfo *> kernelInfos;
Elf::Elf<Elf::EI_CLASS_64> decodedElf;
};
size_t getMaxInlineSlmNeeded(const ProgramInfo &programInfo);

View File

@@ -5,11 +5,13 @@
*
*/
#include "shared/source/device_binary_format/elf/zebin_elf.h"
#include "shared/source/helpers/ptr_math.h"
#include "shared/source/memory_manager/graphics_allocation.h"
#include "shared/source/program/program_initialization.h"
#include "shared/test/unit_test/helpers/debug_manager_state_restore.h"
#include "shared/test/unit_test/helpers/default_hw_info.h"
#include "shared/test/unit_test/mocks/mock_elf.h"
#include "shared/test/unit_test/mocks/mock_graphics_allocation.h"
#include "opencl/test/unit_test/mocks/mock_cl_device.h"
@@ -264,6 +266,603 @@ TEST(LinkerInputTests, whenDataRelocationsAreAddedThenProperTraitsAreSet) {
EXPECT_TRUE(linkerInput.isValid());
}
TEST(LinkerInputTests, WhenGettingSegmentForSectionNameThenCorrectSegmentIsReturned) {
auto segmentConst = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::dataConst.str());
auto segmentGlobalConst = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::dataGlobalConst.str());
auto segmentGlobal = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::dataGlobal.str());
auto segmentInstructions = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::textPrefix.str());
auto segmentInstructions2 = NEO::LinkerInput::getSegmentForSection(".text.abc");
EXPECT_EQ(NEO::SegmentType::GlobalConstants, segmentConst);
EXPECT_EQ(NEO::SegmentType::GlobalConstants, segmentGlobalConst);
EXPECT_EQ(NEO::SegmentType::GlobalVariables, segmentGlobal);
EXPECT_EQ(NEO::SegmentType::Instructions, segmentInstructions);
EXPECT_EQ(NEO::SegmentType::Instructions, segmentInstructions2);
}
TEST(LinkerInputTests, WhenGettingSegmentForUnknownSectionNameThenUnknownSegmentIsReturned) {
auto segment = NEO::LinkerInput::getSegmentForSection("Not_a_valid_section_name");
EXPECT_EQ(NEO::SegmentType::Unknown, segment);
}
TEST(LinkerInputTests, WhenAddingElfTextRelocationForSegmentIndexThenInstructionSegmentForRelocationAndProperTraitsAreSet) {
NEO::LinkerInput linkerInput = {};
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfInstructionSegments);
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalConstantsBuffer);
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalVariablesBuffer);
NEO::LinkerInput::RelocationInfo relocInfo;
relocInfo.offset = 7u;
relocInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
relocInfo.symbolName = "test";
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
linkerInput.addElfTextSegmentRelocation(relocInfo, 5);
ASSERT_EQ(0u, linkerInput.getDataRelocations().size());
ASSERT_EQ(6u, linkerInput.getRelocationsInInstructionSegments().size());
auto relocs = linkerInput.getRelocationsInInstructionSegments()[5];
ASSERT_EQ(1u, relocs.size());
EXPECT_EQ(NEO::SegmentType::Instructions, relocs[0].relocationSegment);
EXPECT_EQ(NEO::SegmentType::Unknown, relocs[0].symbolSegment);
EXPECT_EQ(std::string("test"), relocs[0].symbolName);
EXPECT_EQ(7u, relocs[0].offset);
EXPECT_TRUE(linkerInput.getTraits().requiresPatchingOfInstructionSegments);
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalConstantsBuffer);
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalVariablesBuffer);
EXPECT_TRUE(linkerInput.isValid());
}
TEST(LinkerInputTests, WhenAddingTwoElfTextRelocationForSingleSegmentIndexThenBothRelocationsAreAddedForTheSameSegment) {
NEO::LinkerInput linkerInput = {};
NEO::LinkerInput::RelocationInfo relocInfo;
relocInfo.offset = 7u;
relocInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
relocInfo.symbolName = "test";
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
linkerInput.addElfTextSegmentRelocation(relocInfo, 0);
ASSERT_EQ(1u, linkerInput.getRelocationsInInstructionSegments().size());
auto &relocs = linkerInput.getRelocationsInInstructionSegments()[0];
EXPECT_EQ(1u, relocs.size());
relocInfo.offset = 24u;
linkerInput.addElfTextSegmentRelocation(relocInfo, 0);
EXPECT_EQ(2u, relocs.size());
EXPECT_TRUE(linkerInput.getTraits().requiresPatchingOfInstructionSegments);
}
TEST(LinkerInputTests, WhenDecodingElfTextRelocationsThenCorrectRelocationsAreAdded) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.const";
sectionNames[2] = ".text.hello";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 1;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 0;
elf64.relocations.emplace_back(reloc);
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc2;
reloc2.offset = 32;
reloc2.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_32);
reloc2.symbolName = "symbol2";
reloc2.symbolSectionIndex = 1;
reloc2.symbolTableIndex = 0;
reloc2.targetSectionIndex = 2;
elf64.relocations.emplace_back(reloc2);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
nameToKernelId["hello"] = 1;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getRelocationsInInstructionSegments();
ASSERT_EQ(2u, relocations.size());
auto &segment0Relocs = relocations[0];
ASSERT_EQ(1u, segment0Relocs.size());
EXPECT_EQ(64u, segment0Relocs[0].offset);
EXPECT_EQ(NEO::SegmentType::Instructions, segment0Relocs[0].relocationSegment);
EXPECT_EQ("symbol1", segment0Relocs[0].symbolName);
EXPECT_EQ(NEO::SegmentType::Unknown, segment0Relocs[0].symbolSegment);
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, segment0Relocs[0].type);
auto &segment1Relocs = relocations[1];
ASSERT_EQ(1u, segment1Relocs.size());
EXPECT_EQ(32u, segment1Relocs[0].offset);
EXPECT_EQ(NEO::SegmentType::Instructions, segment1Relocs[0].relocationSegment);
EXPECT_EQ("symbol2", segment1Relocs[0].symbolName);
EXPECT_EQ(NEO::SegmentType::Unknown, segment1Relocs[0].symbolSegment);
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::AddressLow, segment1Relocs[0].type);
}
TEST(LinkerInputTests, GivenNoKernelNameToIdWhenDecodingElfTextRelocationsThenNoRelocationIsAdded) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.const";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 1;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 0;
elf64.relocations.emplace_back(reloc);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["wrong_name"] = 0;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getRelocationsInInstructionSegments();
ASSERT_EQ(0u, relocations.size());
}
TEST(LinkerInputTests, GivenInvalidTextSectionNameWhenDecodingElfTextRelocationsThenNoRelocationIsAdded) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".invalid.abc";
sectionNames[1] = ".data.const";
sectionNames[2] = ".text.hello";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 1;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 0;
elf64.relocations.emplace_back(reloc);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
nameToKernelId["hello"] = 1;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getRelocationsInInstructionSegments();
ASSERT_EQ(0u, relocations.size());
}
TEST(LinkerInputTests, GivenInvalidRelocationTypeWhenDecodingElfTextRelocationsThenUnknownTypeIsSet) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.const";
sectionNames[2] = ".text.hello";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = 0xffffffff; // invalid type
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 1;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 0;
elf64.relocations.emplace_back(reloc);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
nameToKernelId["hello"] = 1;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getRelocationsInInstructionSegments();
ASSERT_EQ(1u, relocations.size());
ASSERT_EQ(1u, relocations[0].size());
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Unknown, relocations[0][0].type);
}
TEST(LinkerInputTests, WhenDecodingElfGlobalDataRelocationsThenCorrectRelocationsAreAdded) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.global";
sectionNames[2] = ".data.const";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 1;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 1;
elf64.relocations.emplace_back(reloc);
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc2;
reloc2.offset = 32;
reloc2.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc2.symbolName = "symbol2";
reloc2.symbolSectionIndex = 2;
reloc2.symbolTableIndex = 0;
reloc2.targetSectionIndex = 1;
elf64.relocations.emplace_back(reloc2);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getDataRelocations();
ASSERT_EQ(2u, relocations.size());
EXPECT_EQ(64u, relocations[0].offset);
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocations[0].relocationSegment);
EXPECT_EQ("symbol1", relocations[0].symbolName);
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocations[0].symbolSegment);
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocations[0].type);
EXPECT_EQ(32u, relocations[1].offset);
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocations[1].relocationSegment);
EXPECT_EQ("symbol2", relocations[1].symbolName);
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocations[1].symbolSegment);
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocations[1].type);
}
TEST(LinkerInputTests, WhenDecodingElfConstantDataRelocationsThenCorrectRelocationsAreAdded) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.global";
sectionNames[2] = ".data.const";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 1;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 2;
elf64.relocations.emplace_back(reloc);
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc2;
reloc2.offset = 32;
reloc2.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc2.symbolName = "symbol2";
reloc2.symbolSectionIndex = 2;
reloc2.symbolTableIndex = 0;
reloc2.targetSectionIndex = 2;
elf64.relocations.emplace_back(reloc2);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getDataRelocations();
ASSERT_EQ(2u, relocations.size());
EXPECT_EQ(64u, relocations[0].offset);
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocations[0].relocationSegment);
EXPECT_EQ("symbol1", relocations[0].symbolName);
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocations[0].symbolSegment);
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocations[0].type);
EXPECT_EQ(32u, relocations[1].offset);
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocations[1].relocationSegment);
EXPECT_EQ("symbol2", relocations[1].symbolName);
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocations[1].symbolSegment);
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocations[1].type);
}
TEST(LinkerInputTests, GivenUnsupportedDataSegmentWhenDecodingElfDataRelocationThenNoRelocationsAreAdded) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data";
sectionNames[2] = ".data.const";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 2;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 1;
elf64.relocations.emplace_back(reloc);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getDataRelocations();
ASSERT_EQ(0u, relocations.size());
}
TEST(LinkerInputTests, GivenUnsupportedSymbolSegmentWhenDecodingElfDataRelocationThenNoRelocationsAreAddedAndDebugBreakIsCalled) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data";
sectionNames[2] = ".data.const";
elf64.setupSecionNames(std::move(sectionNames));
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc;
reloc.offset = 64;
reloc.relocType = static_cast<uint32_t>(Elf::RELOCATION_X8664_TYPE::R_X8664_64);
reloc.symbolName = "symbol1";
reloc.symbolSectionIndex = 1;
reloc.symbolTableIndex = 0;
reloc.targetSectionIndex = 2;
elf64.relocations.emplace_back(reloc);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto relocations = linkerInput.getDataRelocations();
ASSERT_EQ(0u, relocations.size());
}
TEST(LinkerInputTests, GivenGlobalAndLocalElfSymbolsWhenDecodingThenOnlyGlobalSymbolsAreAdded) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.const";
sectionNames[2] = ".text.hello";
elf64.setupSecionNames(std::move(sectionNames));
elf64.overrideSymbolName = true;
NEO::Elf::ElfSymbolEntry<NEO::Elf::EI_CLASS_64> symbol;
symbol.info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_OBJECT | NEO::Elf::SYMBOL_TABLE_BIND::STB_GLOBAL << 4;
symbol.name = 0;
symbol.other = 0;
symbol.shndx = 1;
symbol.size = 8;
symbol.value = 0x1234000;
NEO::Elf::ElfSymbolEntry<NEO::Elf::EI_CLASS_64> symbol2;
symbol2.info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_FUNC | NEO::Elf::SYMBOL_TABLE_BIND::STB_GLOBAL << 4;
symbol2.name = 8;
symbol2.other = 0;
symbol2.shndx = 0;
symbol2.size = 16;
symbol2.value = 0x5000;
NEO::Elf::ElfSymbolEntry<NEO::Elf::EI_CLASS_64> symbol3;
symbol3.info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_FUNC | NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL << 4;
symbol3.name = 16;
symbol3.other = 0;
symbol3.shndx = 0;
symbol3.size = 8;
symbol3.value = 0;
elf64.symbolTable.emplace_back(symbol);
elf64.symbolTable.emplace_back(symbol2);
elf64.symbolTable.emplace_back(symbol3);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
nameToKernelId["hello"] = 1;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto symbols = linkerInput.getSymbols();
ASSERT_EQ(2u, symbols.size());
EXPECT_EQ(0x1234000u, symbols[std::to_string(symbol.name)].offset);
EXPECT_EQ(NEO::SegmentType::GlobalConstants, symbols[std::to_string(symbol.name)].segment);
EXPECT_EQ(8u, symbols[std::to_string(symbol.name)].size);
EXPECT_EQ(0x5000u, symbols[std::to_string(symbol2.name)].offset);
EXPECT_EQ(NEO::SegmentType::Instructions, symbols[std::to_string(symbol2.name)].segment);
EXPECT_EQ(16u, symbols[std::to_string(symbol2.name)].size);
EXPECT_FALSE(linkerInput.getTraits().exportsGlobalVariables);
EXPECT_TRUE(linkerInput.getTraits().exportsGlobalConstants);
EXPECT_TRUE(linkerInput.getTraits().exportsFunctions);
}
TEST(LinkerInputTests, GivenGlobalFunctionsInTwoSegementsWhenDecodingThenUnrecoverableIsCalled) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.const";
sectionNames[2] = ".text.hello";
elf64.setupSecionNames(std::move(sectionNames));
elf64.overrideSymbolName = true;
NEO::Elf::ElfSymbolEntry<NEO::Elf::EI_CLASS_64> symbol;
symbol.info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_FUNC | NEO::Elf::SYMBOL_TABLE_BIND::STB_GLOBAL << 4;
symbol.name = 0;
symbol.other = 0;
symbol.shndx = 0;
symbol.size = 8;
symbol.value = 0x1234000;
NEO::Elf::ElfSymbolEntry<NEO::Elf::EI_CLASS_64> symbol2;
symbol2.info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_FUNC | NEO::Elf::SYMBOL_TABLE_BIND::STB_GLOBAL << 4;
symbol2.name = 8;
symbol2.other = 0;
symbol2.shndx = 2;
symbol2.size = 16;
symbol2.value = 0x5000;
elf64.symbolTable.emplace_back(symbol);
elf64.symbolTable.emplace_back(symbol2);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
nameToKernelId["hello"] = 1;
EXPECT_THROW(linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId), std::exception);
auto symbols = linkerInput.getSymbols();
ASSERT_EQ(2u, symbols.size());
EXPECT_EQ(0, linkerInput.getExportedFunctionsSegmentId());
}
TEST(LinkerInputTests, GivenNoKernelNameToIdWhenDecodingGlobalFunctionThenExportedFunctionsSegmentIsNotSet) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
elf64.setupSecionNames(std::move(sectionNames));
elf64.overrideSymbolName = true;
NEO::Elf::ElfSymbolEntry<NEO::Elf::EI_CLASS_64> symbol;
symbol.info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_FUNC | NEO::Elf::SYMBOL_TABLE_BIND::STB_GLOBAL << 4;
symbol.name = 0;
symbol.other = 0;
symbol.shndx = 0;
symbol.size = 8;
symbol.value = 0x1234000;
elf64.symbolTable.emplace_back(symbol);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["hello"] = 1;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto symbols = linkerInput.getSymbols();
ASSERT_EQ(1u, symbols.size());
EXPECT_EQ(-1, linkerInput.getExportedFunctionsSegmentId());
}
TEST(LinkerInputTests, GivenGlobalElfSymbolOfNoTypeWhenDecodingThenSymbolWithUnknownSegmentIsAddedAndDebugBreakCalled) {
NEO::LinkerInput linkerInput = {};
NEO::Elf::ElfFileHeader<NEO::Elf::EI_CLASS_64> header;
MockElf<NEO::Elf::EI_CLASS_64> elf64;
elf64.elfFileHeader = &header;
std::unordered_map<uint32_t, std::string> sectionNames;
sectionNames[0] = ".text.abc";
sectionNames[1] = ".data.const";
sectionNames[2] = ".text.hello";
elf64.setupSecionNames(std::move(sectionNames));
elf64.overrideSymbolName = true;
NEO::Elf::ElfSymbolEntry<NEO::Elf::EI_CLASS_64> symbol;
symbol.info = NEO::Elf::SYMBOL_TABLE_TYPE::STT_NOTYPE | NEO::Elf::SYMBOL_TABLE_BIND::STB_GLOBAL << 4;
symbol.name = 0;
symbol.other = 0;
symbol.shndx = 1;
symbol.size = 8;
symbol.value = 0x1234000;
elf64.symbolTable.emplace_back(symbol);
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
nameToKernelId["abc"] = 0;
nameToKernelId["hello"] = 1;
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
auto symbols = linkerInput.getSymbols();
ASSERT_EQ(1u, symbols.size());
EXPECT_EQ(SegmentType::Unknown, symbols.begin()->second.segment);
EXPECT_FALSE(linkerInput.getTraits().exportsGlobalVariables);
EXPECT_FALSE(linkerInput.getTraits().exportsGlobalConstants);
EXPECT_FALSE(linkerInput.getTraits().exportsFunctions);
}
TEST(LinkerTests, givenEmptyLinkerInputThenLinkerOutputIsEmpty) {
NEO::LinkerInput linkerInput;
NEO::Linker linker(linkerInput);

View File

@@ -89,6 +89,10 @@ TEST(ExtractZebinSections, GivenKnownSectionsThenCapturesThemProperly) {
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_ZEINFO, NEO::Elf::SectionsNamesZebin::zeInfo, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_SPIRV, NEO::Elf::SectionsNamesZebin::spv, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_ZEBIN_GTPIN_INFO, NEO::Elf::SectionsNamesZebin::gtpinInfo, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_REL, NEO::Elf::SpecialSectionNames::relPrefix.str() + "someKernel", std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_RELA, NEO::Elf::SpecialSectionNames::relaPrefix.str() + "someKernel", std::string{});
auto encodedElf = elfEncoder.encode();
std::string elfDecodeErrors;
std::string elfDecodeWarnings;

View File

@@ -15,6 +15,29 @@ struct MockElf : public NEO::Elf::Elf<NumBits> {
using BaseClass::relocations;
using BaseClass::symbolTable;
std::string getSectionName(uint32_t id) const override {
if (overrideSectionNames) {
return sectionNames.find(id)->second;
}
return NEO::Elf::Elf<NumBits>::getSectionName(id);
}
std::string getSymbolName(uint32_t nameOffset) const override {
if (overrideSymbolName) {
return std::to_string(nameOffset);
}
return NEO::Elf::Elf<NumBits>::getSymbolName(nameOffset);
}
void setupSecionNames(std::unordered_map<uint32_t, std::string> map) {
sectionNames = map;
overrideSectionNames = true;
}
bool overrideSectionNames = false;
std::unordered_map<uint32_t, std::string> sectionNames;
bool overrideSymbolName = false;
};
template <NEO::Elf::ELF_IDENTIFIER_CLASS NumBits = NEO::Elf::EI_CLASS_64>