mirror of
https://github.com/intel/compute-runtime.git
synced 2025-09-10 12:53:42 +08:00
Add support for data relocations using symbols
Support symbols for data relocations. Remove unused symbolSegment field in RelocationInfo. Related-To: NEO-5833 Signed-off-by: Krystian Chmielewski <krystian.chmielewski@intel.com>
This commit is contained in:

committed by
Compute-Runtime-Automation

parent
ab7e0013e1
commit
0b9e87e35f
@ -459,11 +459,19 @@ TEST_F(ProgramDataTest, GivenProgramWith32bitPointerOptWhenProgramScopeConstantB
|
||||
EXPECT_EQ(nullptr, prog->getConstantSurface(pContext->getDevice(0)->getRootDeviceIndex()));
|
||||
ProgramInfo programInfo;
|
||||
programInfo.prepareLinkerInputStorage();
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo;
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocInfo.offset = 0U;
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
relocInfo.symbolName = "GlobalConstantPointer";
|
||||
|
||||
NEO::SymbolInfo symbol = {};
|
||||
symbol.offset = 0U;
|
||||
symbol.size = 8U;
|
||||
symbol.segment = NEO::SegmentType::GlobalConstants;
|
||||
|
||||
programInfo.linkerInput->addSymbol("GlobalConstantPointer", symbol);
|
||||
programInfo.linkerInput->addDataRelocationInfo(relocInfo);
|
||||
programInfo.linkerInput->setPointerSize(LinkerInput::Traits::PointerSize::Ptr32bit);
|
||||
|
||||
@ -499,10 +507,17 @@ TEST_F(ProgramDataTest, GivenProgramWith32bitPointerOptWhenProgramScopeGlobalPoi
|
||||
ProgramInfo programInfo;
|
||||
programInfo.prepareLinkerInputStorage();
|
||||
NEO::LinkerInput::RelocationInfo relocInfo;
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.offset = 0U;
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.symbolName = "GlobalVariablePointer";
|
||||
|
||||
NEO::SymbolInfo symbol = {};
|
||||
symbol.offset = 0U;
|
||||
symbol.size = 8U;
|
||||
symbol.segment = NEO::SegmentType::GlobalVariables;
|
||||
|
||||
programInfo.linkerInput->addSymbol("GlobalVariablePointer", symbol);
|
||||
programInfo.linkerInput->addDataRelocationInfo(relocInfo);
|
||||
programInfo.linkerInput->setPointerSize(LinkerInput::Traits::PointerSize::Ptr32bit);
|
||||
|
||||
|
@ -118,7 +118,6 @@ bool LinkerInput::decodeRelocationTable(const void *data, uint32_t numEntries, u
|
||||
RelocationInfo relocInfo{};
|
||||
relocInfo.offset = relocEntryIt->r_offset;
|
||||
relocInfo.symbolName = relocEntryIt->r_symbol;
|
||||
relocInfo.symbolSegment = SegmentType::Unknown;
|
||||
relocInfo.relocationSegment = SegmentType::Instructions;
|
||||
switch (relocEntryIt->r_type) {
|
||||
default:
|
||||
@ -145,7 +144,6 @@ bool LinkerInput::decodeRelocationTable(const void *data, uint32_t numEntries, u
|
||||
|
||||
void LinkerInput::addDataRelocationInfo(const RelocationInfo &relocationInfo) {
|
||||
DEBUG_BREAK_IF((relocationInfo.relocationSegment != SegmentType::GlobalConstants) && (relocationInfo.relocationSegment != SegmentType::GlobalVariables));
|
||||
DEBUG_BREAK_IF(relocationInfo.type == LinkerInput::RelocationInfo::Type::AddressHigh);
|
||||
this->traits.requiresPatchingOfGlobalVariablesBuffer |= (relocationInfo.relocationSegment == SegmentType::GlobalVariables);
|
||||
this->traits.requiresPatchingOfGlobalConstantsBuffer |= (relocationInfo.relocationSegment == SegmentType::GlobalConstants);
|
||||
this->dataRelocations.push_back(relocationInfo);
|
||||
@ -161,7 +159,6 @@ void LinkerInput::addElfTextSegmentRelocation(RelocationInfo relocationInfo, uin
|
||||
|
||||
auto &outRelocInfo = relocations[instructionsSegmentId];
|
||||
|
||||
relocationInfo.symbolSegment = SegmentType::Unknown;
|
||||
relocationInfo.relocationSegment = SegmentType::Instructions;
|
||||
|
||||
outRelocInfo.push_back(std::move(relocationInfo));
|
||||
@ -198,7 +195,6 @@ void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64>
|
||||
} else if (nameRef.startsWith(NEO::Elf::SpecialSectionNames::data.data())) {
|
||||
auto symbolSectionName = elf.getSectionName(reloc.symbolSectionIndex);
|
||||
auto symbolSegment = getSegmentForSection(symbolSectionName);
|
||||
relocationInfo.symbolSegment = symbolSegment;
|
||||
auto relocationSegment = getSegmentForSection(nameRef);
|
||||
if (symbolSegment != NEO::SegmentType::Unknown &&
|
||||
(relocationSegment == NEO::SegmentType::GlobalConstants || relocationSegment == NEO::SegmentType::GlobalVariables)) {
|
||||
@ -331,45 +327,27 @@ void Linker::patchDataSegments(const SegmentInfo &globalVariablesSegInfo, const
|
||||
GraphicsAllocation *globalVariablesSeg, GraphicsAllocation *globalConstantsSeg,
|
||||
std::vector<UnresolvedExternal> &outUnresolvedExternals, Device *pDevice,
|
||||
const void *constantsInitData, const void *variablesInitData) {
|
||||
if (false == (data.getTraits().requiresPatchingOfGlobalConstantsBuffer || data.getTraits().requiresPatchingOfGlobalVariablesBuffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &relocation : data.getDataRelocations()) {
|
||||
const SegmentInfo *src = nullptr;
|
||||
auto symbolIt = relocatedSymbols.find(relocation.symbolName);
|
||||
if (symbolIt == relocatedSymbols.end()) {
|
||||
outUnresolvedExternals.push_back(UnresolvedExternal{relocation});
|
||||
continue;
|
||||
}
|
||||
uint64_t srcGpuAddressAs64Bit = symbolIt->second.gpuAddress;
|
||||
|
||||
GraphicsAllocation *dst = nullptr;
|
||||
const void *initData = nullptr;
|
||||
switch (relocation.symbolSegment) {
|
||||
default:
|
||||
outUnresolvedExternals.push_back(UnresolvedExternal{relocation});
|
||||
continue;
|
||||
case SegmentType::GlobalVariables:
|
||||
src = &globalVariablesSegInfo;
|
||||
break;
|
||||
case SegmentType::GlobalConstants:
|
||||
src = &globalConstantsSegInfo;
|
||||
break;
|
||||
}
|
||||
switch (relocation.relocationSegment) {
|
||||
default:
|
||||
outUnresolvedExternals.push_back(UnresolvedExternal{relocation});
|
||||
continue;
|
||||
case SegmentType::GlobalVariables:
|
||||
if (SegmentType::GlobalVariables == relocation.relocationSegment) {
|
||||
dst = globalVariablesSeg;
|
||||
initData = variablesInitData;
|
||||
break;
|
||||
case SegmentType::GlobalConstants:
|
||||
} else if (SegmentType::GlobalConstants == relocation.relocationSegment) {
|
||||
dst = globalConstantsSeg;
|
||||
initData = constantsInitData;
|
||||
break;
|
||||
}
|
||||
|
||||
UNRECOVERABLE_IF(nullptr == dst);
|
||||
|
||||
if (RelocationInfo::Type::AddressHigh == relocation.type) {
|
||||
} else {
|
||||
outUnresolvedExternals.push_back(UnresolvedExternal{relocation});
|
||||
continue;
|
||||
}
|
||||
UNRECOVERABLE_IF(nullptr == dst);
|
||||
|
||||
auto relocType = (LinkerInput::Traits::PointerSize::Ptr32bit == data.getTraits().pointerSize) ? RelocationInfo::Type::AddressLow : relocation.type;
|
||||
bool invalidOffset = relocation.offset + addressSizeInBytes(relocType) > dst->getUnderlyingBufferSize();
|
||||
@ -379,20 +357,21 @@ void Linker::patchDataSegments(const SegmentInfo &globalVariablesSegInfo, const
|
||||
continue;
|
||||
}
|
||||
|
||||
UNRECOVERABLE_IF((RelocationInfo::Type::Address != relocType) && (RelocationInfo::Type::AddressLow != relocType));
|
||||
uint64_t gpuAddressAs64bit = src->gpuAddress;
|
||||
uint32_t patchSize = (RelocationInfo::Type::AddressLow == relocType) ? 4 : sizeof(uintptr_t);
|
||||
uint64_t incrementValue = (RelocationInfo::Type::AddressLow == relocType)
|
||||
? static_cast<uint32_t>(gpuAddressAs64bit & 0xffffffff)
|
||||
: gpuAddressAs64bit;
|
||||
|
||||
if (initData) {
|
||||
if (patchSize == sizeof(uint64_t)) {
|
||||
patchIncrement<uint64_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
|
||||
} else {
|
||||
UNRECOVERABLE_IF(patchSize != sizeof(uint32_t));
|
||||
patchIncrement<uint32_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
|
||||
}
|
||||
uint64_t incrementValue = 0U;
|
||||
switch (relocType) {
|
||||
default:
|
||||
UNRECOVERABLE_IF(RelocationInfo::Type::Address != relocType);
|
||||
incrementValue = srcGpuAddressAs64Bit;
|
||||
patchIncrement<uint64_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
|
||||
break;
|
||||
case RelocationInfo::Type::AddressLow:
|
||||
incrementValue = srcGpuAddressAs64Bit & 0xffffffff;
|
||||
patchIncrement<uint32_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
|
||||
break;
|
||||
case RelocationInfo::Type::AddressHigh:
|
||||
incrementValue = (srcGpuAddressAs64Bit >> 32) & 0xffffffff;
|
||||
patchIncrement<uint32_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -416,7 +395,7 @@ std::string constructLinkerErrorMessage(const Linker::UnresolvedExternals &unres
|
||||
errorStream << " (aka " << instructionsSegmentsNames[unresExtern.instructionsSegmentId] << ")";
|
||||
}
|
||||
} else {
|
||||
errorStream << " address of segment #" << asString(unresExtern.unresolvedRelocation.symbolSegment) << " at offset " << unresExtern.unresolvedRelocation.offset
|
||||
errorStream << " symbol #" << unresExtern.unresolvedRelocation.symbolName << " at offset " << unresExtern.unresolvedRelocation.offset
|
||||
<< " in data segment #" << asString(unresExtern.unresolvedRelocation.relocationSegment);
|
||||
}
|
||||
errorStream << "\n";
|
||||
|
@ -88,7 +88,6 @@ struct LinkerInput {
|
||||
uint64_t offset = std::numeric_limits<uint64_t>::max();
|
||||
Type type = Type::Unknown;
|
||||
SegmentType relocationSegment = SegmentType::Unknown;
|
||||
SegmentType symbolSegment = SegmentType::Unknown;
|
||||
};
|
||||
using SectionNameToSegmentIdMap = std::unordered_map<std::string, uint32_t>;
|
||||
using Relocations = std::vector<RelocationInfo>;
|
||||
@ -119,6 +118,10 @@ struct LinkerInput {
|
||||
return symbols;
|
||||
}
|
||||
|
||||
void addSymbol(const std::string &symbolName, const SymbolInfo &symbolInfo) {
|
||||
symbols.emplace(std::make_pair(symbolName, symbolInfo));
|
||||
}
|
||||
|
||||
const RelocationsPerInstSegment &getRelocationsInInstructionSegments() const {
|
||||
return relocations;
|
||||
}
|
||||
|
@ -63,22 +63,29 @@ void populateProgramInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPa
|
||||
dst.globalVariables.initData = NEO::PatchTokenBinary::getInlineData(surface);
|
||||
}
|
||||
|
||||
constexpr ConstStringRef globalConstantsSymbolName = "globalConstants";
|
||||
constexpr ConstStringRef globalVariablesSymbolName = "globalVariables";
|
||||
|
||||
if (false == (src.programScopeTokens.constantPointer.empty() && src.programScopeTokens.globalPointer.empty() && (src.programScopeTokens.symbolTable == nullptr))) {
|
||||
UNRECOVERABLE_IF((src.header->GPUPointerSizeInBytes != 4) && (src.header->GPUPointerSizeInBytes != 8));
|
||||
dst.prepareLinkerInputStorage();
|
||||
dst.linkerInput->setPointerSize((src.header->GPUPointerSizeInBytes == 4) ? LinkerInput::Traits::PointerSize::Ptr32bit : LinkerInput::Traits::PointerSize::Ptr64bit);
|
||||
|
||||
dst.linkerInput->addSymbol(globalConstantsSymbolName.data(), {0U, 8U, SegmentType::GlobalConstants});
|
||||
dst.linkerInput->addSymbol(globalVariablesSymbolName.data(), {0U, 8U, SegmentType::GlobalVariables});
|
||||
}
|
||||
|
||||
for (const auto &globalConstantPointerToken : src.programScopeTokens.constantPointer) {
|
||||
NEO::LinkerInput::RelocationInfo relocInfo = {};
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocInfo.offset = readMisalignedUint64(&globalConstantPointerToken->ConstantPointerOffset);
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
if (globalConstantPointerToken->BufferType != iOpenCL::PROGRAM_SCOPE_CONSTANT_BUFFER) {
|
||||
UNRECOVERABLE_IF(globalConstantPointerToken->BufferType != iOpenCL::PROGRAM_SCOPE_GLOBAL_BUFFER);
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
}
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
relocInfo.symbolName = std::string(globalConstantsSymbolName);
|
||||
if (iOpenCL::PROGRAM_SCOPE_CONSTANT_BUFFER != globalConstantPointerToken->BufferType) {
|
||||
UNRECOVERABLE_IF(iOpenCL::PROGRAM_SCOPE_GLOBAL_BUFFER != globalConstantPointerToken->BufferType);
|
||||
relocInfo.symbolName = std::string(globalVariablesSymbolName);
|
||||
}
|
||||
|
||||
dst.linkerInput->addDataRelocationInfo(relocInfo);
|
||||
}
|
||||
|
||||
@ -86,12 +93,13 @@ void populateProgramInfo(ProgramInfo &dst, const PatchTokenBinary::ProgramFromPa
|
||||
NEO::LinkerInput::RelocationInfo relocInfo = {};
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.offset = readMisalignedUint64(&globalVariablePointerToken->GlobalPointerOffset);
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
if (globalVariablePointerToken->BufferType != iOpenCL::PROGRAM_SCOPE_GLOBAL_BUFFER) {
|
||||
UNRECOVERABLE_IF(globalVariablePointerToken->BufferType != iOpenCL::PROGRAM_SCOPE_CONSTANT_BUFFER);
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
}
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
relocInfo.symbolName = std::string(globalVariablesSymbolName);
|
||||
if (iOpenCL::PROGRAM_SCOPE_GLOBAL_BUFFER != globalVariablePointerToken->BufferType) {
|
||||
UNRECOVERABLE_IF(iOpenCL::PROGRAM_SCOPE_CONSTANT_BUFFER != globalVariablePointerToken->BufferType);
|
||||
relocInfo.symbolName = std::string(globalConstantsSymbolName);
|
||||
}
|
||||
|
||||
dst.linkerInput->addDataRelocationInfo(relocInfo);
|
||||
}
|
||||
|
||||
|
@ -268,14 +268,12 @@ TEST(LinkerInputTests, whenDataRelocationsAreAddedThenProperTraitsAreSet) {
|
||||
relocInfo.offset = 7U;
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocInfo.symbolName = "aaa";
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.addDataRelocationInfo(relocInfo);
|
||||
ASSERT_EQ(1U, linkerInput.getDataRelocations().size());
|
||||
EXPECT_EQ(relocInfo.offset, linkerInput.getDataRelocations()[0].offset);
|
||||
EXPECT_EQ(relocInfo.relocationSegment, linkerInput.getDataRelocations()[0].relocationSegment);
|
||||
EXPECT_EQ(relocInfo.symbolName, linkerInput.getDataRelocations()[0].symbolName);
|
||||
EXPECT_EQ(relocInfo.symbolSegment, linkerInput.getDataRelocations()[0].symbolSegment);
|
||||
EXPECT_EQ(relocInfo.type, linkerInput.getDataRelocations()[0].type);
|
||||
EXPECT_TRUE(linkerInput.getTraits().requiresPatchingOfGlobalConstantsBuffer);
|
||||
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalVariablesBuffer);
|
||||
@ -285,7 +283,6 @@ TEST(LinkerInputTests, whenDataRelocationsAreAddedThenProperTraitsAreSet) {
|
||||
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalConstantsBuffer);
|
||||
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalVariablesBuffer);
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
linkerInput.addDataRelocationInfo(relocInfo);
|
||||
ASSERT_EQ(1U, linkerInput.getDataRelocations().size());
|
||||
EXPECT_FALSE(linkerInput.getTraits().requiresPatchingOfGlobalConstantsBuffer);
|
||||
@ -324,7 +321,6 @@ TEST(LinkerInputTests, WhenAddingElfTextRelocationForSegmentIndexThenInstruction
|
||||
relocInfo.symbolName = "test";
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
|
||||
linkerInput.addElfTextSegmentRelocation(relocInfo, 5);
|
||||
|
||||
@ -336,7 +332,6 @@ TEST(LinkerInputTests, WhenAddingElfTextRelocationForSegmentIndexThenInstruction
|
||||
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);
|
||||
|
||||
@ -354,7 +349,6 @@ TEST(LinkerInputTests, WhenAddingTwoElfTextRelocationForSingleSegmentIndexThenBo
|
||||
relocInfo.symbolName = "test";
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
relocInfo.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocInfo.symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
|
||||
linkerInput.addElfTextSegmentRelocation(relocInfo, 0);
|
||||
|
||||
@ -418,7 +412,6 @@ TEST(LinkerInputTests, WhenDecodingElfTextRelocationsThenCorrectRelocationsAreAd
|
||||
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];
|
||||
@ -427,7 +420,6 @@ TEST(LinkerInputTests, WhenDecodingElfTextRelocationsThenCorrectRelocationsAreAd
|
||||
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);
|
||||
}
|
||||
|
||||
@ -658,19 +650,16 @@ TEST(LinkerInputTests, WhenDecodingElfGlobalDataRelocationsThenCorrectRelocation
|
||||
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);
|
||||
|
||||
EXPECT_EQ(0u, relocations[2].offset);
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocations[2].relocationSegment);
|
||||
EXPECT_EQ("symbol3", relocations[2].symbolName);
|
||||
EXPECT_EQ(NEO::SegmentType::Instructions, relocations[2].symbolSegment);
|
||||
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocations[2].type);
|
||||
}
|
||||
|
||||
@ -719,13 +708,11 @@ TEST(LinkerInputTests, WhenDecodingElfConstantDataRelocationsThenCorrectRelocati
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1297,462 +1284,304 @@ TEST(LinkerTests, givenUnknownSymbolTypeWhenPatchingInstructionsThenRelocationFa
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenInvalidSourceSegmentWhenPatchingDataSegmentsThenLinkerFails) {
|
||||
TEST(LinkerTests, givenValidSymbolsAndRelocationsWhenPatchingDataSegmentsThenTheyAreProperlyPatched) {
|
||||
uint64_t initGlobalConstantData[3];
|
||||
initGlobalConstantData[0] = 0x10; // var1 address will be added here
|
||||
initGlobalConstantData[1] = 0x1234; // <- const1
|
||||
initGlobalConstantData[2] = 0x0; // fun1 address will be added here
|
||||
|
||||
uint64_t initGlobalVariablesData[3];
|
||||
initGlobalVariablesData[0] = 0x20; // const1 address will be added here
|
||||
initGlobalVariablesData[1] = 0x4321; // <- var1
|
||||
initGlobalVariablesData[2] = 0x0; // fun2 address will be added here
|
||||
|
||||
uint64_t exportedFunctionsInit[2];
|
||||
exportedFunctionsInit[0] = 0x12; // <- fun1
|
||||
exportedFunctionsInit[1] = 0x34; // <- fun2
|
||||
|
||||
NEO::MockGraphicsAllocation globalConstantsPatchableSegment{initGlobalConstantData, sizeof(initGlobalConstantData)};
|
||||
NEO::MockGraphicsAllocation globalVariablesPatchableSegment{initGlobalVariablesData, sizeof(initGlobalVariablesData)};
|
||||
NEO::MockGraphicsAllocation exportedFunctions{&exportedFunctionsInit, sizeof(exportedFunctionsInit)};
|
||||
|
||||
NEO::Linker::SegmentInfo globalConstantsSegmentInfo, globalVariablesSegmentInfo, exportedFunctionsSegmentInfo;
|
||||
globalConstantsSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalConstantsPatchableSegment.getUnderlyingBuffer());
|
||||
globalConstantsSegmentInfo.segmentSize = globalConstantsPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
globalVariablesSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalVariablesPatchableSegment.getUnderlyingBuffer());
|
||||
globalVariablesSegmentInfo.segmentSize = globalVariablesPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
exportedFunctionsSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(exportedFunctions.getUnderlyingBuffer());
|
||||
exportedFunctionsSegmentInfo.segmentSize = exportedFunctions.getUnderlyingBufferSize();
|
||||
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::Linker linker(linkerInput);
|
||||
auto &fun1 = linkerInput.symbols["fun1"];
|
||||
fun1.segment = SegmentType::Instructions;
|
||||
fun1.offset = 0U;
|
||||
fun1.size = 8U;
|
||||
|
||||
NEO::Linker::SegmentInfo emptySegmentInfo;
|
||||
NEO::MockGraphicsAllocation emptyPatchableSegment;
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
auto &fun2 = linkerInput.symbols["fun2"];
|
||||
fun2.segment = SegmentType::Instructions;
|
||||
fun2.offset = 8U;
|
||||
fun2.size = 8U;
|
||||
|
||||
std::vector<char> nonEmptypatchableSegmentData;
|
||||
nonEmptypatchableSegmentData.resize(64, 8U);
|
||||
NEO::MockGraphicsAllocation nonEmptypatchableSegment{nonEmptypatchableSegmentData.data(), nonEmptypatchableSegmentData.size()};
|
||||
auto &var1 = linkerInput.symbols["var1"];
|
||||
var1.segment = SegmentType::GlobalVariables;
|
||||
var1.offset = 8U;
|
||||
var1.size = 8U;
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo;
|
||||
relocInfo.offset = 0U;
|
||||
relocInfo.symbolName = "aaa";
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocInfo);
|
||||
auto &const1 = linkerInput.symbols["const1"];
|
||||
const1.segment = SegmentType::GlobalConstants;
|
||||
const1.offset = 8U;
|
||||
const1.size = 8U;
|
||||
|
||||
/*
|
||||
Segments:
|
||||
Const:
|
||||
0x00 0x10
|
||||
0x08 0x1234 <- const1
|
||||
0x10 0x0
|
||||
|
||||
Var:
|
||||
0x00 0x20
|
||||
0x08 0x4321 <- var1
|
||||
0x10 0x0
|
||||
|
||||
ExportFun:
|
||||
0x00 0x12 <- fun1
|
||||
0x08 0x34 <- fun2
|
||||
|
||||
After patching:
|
||||
Const:
|
||||
0x00 0x10 + &var1
|
||||
0x08 0x1234
|
||||
0x10 0x0 + &fun1
|
||||
|
||||
Var:
|
||||
0x00 0x20 + &const1
|
||||
0x08 0x4321
|
||||
0x10 0x0 + &fun2
|
||||
*/
|
||||
|
||||
// var1 -> Constant
|
||||
// *(uint64_t*)(constant + 0) += *(uint64_t*)(var + 8)
|
||||
{
|
||||
linkerInput.traits.requiresPatchingOfGlobalVariablesBuffer = true;
|
||||
linkerInput.traits.requiresPatchingOfGlobalConstantsBuffer = false;
|
||||
linkerInput.dataRelocations[0].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::Unknown;
|
||||
auto linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
unresolvedExternals.clear();
|
||||
linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
NEO::LinkerInput::RelocationInfo relocation;
|
||||
relocation.offset = 0U;
|
||||
relocation.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocation.symbolName = "var1";
|
||||
relocation.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocation);
|
||||
}
|
||||
|
||||
// const1 -> Var
|
||||
// *(uint64_t*)(var + 0) += *(uint64_t*)(const + 8)
|
||||
{
|
||||
linkerInput.traits.requiresPatchingOfGlobalVariablesBuffer = false;
|
||||
linkerInput.traits.requiresPatchingOfGlobalConstantsBuffer = true;
|
||||
linkerInput.dataRelocations[0].relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::Unknown;
|
||||
unresolvedExternals.clear();
|
||||
auto linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&emptyPatchableSegment, &nonEmptypatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
NEO::LinkerInput::RelocationInfo relocation;
|
||||
relocation.offset = 0U;
|
||||
relocation.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocation.symbolName = "const1";
|
||||
relocation.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocation);
|
||||
}
|
||||
// fun1 -> Const
|
||||
// *(uint64_t*)(const + 0x10) += *(uint64_t*)(export_fun + 0)
|
||||
{
|
||||
NEO::LinkerInput::RelocationInfo relocation;
|
||||
relocation.offset = 0x10U;
|
||||
relocation.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocation.symbolName = "fun1";
|
||||
relocation.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocation);
|
||||
}
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
if (LinkerInput::Traits::PointerSize::Ptr64bit == linkerInput.getTraits().pointerSize) {
|
||||
// fun2_LO -> var
|
||||
// *(uint32_t*)(var + 0x10) += *(uint32_t*)((export_fun + 8) & 0xffffffff)
|
||||
{
|
||||
NEO::LinkerInput::RelocationInfo relocation;
|
||||
relocation.offset = 0x10U;
|
||||
relocation.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocation.symbolName = "fun2";
|
||||
relocation.type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
|
||||
linkerInput.dataRelocations.push_back(relocation);
|
||||
}
|
||||
// fun2_HI -> var
|
||||
// *(uint32_t*)(var + 0x14) += *(uint32_t*)(((export_fun + 8) >> 32) & 0xffffffff)
|
||||
{
|
||||
NEO::LinkerInput::RelocationInfo relocation;
|
||||
relocation.offset = 0x14U;
|
||||
relocation.relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocation.symbolName = "fun2";
|
||||
relocation.type = NEO::LinkerInput::RelocationInfo::Type::AddressHigh;
|
||||
linkerInput.dataRelocations.push_back(relocation);
|
||||
}
|
||||
}
|
||||
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
unresolvedExternals.clear();
|
||||
linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&emptyPatchableSegment, &nonEmptypatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
NEO::Linker linker(linkerInput);
|
||||
auto device = std::unique_ptr<NEO::MockDevice>(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(NEO::defaultHwInfo.get()));
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, exportedFunctionsSegmentInfo,
|
||||
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
|
||||
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
auto constantsAddr = globalConstantsSegmentInfo.gpuAddress;
|
||||
auto varsAddr = globalVariablesSegmentInfo.gpuAddress;
|
||||
auto exportFunAddr = exportedFunctionsSegmentInfo.gpuAddress;
|
||||
|
||||
auto const1Addr = constantsAddr + const1.offset;
|
||||
auto var1Addr = varsAddr + var1.offset;
|
||||
auto fun1Addr = exportFunAddr + fun1.offset;
|
||||
auto fun2Addr = exportFunAddr + fun2.offset;
|
||||
|
||||
if (LinkerInput::Traits::PointerSize::Ptr64bit == linkerInput.getTraits().pointerSize) {
|
||||
EXPECT_EQ(0x10U + var1Addr, *(uint64_t *)(constantsAddr));
|
||||
EXPECT_EQ(0x1234U, *(uint64_t *)(constantsAddr + 0x8));
|
||||
EXPECT_EQ(fun1Addr, *(uint64_t *)(constantsAddr + 0x10));
|
||||
|
||||
EXPECT_EQ(0x20U + const1Addr, *(uint64_t *)(varsAddr));
|
||||
EXPECT_EQ(0x4321U, *(uint64_t *)(varsAddr + 0x8));
|
||||
EXPECT_EQ(fun2Addr, *(uint64_t *)(varsAddr + 0x10));
|
||||
} else if (LinkerInput::Traits::PointerSize::Ptr32bit == linkerInput.getTraits().pointerSize) {
|
||||
EXPECT_EQ(0x10U + var1Addr, *(uint32_t *)(constantsAddr));
|
||||
EXPECT_EQ(0x1234U, *(uint32_t *)(constantsAddr + 0x8));
|
||||
EXPECT_EQ(fun1Addr, *(uint32_t *)(constantsAddr + 0x10));
|
||||
|
||||
EXPECT_EQ(0x20U + const1Addr, *(uint32_t *)(varsAddr));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenUnknownRelocationSegmentWhenPatchingDataSegmentsThenLinkerFails) {
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::Linker linker(linkerInput);
|
||||
TEST(LinkerTests, givenInvalidSymbolWhenPatchingDataSegmentsThenRelocationIsUnresolved) {
|
||||
uint64_t initGlobalConstantData[3] = {};
|
||||
uint64_t initGlobalVariablesData[3] = {};
|
||||
|
||||
NEO::Linker::SegmentInfo emptySegmentInfo;
|
||||
NEO::MockGraphicsAllocation emptyPatchableSegment;
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
|
||||
std::vector<char> nonEmptypatchableSegmentData;
|
||||
nonEmptypatchableSegmentData.resize(64, 8U);
|
||||
NEO::MockGraphicsAllocation nonEmptypatchableSegment{nonEmptypatchableSegmentData.data(), nonEmptypatchableSegmentData.size()};
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo;
|
||||
relocInfo.offset = 0U;
|
||||
relocInfo.symbolName = "aaa";
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocInfo);
|
||||
linkerInput.dataRelocations[0].relocationSegment = NEO::SegmentType::Unknown;
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.traits.requiresPatchingOfGlobalVariablesBuffer = true;
|
||||
|
||||
auto linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
|
||||
linkerInput.dataRelocations[0].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
unresolvedExternals.clear();
|
||||
linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenRelocationTypeWithHighPartOfAddressWhenPatchingDataSegmentsThenLinkerFails) {
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::Linker linker(linkerInput);
|
||||
|
||||
NEO::Linker::SegmentInfo emptySegmentInfo;
|
||||
NEO::MockGraphicsAllocation emptyPatchableSegment;
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
|
||||
std::vector<char> nonEmptypatchableSegmentData;
|
||||
nonEmptypatchableSegmentData.resize(64, 8U);
|
||||
NEO::MockGraphicsAllocation nonEmptypatchableSegment{nonEmptypatchableSegmentData.data(), nonEmptypatchableSegmentData.size()};
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo;
|
||||
relocInfo.offset = 0U;
|
||||
relocInfo.symbolName = "aaa";
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::AddressHigh;
|
||||
linkerInput.dataRelocations.push_back(relocInfo);
|
||||
linkerInput.dataRelocations[0].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.traits.requiresPatchingOfGlobalVariablesBuffer = true;
|
||||
|
||||
auto linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
|
||||
linkerInput.dataRelocations[0].type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
|
||||
unresolvedExternals.clear();
|
||||
linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenValidSymbolsAndRelocationsThenDataSegmentsAreProperlyPatched) {
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::Linker linker(linkerInput);
|
||||
|
||||
std::vector<char> globalConstantsSegmentData;
|
||||
globalConstantsSegmentData.resize(128, 7U);
|
||||
|
||||
std::vector<char> globalVariablesSegmentData;
|
||||
globalVariablesSegmentData.resize(256, 13U);
|
||||
NEO::MockGraphicsAllocation globalConstantsPatchableSegment{initGlobalConstantData, sizeof(initGlobalConstantData)};
|
||||
NEO::MockGraphicsAllocation globalVariablesPatchableSegment{initGlobalVariablesData, sizeof(initGlobalVariablesData)};
|
||||
|
||||
NEO::Linker::SegmentInfo globalConstantsSegmentInfo, globalVariablesSegmentInfo;
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
globalConstantsSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalConstantsPatchableSegment.getUnderlyingBuffer());
|
||||
globalConstantsSegmentInfo.segmentSize = globalConstantsPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
globalConstantsSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalConstantsSegmentData.data());
|
||||
globalConstantsSegmentInfo.segmentSize = globalConstantsSegmentData.size();
|
||||
NEO::MockGraphicsAllocation globalConstantsPatchableSegment{globalConstantsSegmentData.data(), globalConstantsSegmentData.size()};
|
||||
globalVariablesSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalVariablesPatchableSegment.getUnderlyingBuffer());
|
||||
globalVariablesSegmentInfo.segmentSize = globalVariablesPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
globalVariablesSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalVariablesSegmentData.data());
|
||||
globalVariablesSegmentInfo.segmentSize = globalVariablesSegmentData.size();
|
||||
NEO::MockGraphicsAllocation globalVariablesPatchableSegment{globalVariablesSegmentData.data(), globalVariablesSegmentData.size()};
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo[5];
|
||||
// GlobalVar -> GlobalVar
|
||||
relocationInfo[0].offset = 8U;
|
||||
relocationInfo[0].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[0].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalConst -> GlobalVar
|
||||
relocationInfo[1].offset = 24U;
|
||||
relocationInfo[1].relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[1].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[1].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalConst -> GlobalConst
|
||||
relocationInfo[2].offset = 40U;
|
||||
relocationInfo[2].relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[2].symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[2].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalVar -> GlobalConst
|
||||
relocationInfo[3].offset = 56U;
|
||||
relocationInfo[3].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[3].symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[3].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalVar Low -> GlobalVar
|
||||
relocationInfo[4].offset = 72;
|
||||
relocationInfo[4].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[4].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[4].type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
|
||||
|
||||
uint32_t initValue = 0;
|
||||
for (const auto &reloc : relocationInfo) {
|
||||
linkerInput.addDataRelocationInfo(reloc);
|
||||
void *dstRaw = (reloc.relocationSegment == NEO::SegmentType::GlobalVariables)
|
||||
? globalVariablesPatchableSegment.getUnderlyingBuffer()
|
||||
: globalConstantsPatchableSegment.getUnderlyingBuffer();
|
||||
if (reloc.type == NEO::LinkerInput::RelocationInfo::Type::Address) {
|
||||
*reinterpret_cast<uintptr_t *>(ptrOffset(dstRaw, static_cast<size_t>(reloc.offset))) = initValue * 4; // relocations to global data are currently based on patchIncrement, simulate init data
|
||||
} else {
|
||||
*reinterpret_cast<uint32_t *>(ptrOffset(dstRaw, static_cast<size_t>(reloc.offset))) = initValue * 4; // relocations to global data are currently based on patchIncrement, simulate init data
|
||||
}
|
||||
++initValue;
|
||||
}
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo;
|
||||
relocationInfo.offset = 0U;
|
||||
relocationInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo.symbolName = "symbol";
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocationInfo);
|
||||
|
||||
NEO::Linker linker(linkerInput);
|
||||
auto device = std::unique_ptr<NEO::MockDevice>(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(NEO::defaultHwInfo.get()));
|
||||
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, {},
|
||||
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
|
||||
unresolvedExternals, device.get(), globalConstantsPatchableSegment.getUnderlyingBuffer(),
|
||||
globalVariablesPatchableSegment.getUnderlyingBuffer());
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
EXPECT_EQ(7U, *reinterpret_cast<uint8_t *>(globalConstantsPatchableSegment.getUnderlyingBuffer()));
|
||||
EXPECT_EQ(13U, *reinterpret_cast<uint8_t *>(globalVariablesPatchableSegment.getUnderlyingBuffer()));
|
||||
|
||||
initValue = 0;
|
||||
for (const auto &reloc : relocationInfo) {
|
||||
void *srcRaw = (reloc.symbolSegment == NEO::SegmentType::GlobalVariables)
|
||||
? globalVariablesPatchableSegment.getUnderlyingBuffer()
|
||||
: globalConstantsPatchableSegment.getUnderlyingBuffer();
|
||||
void *dstRaw = (reloc.relocationSegment == NEO::SegmentType::GlobalVariables)
|
||||
? globalVariablesPatchableSegment.getUnderlyingBuffer()
|
||||
: globalConstantsPatchableSegment.getUnderlyingBuffer();
|
||||
uint8_t *src = reinterpret_cast<uint8_t *>(srcRaw);
|
||||
uint8_t *dst = reinterpret_cast<uint8_t *>(dstRaw);
|
||||
|
||||
// make sure no buffer underflow occured
|
||||
EXPECT_EQ(dst[0], dst[reloc.offset - 1]);
|
||||
|
||||
// check patch-incremented value
|
||||
if (reloc.type == NEO::LinkerInput::RelocationInfo::Type::Address) {
|
||||
// make sure no buffer overflow occured
|
||||
EXPECT_EQ(dst[0], dst[reloc.offset + sizeof(uintptr_t)]);
|
||||
EXPECT_EQ(reinterpret_cast<uintptr_t>(src) + initValue * 4, *reinterpret_cast<uintptr_t *>(dst + reloc.offset)) << initValue;
|
||||
} else {
|
||||
// make sure no buffer overflow occured
|
||||
EXPECT_EQ(dst[0], dst[reloc.offset + sizeof(uint32_t)]);
|
||||
EXPECT_EQ(static_cast<uint32_t>(reinterpret_cast<uintptr_t>(src)) + initValue * 4, *reinterpret_cast<uint32_t *>(dst + reloc.offset)) << initValue;
|
||||
}
|
||||
++initValue;
|
||||
}
|
||||
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenValidSymbolsAndRelocationsWhenPatchin32bitBinaryThenDataSegmentsAreProperlyPatchedWithLowerPartOfTheAddress) {
|
||||
TEST(LinkerTests, givenInvalidRelocationOffsetWhenPatchingDataSegmentsThenRelocationIsUnresolved) {
|
||||
uint64_t initGlobalConstantData[3] = {};
|
||||
uint64_t initGlobalVariablesData[3] = {};
|
||||
|
||||
NEO::MockGraphicsAllocation globalConstantsPatchableSegment{initGlobalConstantData, sizeof(initGlobalConstantData)};
|
||||
NEO::MockGraphicsAllocation globalVariablesPatchableSegment{initGlobalVariablesData, sizeof(initGlobalVariablesData)};
|
||||
|
||||
NEO::Linker::SegmentInfo globalConstantsSegmentInfo, globalVariablesSegmentInfo;
|
||||
globalConstantsSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalConstantsPatchableSegment.getUnderlyingBuffer());
|
||||
globalConstantsSegmentInfo.segmentSize = globalConstantsPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
globalVariablesSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalVariablesPatchableSegment.getUnderlyingBuffer());
|
||||
globalVariablesSegmentInfo.segmentSize = globalVariablesPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
auto &symbol = linkerInput.symbols["symbol"];
|
||||
symbol.segment = SegmentType::GlobalVariables;
|
||||
symbol.offset = 0U;
|
||||
symbol.size = 8U;
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo;
|
||||
relocationInfo.offset = globalConstantsSegmentInfo.segmentSize + 1U;
|
||||
relocationInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo.symbolName = "symbol";
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocationInfo);
|
||||
|
||||
NEO::Linker linker(linkerInput);
|
||||
auto device = std::unique_ptr<NEO::MockDevice>(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(NEO::defaultHwInfo.get()));
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, {},
|
||||
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
|
||||
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenInvalidRelocationSegmentWhenPatchingDataSegmentsThenRelocationIsUnresolved) {
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
auto &symbol = linkerInput.symbols["symbol"];
|
||||
symbol.segment = SegmentType::GlobalVariables;
|
||||
symbol.offset = 0U;
|
||||
symbol.size = 8U;
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo;
|
||||
relocationInfo.offset = 0U;
|
||||
relocationInfo.relocationSegment = NEO::SegmentType::Unknown;
|
||||
relocationInfo.symbolName = "symbol";
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocationInfo);
|
||||
NEO::Linker linker(linkerInput);
|
||||
auto device = std::unique_ptr<NEO::MockDevice>(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(NEO::defaultHwInfo.get()));
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
auto linkResult = linker.link({}, {}, {},
|
||||
nullptr, nullptr, {},
|
||||
unresolvedExternals, device.get(), nullptr, nullptr);
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, given32BitBinaryWithValidSymbolsAndRelocationsWhenPatchingDataSegmentsThenTreatAddressRelocationAsLowerHalfOfTheAddress) {
|
||||
uint64_t initGlobalConstantData[3] = {};
|
||||
uint64_t initGlobalVariablesData[3] = {};
|
||||
|
||||
NEO::MockGraphicsAllocation globalConstantsPatchableSegment{initGlobalConstantData, sizeof(initGlobalConstantData)};
|
||||
NEO::MockGraphicsAllocation globalVariablesPatchableSegment{initGlobalVariablesData, sizeof(initGlobalVariablesData)};
|
||||
|
||||
NEO::Linker::SegmentInfo globalConstantsSegmentInfo, globalVariablesSegmentInfo;
|
||||
globalConstantsSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalConstantsPatchableSegment.getUnderlyingBuffer());
|
||||
globalConstantsSegmentInfo.segmentSize = globalConstantsPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
globalVariablesSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalVariablesPatchableSegment.getUnderlyingBuffer());
|
||||
globalVariablesSegmentInfo.segmentSize = globalVariablesPatchableSegment.getUnderlyingBufferSize();
|
||||
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
linkerInput.setPointerSize(NEO::LinkerInput::Traits::PointerSize::Ptr32bit);
|
||||
auto &fun1 = linkerInput.symbols["symbol"];
|
||||
fun1.segment = SegmentType::GlobalVariables;
|
||||
fun1.offset = 0U;
|
||||
fun1.size = 8U;
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo;
|
||||
relocationInfo.offset = 0U;
|
||||
relocationInfo.relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo.symbolName = "symbol";
|
||||
relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocationInfo);
|
||||
|
||||
NEO::Linker linker(linkerInput);
|
||||
|
||||
std::vector<char> globalConstantsSegmentData;
|
||||
globalConstantsSegmentData.resize(128, 7U);
|
||||
|
||||
std::vector<char> globalVariablesSegmentData;
|
||||
globalVariablesSegmentData.resize(256, 13U);
|
||||
|
||||
NEO::Linker::SegmentInfo globalConstantsSegmentInfo, globalVariablesSegmentInfo;
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
|
||||
globalConstantsSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalConstantsSegmentData.data());
|
||||
globalConstantsSegmentInfo.segmentSize = globalConstantsSegmentData.size();
|
||||
NEO::MockGraphicsAllocation globalConstantsPatchableSegment{globalConstantsSegmentData.data(), globalConstantsSegmentData.size()};
|
||||
|
||||
globalVariablesSegmentInfo.gpuAddress = reinterpret_cast<uintptr_t>(globalVariablesSegmentData.data());
|
||||
globalVariablesSegmentInfo.segmentSize = globalVariablesSegmentData.size();
|
||||
NEO::MockGraphicsAllocation globalVariablesPatchableSegment{globalVariablesSegmentData.data(), globalVariablesSegmentData.size()};
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocationInfo[5];
|
||||
// GlobalVar -> GlobalVar
|
||||
relocationInfo[0].offset = 8U;
|
||||
relocationInfo[0].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[0].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalConst -> GlobalVar
|
||||
relocationInfo[1].offset = 24U;
|
||||
relocationInfo[1].relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[1].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[1].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalConst -> GlobalConst
|
||||
relocationInfo[2].offset = 40U;
|
||||
relocationInfo[2].relocationSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[2].symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[2].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalVar -> GlobalConst
|
||||
relocationInfo[3].offset = 56U;
|
||||
relocationInfo[3].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[3].symbolSegment = NEO::SegmentType::GlobalConstants;
|
||||
relocationInfo[3].type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
|
||||
// GlobalVar Low -> GlobalVar
|
||||
relocationInfo[4].offset = 72;
|
||||
relocationInfo[4].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[4].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
relocationInfo[4].type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
|
||||
|
||||
uint32_t initValue = 0;
|
||||
for (const auto &reloc : relocationInfo) {
|
||||
linkerInput.addDataRelocationInfo(reloc);
|
||||
void *dstRaw = (reloc.relocationSegment == NEO::SegmentType::GlobalVariables)
|
||||
? globalVariablesPatchableSegment.getUnderlyingBuffer()
|
||||
: globalConstantsPatchableSegment.getUnderlyingBuffer();
|
||||
*reinterpret_cast<uint32_t *>(ptrOffset(dstRaw, static_cast<size_t>(reloc.offset))) = initValue * 4; // relocations to global data are currently based on patchIncrement, simulate init data
|
||||
++initValue;
|
||||
}
|
||||
|
||||
auto device = std::unique_ptr<NEO::MockDevice>(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(NEO::defaultHwInfo.get()));
|
||||
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, {},
|
||||
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
|
||||
unresolvedExternals, device.get(), globalConstantsPatchableSegment.getUnderlyingBuffer(),
|
||||
globalVariablesPatchableSegment.getUnderlyingBuffer());
|
||||
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
EXPECT_EQ(7U, *reinterpret_cast<uint8_t *>(globalConstantsPatchableSegment.getUnderlyingBuffer()));
|
||||
EXPECT_EQ(13U, *reinterpret_cast<uint8_t *>(globalVariablesPatchableSegment.getUnderlyingBuffer()));
|
||||
|
||||
initValue = 0;
|
||||
for (const auto &reloc : relocationInfo) {
|
||||
void *srcRaw = (reloc.symbolSegment == NEO::SegmentType::GlobalVariables)
|
||||
? globalVariablesPatchableSegment.getUnderlyingBuffer()
|
||||
: globalConstantsPatchableSegment.getUnderlyingBuffer();
|
||||
void *dstRaw = (reloc.relocationSegment == NEO::SegmentType::GlobalVariables)
|
||||
? globalVariablesPatchableSegment.getUnderlyingBuffer()
|
||||
: globalConstantsPatchableSegment.getUnderlyingBuffer();
|
||||
uint8_t *src = reinterpret_cast<uint8_t *>(srcRaw);
|
||||
uint8_t *dst = reinterpret_cast<uint8_t *>(dstRaw);
|
||||
|
||||
// make sure no buffer under/overflow occured
|
||||
EXPECT_EQ(dst[0], dst[reloc.offset - 1]);
|
||||
EXPECT_EQ(dst[0], dst[reloc.offset + sizeof(uint32_t)]);
|
||||
|
||||
// check patch-incremented value
|
||||
EXPECT_EQ(static_cast<uint32_t>(reinterpret_cast<uintptr_t>(src)) + initValue * 4, *reinterpret_cast<uint32_t *>(dst + reloc.offset)) << initValue;
|
||||
++initValue;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenInvalidRelocationOffsetThenPatchingOfDataSegmentsFails) {
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::Linker linker(linkerInput);
|
||||
|
||||
NEO::Linker::SegmentInfo emptySegmentInfo;
|
||||
NEO::MockGraphicsAllocation emptyPatchableSegment;
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
|
||||
std::vector<char> nonEmptypatchableSegmentData;
|
||||
nonEmptypatchableSegmentData.resize(64, 8U);
|
||||
NEO::MockGraphicsAllocation nonEmptypatchableSegment{nonEmptypatchableSegmentData.data(), nonEmptypatchableSegmentData.size()};
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo;
|
||||
relocInfo.offset = 64U;
|
||||
relocInfo.symbolName = "aaa";
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocInfo);
|
||||
linkerInput.dataRelocations[0].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.traits.requiresPatchingOfGlobalVariablesBuffer = true;
|
||||
|
||||
auto linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
|
||||
EXPECT_EQ(1U, unresolvedExternals.size());
|
||||
|
||||
linkerInput.dataRelocations[0].offset = 32;
|
||||
unresolvedExternals.clear();
|
||||
linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
&nonEmptypatchableSegment, &emptyPatchableSegment, {},
|
||||
unresolvedExternals, nullptr, nullptr, nullptr);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, GivenAllocationInLocalMemoryWhichRequiresBlitterWhenPatchingDataSegmentsAllocationThenBlitterIsUsed) {
|
||||
DebugManagerStateRestore restorer;
|
||||
|
||||
auto hwInfo = *defaultHwInfo;
|
||||
hwInfo.capabilityTable.blitterOperationsSupported = true;
|
||||
|
||||
uint32_t blitsCounter = 0;
|
||||
uint32_t expectedBlitsCount = 0;
|
||||
auto mockBlitMemoryToAllocation = [&blitsCounter](const Device &device, GraphicsAllocation *memory, size_t offset, const void *hostPtr,
|
||||
Vec3<size_t> size) -> BlitOperationResult {
|
||||
blitsCounter++;
|
||||
return BlitOperationResult::Success;
|
||||
};
|
||||
VariableBackup<BlitHelperFunctions::BlitMemoryToAllocationFunc> blitMemoryToAllocationFuncBackup{
|
||||
&BlitHelperFunctions::blitMemoryToAllocation, mockBlitMemoryToAllocation};
|
||||
|
||||
LocalMemoryAccessMode localMemoryAccessModes[] = {
|
||||
LocalMemoryAccessMode::Default,
|
||||
LocalMemoryAccessMode::CpuAccessAllowed,
|
||||
LocalMemoryAccessMode::CpuAccessDisallowed};
|
||||
|
||||
std::vector<uint8_t> initData;
|
||||
initData.resize(64, 7U);
|
||||
|
||||
for (auto localMemoryAccessMode : localMemoryAccessModes) {
|
||||
DebugManager.flags.ForceLocalMemoryAccessMode.set(static_cast<int32_t>(localMemoryAccessMode));
|
||||
for (auto isLocalMemorySupported : ::testing::Bool()) {
|
||||
DebugManager.flags.EnableLocalMemory.set(isLocalMemorySupported);
|
||||
auto pDevice = std::unique_ptr<MockDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(&hwInfo));
|
||||
MockSVMAllocsManager svmAllocsManager(pDevice->getMemoryManager(), false);
|
||||
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::Linker linker(linkerInput);
|
||||
|
||||
NEO::Linker::SegmentInfo emptySegmentInfo;
|
||||
NEO::Linker::UnresolvedExternals unresolvedExternals;
|
||||
|
||||
std::vector<char> nonEmptypatchableSegmentData;
|
||||
nonEmptypatchableSegmentData.resize(64, 8U);
|
||||
auto pNonEmptypatchableSegment = allocateGlobalsSurface(&svmAllocsManager, *pDevice, nonEmptypatchableSegmentData.size(),
|
||||
true /* constant */, nullptr /* linker input */,
|
||||
nonEmptypatchableSegmentData.data());
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo;
|
||||
relocInfo.offset = 0U;
|
||||
relocInfo.symbolName = "aaa";
|
||||
relocInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
|
||||
linkerInput.dataRelocations.push_back(relocInfo);
|
||||
linkerInput.dataRelocations[0].relocationSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.dataRelocations[0].symbolSegment = NEO::SegmentType::GlobalVariables;
|
||||
linkerInput.traits.requiresPatchingOfGlobalVariablesBuffer = true;
|
||||
uint64_t initData = 0x1234;
|
||||
|
||||
auto linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
pNonEmptypatchableSegment, pNonEmptypatchableSegment, {},
|
||||
unresolvedExternals, pDevice.get(), &initData, &initData);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
|
||||
linkerInput.dataRelocations[0].type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
|
||||
linkResult = linker.link(emptySegmentInfo, emptySegmentInfo, emptySegmentInfo,
|
||||
pNonEmptypatchableSegment, pNonEmptypatchableSegment, {},
|
||||
unresolvedExternals, pDevice.get(), &initData, &initData);
|
||||
|
||||
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
|
||||
EXPECT_EQ(0U, unresolvedExternals.size());
|
||||
|
||||
if (pNonEmptypatchableSegment->isAllocatedInLocalMemoryPool() &&
|
||||
(localMemoryAccessMode == LocalMemoryAccessMode::CpuAccessDisallowed)) {
|
||||
auto blitsOnAllocationInitialization = 1;
|
||||
auto blitsOnPatchingDataSegments = 2;
|
||||
expectedBlitsCount += blitsOnAllocationInitialization + blitsOnPatchingDataSegments;
|
||||
}
|
||||
EXPECT_EQ(expectedBlitsCount, blitsCounter);
|
||||
pDevice->getMemoryManager()->freeGraphicsMemory(pNonEmptypatchableSegment);
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(globalVariablesSegmentInfo.gpuAddress & 0xffffffff, *(uint32_t *)(globalConstantsSegmentInfo.gpuAddress));
|
||||
EXPECT_EQ(0U, *(uint32_t *)(globalConstantsSegmentInfo.gpuAddress + 4));
|
||||
}
|
||||
|
||||
TEST(LinkerErrorMessageTests, whenListOfUnresolvedExternalsIsEmptyThenErrorTypeDefaultsToInternalError) {
|
||||
|
@ -73,9 +73,10 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalConstants
|
||||
ASSERT_EQ(1U, programInfo.linkerInput->getDataRelocations().size());
|
||||
auto relocation = programInfo.linkerInput->getDataRelocations()[0];
|
||||
EXPECT_EQ(programFromTokens.programScopeTokens.constantPointer[0]->ConstantPointerOffset, relocation.offset);
|
||||
EXPECT_TRUE(relocation.symbolName.empty());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocation.relocationSegment);
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocation.symbolSegment);
|
||||
auto symbol = programInfo.linkerInput->getSymbols().find(relocation.symbolName);
|
||||
EXPECT_TRUE(symbol != programInfo.linkerInput->getSymbols().end());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalConstants, symbol->second.segment);
|
||||
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocation.type);
|
||||
}
|
||||
|
||||
@ -88,9 +89,10 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresGlobalVariables
|
||||
ASSERT_EQ(1U, programInfo.linkerInput->getDataRelocations().size());
|
||||
auto relocation = programInfo.linkerInput->getDataRelocations()[0];
|
||||
EXPECT_EQ(NEO::readMisalignedUint64(&programFromTokens.programScopeTokens.globalPointer[0]->GlobalPointerOffset), relocation.offset);
|
||||
EXPECT_TRUE(relocation.symbolName.empty());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocation.relocationSegment);
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocation.symbolSegment);
|
||||
auto symbol = programInfo.linkerInput->getSymbols().find(relocation.symbolName);
|
||||
EXPECT_TRUE(symbol != programInfo.linkerInput->getSymbols().end());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalVariables, symbol->second.segment);
|
||||
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocation.type);
|
||||
}
|
||||
|
||||
@ -118,16 +120,19 @@ TEST(PopulateProgramInfoFromPatchtokensTests, WhenProgramRequiresMixedGlobalVarA
|
||||
|
||||
ASSERT_NE(nullptr, relocationGlobalConst);
|
||||
EXPECT_EQ(NEO::readMisalignedUint64(&programFromTokens.programScopeTokens.constantPointer[0]->ConstantPointerOffset), relocationGlobalConst->offset);
|
||||
EXPECT_TRUE(relocationGlobalConst->symbolName.empty());
|
||||
EXPECT_FALSE(relocationGlobalConst->symbolName.empty());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocationGlobalConst->relocationSegment);
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocationGlobalConst->symbolSegment);
|
||||
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocationGlobalConst->type);
|
||||
auto symbol1 = programInfo.linkerInput->getSymbols().find(relocationGlobalConst->symbolName);
|
||||
EXPECT_TRUE(symbol1 != programInfo.linkerInput->getSymbols().end());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalVariables, symbol1->second.segment);
|
||||
|
||||
ASSERT_NE(nullptr, relocationGlobalVar);
|
||||
EXPECT_EQ(NEO::readMisalignedUint64(&programFromTokens.programScopeTokens.globalPointer[0]->GlobalPointerOffset), relocationGlobalVar->offset);
|
||||
EXPECT_TRUE(relocationGlobalVar->symbolName.empty());
|
||||
EXPECT_FALSE(relocationGlobalVar->symbolName.empty());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalVariables, relocationGlobalVar->relocationSegment);
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalConstants, relocationGlobalVar->symbolSegment);
|
||||
auto symbol2 = programInfo.linkerInput->getSymbols().find(relocationGlobalVar->symbolName);
|
||||
EXPECT_TRUE(symbol2 != programInfo.linkerInput->getSymbols().end());
|
||||
EXPECT_EQ(NEO::SegmentType::GlobalConstants, symbol2->second.segment);
|
||||
EXPECT_EQ(NEO::LinkerInput::RelocationInfo::Type::Address, relocationGlobalVar->type);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user