fix: patch relocations byte-wise

there is no restriction for alignment of relocation offset

Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
Mateusz Jablonski 2025-05-12 12:22:23 +00:00 committed by Compute-Runtime-Automation
parent 4ab91eab1e
commit 6e20cbc05f
2 changed files with 104 additions and 10 deletions

View File

@ -402,17 +402,20 @@ void Linker::patchAddress(void *relocAddress, const uint64_t value, const Linker
switch (relocation.type) {
default:
UNRECOVERABLE_IF(RelocationInfo::Type::address != relocation.type);
*reinterpret_cast<uint64_t *>(relocAddress) = value;
break;
case RelocationInfo::Type::addressLow:
*reinterpret_cast<uint32_t *>(relocAddress) = static_cast<uint32_t>(value & 0xffffffff);
break;
case RelocationInfo::Type::addressHigh:
*reinterpret_cast<uint32_t *>(relocAddress) = static_cast<uint32_t>((value >> 32) & 0xffffffff);
break;
case RelocationInfo::Type::address16:
*reinterpret_cast<uint16_t *>(relocAddress) = static_cast<uint16_t>(value);
memcpy_s(relocAddress, sizeof(uint64_t), &value, sizeof(uint64_t));
break;
case RelocationInfo::Type::addressLow: {
uint32_t valueToPatch = static_cast<uint32_t>(value & 0xffffffff);
memcpy_s(relocAddress, sizeof(uint32_t), &valueToPatch, sizeof(uint32_t));
} break;
case RelocationInfo::Type::addressHigh: {
uint32_t valueToPatch = static_cast<uint32_t>((value >> 32) & 0xffffffff);
memcpy_s(relocAddress, sizeof(uint32_t), &valueToPatch, sizeof(uint32_t));
} break;
case RelocationInfo::Type::address16: {
uint16_t valueToPatch = static_cast<uint16_t>(value & 0xffff);
memcpy_s(relocAddress, sizeof(uint16_t), &valueToPatch, sizeof(uint16_t));
} break;
}
}

View File

@ -1329,6 +1329,97 @@ HWTEST_F(LinkerTests, givenValidStringSymbolsAndRelocationsWhenPatchingThenItIsP
EXPECT_EQ(static_cast<size_t>(strAddr), *reinterpret_cast<const size_t *>(patchAddr));
}
TEST_F(LinkerTests, givenValidStringSymbolsAndRelocationsWithWordMisalignedOffsetWhenPatchingThenItIsProperlyPatched) {
NEO::Linker::SegmentInfo stringSegment;
stringSegment.gpuAddress = 0x1234000000567800;
stringSegment.segmentSize = 0x20;
uint8_t instructionSegment[32] = {};
NEO::Linker::PatchableSegment seg0;
seg0.hostPointer = instructionSegment;
seg0.segmentSize = sizeof(instructionSegment);
NEO::Linker::PatchableSegments patchableInstructionSegments{seg0, seg0, seg0, seg0};
WhiteBox<NEO::LinkerInput> linkerInput;
SymbolInfo strSymbol;
strSymbol.segment = SegmentType::globalStrings;
strSymbol.offset = 0U;
strSymbol.size = 8U;
linkerInput.symbols.insert({".str8", strSymbol});
strSymbol.offset = 8U;
strSymbol.size = 4U;
linkerInput.symbols.insert({".str4H", strSymbol});
strSymbol.offset = 12U;
strSymbol.size = 4U;
linkerInput.symbols.insert({".str4L", strSymbol});
strSymbol.offset = 16U;
strSymbol.size = 2U;
linkerInput.symbols.insert({".str2", strSymbol});
NEO::LinkerInput::RelocationInfo relocation;
relocation.offset = 1U;
relocation.relocationSegment = NEO::SegmentType::instructions;
relocation.symbolName = ".str8";
relocation.type = NEO::LinkerInput::RelocationInfo::Type::address;
linkerInput.textRelocations.push_back({relocation});
relocation.offset = 9U;
relocation.relocationSegment = NEO::SegmentType::instructions;
relocation.symbolName = ".str4H";
relocation.type = NEO::LinkerInput::RelocationInfo::Type::addressHigh;
linkerInput.textRelocations.push_back({relocation});
relocation.offset = 13U;
relocation.relocationSegment = NEO::SegmentType::instructions;
relocation.symbolName = ".str4L";
relocation.type = NEO::LinkerInput::RelocationInfo::Type::addressLow;
linkerInput.textRelocations.push_back({relocation});
relocation.offset = 17U;
relocation.relocationSegment = NEO::SegmentType::instructions;
relocation.symbolName = ".str2";
relocation.type = NEO::LinkerInput::RelocationInfo::Type::address16;
linkerInput.textRelocations.push_back({relocation});
linkerInput.traits.requiresPatchingOfInstructionSegments = true;
NEO::Linker linker(linkerInput);
NEO::Linker::UnresolvedExternals unresolvedExternals;
NEO::Linker::KernelDescriptorsT kernelDescriptors;
NEO::Linker::ExternalFunctionsT externalFunctions;
auto linkResult = linker.link(
{}, {}, {}, stringSegment,
nullptr, nullptr, patchableInstructionSegments, unresolvedExternals,
pDevice, nullptr, 0, nullptr, 0, kernelDescriptors, externalFunctions);
EXPECT_EQ(NEO::LinkingStatus::linkedFully, linkResult);
EXPECT_EQ(0U, unresolvedExternals.size());
EXPECT_TRUE(linker.extractRelocatedSymbols().empty());
uint64_t str8Addr = static_cast<uint64_t>(stringSegment.gpuAddress);
uint32_t str4HAddr = static_cast<uint32_t>((stringSegment.gpuAddress + 8u) >> 32);
uint32_t str4LAddr = static_cast<uint32_t>((stringSegment.gpuAddress + 12u) & 0xffffffff);
uint16_t str2Addr = static_cast<uint16_t>((stringSegment.gpuAddress + 16u) & 0xffff);
EXPECT_NE(0u, str8Addr);
EXPECT_NE(0u, str4HAddr);
EXPECT_NE(0u, str4LAddr);
EXPECT_NE(0u, str2Addr);
auto patchAddrStr8 = ptrOffset(instructionSegment, 1u);
auto patchAddrStr4H = ptrOffset(instructionSegment, 9u);
auto patchAddrStr4L = ptrOffset(instructionSegment, 13u);
auto patchAddrStr2 = ptrOffset(instructionSegment, 17u);
EXPECT_EQ(0, memcmp(patchAddrStr8, &str8Addr, 8));
EXPECT_EQ(0, memcmp(patchAddrStr4H, &str4HAddr, 4));
EXPECT_EQ(0, memcmp(patchAddrStr4L, &str4LAddr, 4));
EXPECT_EQ(0, memcmp(patchAddrStr2, &str2Addr, 2));
}
HWTEST_F(LinkerTests, givenValidSymbolsAndRelocationsWhenPatchingDataSegmentsThenTheyAreProperlyPatched) {
uint64_t initGlobalConstantData[3];
initGlobalConstantData[0] = 0x10; // var1 address will be added here