mirror of
https://github.com/intel/compute-runtime.git
synced 2025-12-21 01:04:57 +08:00
Handle relocations from zeBin
Related-To: NEO-5323 Signed-off-by: Mateusz Hoppe <mateusz.hoppe@intel.com>
This commit is contained in:
committed by
Compute-Runtime-Automation
parent
d19d8e0829
commit
5d2ea72db6
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user