mirror of
https://github.com/intel/compute-runtime.git
synced 2025-12-21 01:04:57 +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
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user