Zebin: Use strings section for printf

Resolves: NEO-6143

Signed-off-by: Krystian Chmielewski <krystian.chmielewski@intel.com>
This commit is contained in:
Krystian Chmielewski
2021-11-02 15:29:09 +00:00
committed by Compute-Runtime-Automation
parent 5d1c3c98a4
commit 06eaef0352
14 changed files with 240 additions and 51 deletions

View File

@@ -635,6 +635,7 @@ bool ModuleImp::linkBinary() {
Linker::SegmentInfo globals;
Linker::SegmentInfo constants;
Linker::SegmentInfo exportedFunctions;
Linker::SegmentInfo strings;
GraphicsAllocation *globalsForPatching = translationUnit->globalVarBuffer;
GraphicsAllocation *constantsForPatching = translationUnit->globalConstBuffer;
if (globalsForPatching != nullptr) {
@@ -645,6 +646,10 @@ bool ModuleImp::linkBinary() {
constants.gpuAddress = static_cast<uintptr_t>(constantsForPatching->getGpuAddress());
constants.segmentSize = constantsForPatching->getUnderlyingBufferSize();
}
if (translationUnit->programInfo.globalStrings.initData != nullptr) {
strings.gpuAddress = reinterpret_cast<uintptr_t>(translationUnit->programInfo.globalStrings.initData);
strings.segmentSize = translationUnit->programInfo.globalStrings.size;
}
if (linkerInput->getExportedFunctionsSegmentId() >= 0) {
auto exportedFunctionHeapId = linkerInput->getExportedFunctionsSegmentId();
this->exportedFunctionsSurface = this->kernelImmDatas[exportedFunctionHeapId]->getIsaGraphicsAllocation();
@@ -663,7 +668,7 @@ bool ModuleImp::linkBinary() {
}
}
auto linkStatus = linker.link(globals, constants, exportedFunctions,
auto linkStatus = linker.link(globals, constants, exportedFunctions, strings,
globalsForPatching, constantsForPatching,
isaSegmentsForPatching, unresolvedExternalsInfo, this->device->getNEODevice(),
translationUnit->programInfo.globalConstants.initData,

View File

@@ -1859,6 +1859,42 @@ TEST_F(ModuleTests, whenCopyingPatchedSegmentsThenAllocationsAreSetWritableForTb
EXPECT_TRUE(allocation->isAubWritable(std::numeric_limits<uint32_t>::max()));
}
TEST_F(ModuleTests, givenConstDataStringSectionWhenLinkingModuleThenSegmentIsPatched) {
auto pModule = std::make_unique<Module>(device, nullptr, ModuleType::User);
char data[64]{};
auto kernelInfo = new KernelInfo();
kernelInfo->heapInfo.KernelHeapSize = 64;
kernelInfo->heapInfo.pKernelHeap = data;
std::unique_ptr<WhiteBox<::L0::KernelImmutableData>> kernelImmData{new WhiteBox<::L0::KernelImmutableData>(this->device)};
kernelImmData->initialize(kernelInfo, device, 0, nullptr, nullptr, false);
auto patchAddr = reinterpret_cast<uintptr_t>(ptrOffset(kernelImmData->isaGraphicsAllocation->getUnderlyingBuffer(), 0x8));
pModule->kernelImmDatas.push_back(std::move(kernelImmData));
pModule->translationUnit->programInfo.kernelInfos.push_back(kernelInfo);
auto linkerInput = std::make_unique<::WhiteBox<NEO::LinkerInput>>();
linkerInput->relocations.push_back({{".str", 0x8, LinkerInput::RelocationInfo::Type::Address, SegmentType::Instructions}});
linkerInput->symbols.insert({".str", {0x0, 0x8, SegmentType::GlobalStrings}});
linkerInput->traits.requiresPatchingOfInstructionSegments = true;
pModule->translationUnit->programInfo.linkerInput = std::move(linkerInput);
const char constStringData[] = "Hello World!\n";
auto stringsAddr = reinterpret_cast<uintptr_t>(constStringData);
pModule->translationUnit->programInfo.globalStrings.initData = constStringData;
pModule->translationUnit->programInfo.globalStrings.size = sizeof(constStringData);
auto status = pModule->linkBinary();
EXPECT_TRUE(status);
constexpr bool is64Bit = sizeof(void *) == 8;
if (is64Bit) {
EXPECT_EQ(static_cast<uint64_t>(stringsAddr), *reinterpret_cast<uint64_t *>(patchAddr));
} else {
EXPECT_EQ(static_cast<uint32_t>(stringsAddr), *reinterpret_cast<uint32_t *>(patchAddr));
}
}
TEST_F(ModuleTests, givenImplicitArgsRelocationWhenLinkingModuleThenSegmentIsPatchedAndImplicitArgsAreRequired) {
auto pModule = std::make_unique<Module>(device, nullptr, ModuleType::User);

View File

@@ -54,7 +54,7 @@ const KernelInfo *Program::getKernelInfo(size_t ordinal, uint32_t rootDeviceInde
return kernelInfoArray[ordinal];
}
cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const void *variablesInitData) {
cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const void *variablesInitData, const ProgramInfo::GlobalSurfaceInfo &stringsInfo) {
auto linkerInput = getLinkerInput(pDevice->getRootDeviceIndex());
if (linkerInput == nullptr) {
return CL_SUCCESS;
@@ -65,6 +65,7 @@ cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const
Linker::SegmentInfo globals;
Linker::SegmentInfo constants;
Linker::SegmentInfo exportedFunctions;
Linker::SegmentInfo strings;
GraphicsAllocation *globalsForPatching = getGlobalSurface(rootDeviceIndex);
GraphicsAllocation *constantsForPatching = getConstantSurface(rootDeviceIndex);
if (globalsForPatching != nullptr) {
@@ -75,6 +76,10 @@ cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const
constants.gpuAddress = static_cast<uintptr_t>(constantsForPatching->getGpuAddress());
constants.segmentSize = constantsForPatching->getUnderlyingBufferSize();
}
if (stringsInfo.initData != nullptr) {
strings.gpuAddress = reinterpret_cast<uintptr_t>(stringsInfo.initData);
strings.segmentSize = stringsInfo.size;
}
if (linkerInput->getExportedFunctionsSegmentId() >= 0) {
// Exported functions reside in instruction heap of one of kernels
auto exportedFunctionHeapId = linkerInput->getExportedFunctionsSegmentId();
@@ -95,7 +100,7 @@ cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const
}
Linker::UnresolvedExternals unresolvedExternalsInfo;
bool linkSuccess = LinkingStatus::LinkedFully == linker.link(globals, constants, exportedFunctions,
bool linkSuccess = LinkingStatus::LinkedFully == linker.link(globals, constants, exportedFunctions, strings,
globalsForPatching, constantsForPatching,
isaSegmentsForPatching, unresolvedExternalsInfo,
pDevice, constantsInitData, variablesInitData);
@@ -236,7 +241,7 @@ cl_int Program::processProgramInfo(ProgramInfo &src, const ClDevice &clDevice) {
kernelInfo->apply(deviceInfoConstants);
}
return linkBinary(&clDevice.getDevice(), src.globalConstants.initData, src.globalVariables.initData);
return linkBinary(&clDevice.getDevice(), src.globalConstants.initData, src.globalVariables.initData, src.globalStrings);
}
void Program::processDebugData(uint32_t rootDeviceIndex) {

View File

@@ -287,7 +287,7 @@ class Program : public BaseObject<_cl_program> {
cl_int packDeviceBinary(ClDevice &clDevice);
MOCKABLE_VIRTUAL cl_int linkBinary(Device *pDevice, const void *constantsInitData, const void *variablesInitData);
MOCKABLE_VIRTUAL cl_int linkBinary(Device *pDevice, const void *constantsInitData, const void *variablesInitData, const ProgramInfo::GlobalSurfaceInfo &stringInfo);
void separateBlockKernels(uint32_t rootDeviceIndex);

View File

@@ -1878,7 +1878,7 @@ HWTEST_TEMPLATED_F(BlitCopyTests, givenKernelAllocationInLocalMemoryWithoutCpuAc
auto initialTaskCount = bcsMockContext->bcsCsr->peekTaskCount();
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr);
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
EXPECT_EQ(CL_SUCCESS, ret);
EXPECT_EQ(initialTaskCount + 1, bcsMockContext->bcsCsr->peekTaskCount());

View File

@@ -487,7 +487,7 @@ TEST_F(ProgramDataTest, GivenProgramWith32bitPointerOptWhenProgramScopeConstantB
programInfo.globalConstants.initData = constantSurface.mockGfxAllocation.getUnderlyingBuffer();
pProgram->setLinkerInput(pClDevice->getRootDeviceIndex(), std::move(programInfo.linkerInput));
pProgram->linkBinary(&pClDevice->getDevice(), programInfo.globalConstants.initData, programInfo.globalVariables.initData);
pProgram->linkBinary(&pClDevice->getDevice(), programInfo.globalConstants.initData, programInfo.globalVariables.initData, {});
uint32_t expectedAddr = static_cast<uint32_t>(constantSurface.getGraphicsAllocation(pClDevice->getRootDeviceIndex())->getGpuAddressToPatch());
EXPECT_EQ(expectedAddr, constantSurfaceStorage[0]);
EXPECT_EQ(sentinel, constantSurfaceStorage[1]);
@@ -533,7 +533,7 @@ TEST_F(ProgramDataTest, GivenProgramWith32bitPointerOptWhenProgramScopeGlobalPoi
programInfo.globalVariables.initData = globalSurface.mockGfxAllocation.getUnderlyingBuffer();
pProgram->setLinkerInput(pClDevice->getRootDeviceIndex(), std::move(programInfo.linkerInput));
pProgram->linkBinary(&pClDevice->getDevice(), programInfo.globalConstants.initData, programInfo.globalVariables.initData);
pProgram->linkBinary(&pClDevice->getDevice(), programInfo.globalConstants.initData, programInfo.globalVariables.initData, {});
uint32_t expectedAddr = static_cast<uint32_t>(globalSurface.getGraphicsAllocation(pClDevice->getRootDeviceIndex())->getGpuAddressToPatch());
EXPECT_EQ(expectedAddr, globalSurfaceStorage[0]);
EXPECT_EQ(sentinel, globalSurfaceStorage[1]);
@@ -560,7 +560,7 @@ TEST(ProgramLinkBinaryTest, whenLinkerInputEmptyThenLinkSuccessful) {
auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
MockProgram program{nullptr, false, toClDeviceVector(*device)};
program.setLinkerInput(device->getRootDeviceIndex(), std::move(linkerInput));
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr);
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
EXPECT_EQ(CL_SUCCESS, ret);
}
@@ -585,7 +585,7 @@ TEST(ProgramLinkBinaryTest, whenLinkerUnresolvedExternalThenLinkFailedAndBuildLo
std::string buildLog = program.getBuildLog(device->getRootDeviceIndex());
EXPECT_TRUE(buildLog.empty());
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr);
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
EXPECT_NE(CL_SUCCESS, ret);
program.getKernelInfoArray(rootDeviceIndex).clear();
buildLog = program.getBuildLog(rootDeviceIndex);
@@ -632,7 +632,7 @@ TEST_F(ProgramDataTest, whenLinkerInputValidThenIsaIsProperlyPatched) {
buildInfo.globalSurface = new MockGraphicsAllocation(globalVariablesBuffer.data(), globalVariablesBuffer.size());
buildInfo.constantSurface = new MockGraphicsAllocation(globalConstantsBuffer.data(), globalConstantsBuffer.size());
auto ret = program.linkBinary(&pClDevice->getDevice(), globalConstantsInitData.data(), globalVariablesInitData.data());
auto ret = program.linkBinary(&pClDevice->getDevice(), globalConstantsInitData.data(), globalVariablesInitData.data(), {});
EXPECT_EQ(CL_SUCCESS, ret);
linkerInput.reset(static_cast<WhiteBox<LinkerInput> *>(buildInfo.linkerInput.release()));
@@ -680,7 +680,7 @@ TEST_F(ProgramDataTest, whenRelocationsAreNotNeededThenIsaIsPreserved) {
buildInfo.globalSurface = new MockGraphicsAllocation(globalVariablesBuffer.data(), globalVariablesBuffer.size());
buildInfo.constantSurface = new MockGraphicsAllocation(globalConstantsBuffer.data(), globalConstantsBuffer.size());
auto ret = program.linkBinary(&pClDevice->getDevice(), globalConstantsInitData.data(), globalVariablesInitData.data());
auto ret = program.linkBinary(&pClDevice->getDevice(), globalConstantsInitData.data(), globalVariablesInitData.data(), {});
EXPECT_EQ(CL_SUCCESS, ret);
EXPECT_EQ(kernelHeapData, kernelHeap);
@@ -691,6 +691,49 @@ TEST_F(ProgramDataTest, whenRelocationsAreNotNeededThenIsaIsPreserved) {
buildInfo.constantSurface = nullptr;
}
TEST(ProgramStringSectionTest, WhenConstStringBufferIsPresentThenUseItForLinking) {
auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
auto rootDeviceIndex = device->getRootDeviceIndex();
MockProgram program{nullptr, false, toClDeviceVector(*device)};
uint8_t kernelHeapData[64] = {};
MockGraphicsAllocation kernelIsa(kernelHeapData, 64);
KernelInfo kernelInfo = {};
kernelInfo.kernelDescriptor.kernelMetadata.kernelName = "onlyKernel";
kernelInfo.heapInfo.pKernelHeap = kernelHeapData;
kernelInfo.heapInfo.KernelHeapSize = 64;
kernelInfo.kernelAllocation = &kernelIsa;
program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo);
auto linkerInput = std::make_unique<WhiteBox<LinkerInput>>();
linkerInput->relocations.push_back({{".str", 0x8, LinkerInput::RelocationInfo::Type::Address, SegmentType::Instructions}});
linkerInput->symbols.insert({".str", {0x0, 0x8, SegmentType::GlobalStrings}});
linkerInput->traits.requiresPatchingOfInstructionSegments = true;
program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
auto isaCpuPtr = reinterpret_cast<char *>(kernelInfo.getGraphicsAllocation()->getUnderlyingBuffer());
auto patchAddr = ptrOffset(isaCpuPtr, 0x8);
const char constStringData[] = "Hello World!\n";
auto stringsAddr = reinterpret_cast<uintptr_t>(constStringData);
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {constStringData, sizeof(constStringData)});
EXPECT_EQ(CL_SUCCESS, ret);
constexpr bool is64Bit = sizeof(void *) == 8;
if (is64Bit) {
EXPECT_EQ(static_cast<uint64_t>(stringsAddr), *reinterpret_cast<uint64_t *>(patchAddr));
} else {
EXPECT_EQ(static_cast<uint32_t>(stringsAddr), *reinterpret_cast<uint32_t *>(patchAddr));
}
program.getKernelInfoArray(rootDeviceIndex).clear();
}
TEST(ProgramImplicitArgsTest, whenImplicitRelocationIsPresentThenKernelRequiresImplicitArgs) {
auto device = std::make_unique<MockClDevice>(MockDevice::createWithNewExecutionEnvironment<MockDevice>(defaultHwInfo.get()));
auto rootDeviceIndex = device->getRootDeviceIndex();
@@ -708,7 +751,7 @@ TEST(ProgramImplicitArgsTest, whenImplicitRelocationIsPresentThenKernelRequiresI
linkerInput->relocations.push_back({{implicitArgsRelocationSymbolName, 0x8, LinkerInput::RelocationInfo::Type::AddressLow, SegmentType::Instructions}});
linkerInput->traits.requiresPatchingOfInstructionSegments = true;
program.setLinkerInput(rootDeviceIndex, std::move(linkerInput));
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr);
auto ret = program.linkBinary(&device->getDevice(), nullptr, nullptr, {});
EXPECT_EQ(CL_SUCCESS, ret);
EXPECT_TRUE(kernelInfo.kernelDescriptor.kernelAttributes.flags.requiresImplicitArgs);

View File

@@ -29,6 +29,8 @@ SegmentType LinkerInput::getSegmentForSection(ConstStringRef name) {
return NEO::SegmentType::GlobalConstants;
} else if (name == NEO::Elf::SectionsNamesZebin::dataGlobal) {
return NEO::SegmentType::GlobalVariables;
} else if (name == NEO::Elf::SectionsNamesZebin::dataConstString) {
return NEO::SegmentType::GlobalStrings;
} else if (name.startsWith(NEO::Elf::SpecialSectionNames::text.data())) {
return NEO::SegmentType::Instructions;
}
@@ -243,7 +245,7 @@ void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64>
}
}
bool Linker::processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions) {
bool Linker::processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings) {
relocatedSymbols.reserve(data.getSymbols().size());
for (auto &symbol : data.getSymbols()) {
const SegmentInfo *seg = nullptr;
@@ -257,6 +259,9 @@ bool Linker::processRelocations(const SegmentInfo &globalVariables, const Segmen
case SegmentType::GlobalConstants:
seg = &globalConstants;
break;
case SegmentType::GlobalStrings:
seg = &globalStrings;
break;
case SegmentType::Instructions:
seg = &exportedFunctions;
break;

View File

@@ -23,6 +23,7 @@ class GraphicsAllocation;
enum class SegmentType : uint32_t {
Unknown,
GlobalConstants,
GlobalStrings,
GlobalVariables,
Instructions,
};
@@ -182,12 +183,12 @@ struct Linker {
: data(data) {
}
LinkingStatus link(const SegmentInfo &globalVariablesSegInfo, const SegmentInfo &globalConstantsSegInfo, const SegmentInfo &exportedFunctionsSegInfo,
LinkingStatus link(const SegmentInfo &globalVariablesSegInfo, const SegmentInfo &globalConstantsSegInfo, const SegmentInfo &exportedFunctionsSegInfo, const SegmentInfo &globalStringsSegInfo,
GraphicsAllocation *globalVariablesSeg, GraphicsAllocation *globalConstantsSeg, const PatchableSegments &instructionsSegments,
UnresolvedExternals &outUnresolvedExternals, Device *pDevice, const void *constantsInitData, const void *variablesInitData) {
bool success = data.isValid();
auto initialUnresolvedExternalsCount = outUnresolvedExternals.size();
success = success && processRelocations(globalVariablesSegInfo, globalConstantsSegInfo, exportedFunctionsSegInfo);
success = success && processRelocations(globalVariablesSegInfo, globalConstantsSegInfo, exportedFunctionsSegInfo, globalStringsSegInfo);
if (!success) {
return LinkingStatus::Error;
}
@@ -214,7 +215,7 @@ struct Linker {
const LinkerInput &data;
RelocatedSymbolsMap relocatedSymbols;
bool processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions);
bool processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings);
void patchInstructionsSegments(const std::vector<PatchableSegment> &instructionsSegments, std::vector<UnresolvedExternal> &outUnresolvedExternals);

View File

@@ -43,6 +43,7 @@ static constexpr ConstStringRef textPrefix = ".text.";
static constexpr ConstStringRef dataConst = ".data.const";
static constexpr ConstStringRef dataGlobalConst = ".data.global_const";
static constexpr ConstStringRef dataGlobal = ".data.global";
static constexpr ConstStringRef dataConstString = ".data.const.string";
static constexpr ConstStringRef symtab = ".symtab";
static constexpr ConstStringRef relTablePrefix = ".rel.";
static constexpr ConstStringRef spv = ".spv";

View File

@@ -98,6 +98,8 @@ DecodeError extractZebinSections(NEO::Elf::Elf<Elf::EI_CLASS_64> &elf, ZebinSect
out.constDataSections.push_back(&elfSectionHeader);
} else if (sectionName == NEO::Elf::SectionsNamesZebin::dataGlobal) {
out.globalDataSections.push_back(&elfSectionHeader);
} else if (sectionName == NEO::Elf::SectionsNamesZebin::dataConstString) {
out.constDataStringSections.push_back(&elfSectionHeader);
} else if (sectionName.startsWith(NEO::Elf::SectionsNamesZebin::debugPrefix.data())) {
// ignoring intentionally
} else {
@@ -164,6 +166,7 @@ DecodeError validateZebinSectionsCount(const ZebinSections &sections, std::strin
bool valid = validateZebinSectionsCountAtMost(sections.zeInfoSections, NEO::Elf::SectionsNamesZebin::zeInfo, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.globalDataSections, NEO::Elf::SectionsNamesZebin::dataGlobal, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.constDataSections, NEO::Elf::SectionsNamesZebin::dataConst, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.constDataStringSections, NEO::Elf::SectionsNamesZebin::dataConstString, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.symtabSections, NEO::Elf::SectionsNamesZebin::symtab, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.spirvSections, NEO::Elf::SectionsNamesZebin::spv, 1U, outErrReason, outWarning);
valid &= validateZebinSectionsCountAtMost(sections.noteIntelGTSections, NEO::Elf::SectionsNamesZebin::noteIntelGT, 1U, outErrReason, outWarning);
@@ -1214,6 +1217,11 @@ DecodeError decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(ProgramInfo
dst.globalConstants.size = zebinSections.constDataSections[0]->data.size();
}
if (false == zebinSections.constDataStringSections.empty()) {
dst.globalStrings.initData = zebinSections.constDataStringSections[0]->data.begin();
dst.globalStrings.size = zebinSections.constDataStringSections[0]->data.size();
}
if (false == zebinSections.symtabSections.empty()) {
outWarning.append("DeviceBinaryFormat::Zebin : Ignoring symbol table\n");
}

View File

@@ -26,6 +26,7 @@ struct ZebinSections {
StackVec<SectionHeaderData *, 1> zeInfoSections;
StackVec<SectionHeaderData *, 1> globalDataSections;
StackVec<SectionHeaderData *, 1> constDataSections;
StackVec<SectionHeaderData *, 1> constDataStringSections;
StackVec<SectionHeaderData *, 1> symtabSections;
StackVec<SectionHeaderData *, 1> spirvSections;
StackVec<SectionHeaderData *, 1> noteIntelGTSections;

View File

@@ -37,6 +37,7 @@ struct ProgramInfo {
GlobalSurfaceInfo globalConstants;
GlobalSurfaceInfo globalVariables;
GlobalSurfaceInfo globalStrings;
std::unique_ptr<LinkerInput> linkerInput;
std::vector<KernelInfo *> kernelInfos;

View File

@@ -294,12 +294,14 @@ TEST(LinkerInputTests, WhenGettingSegmentForSectionNameThenCorrectSegmentIsRetur
auto segmentConst = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::dataConst.str());
auto segmentGlobalConst = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::dataGlobalConst.str());
auto segmentGlobal = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::dataGlobal.str());
auto segmentConstString = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::dataConstString.str());
auto segmentInstructions = NEO::LinkerInput::getSegmentForSection(NEO::Elf::SectionsNamesZebin::textPrefix.str());
auto segmentInstructions2 = NEO::LinkerInput::getSegmentForSection(".text.abc");
EXPECT_EQ(NEO::SegmentType::GlobalConstants, segmentConst);
EXPECT_EQ(NEO::SegmentType::GlobalConstants, segmentGlobalConst);
EXPECT_EQ(NEO::SegmentType::GlobalVariables, segmentGlobal);
EXPECT_EQ(NEO::SegmentType::GlobalStrings, segmentConstString);
EXPECT_EQ(NEO::SegmentType::Instructions, segmentInstructions);
EXPECT_EQ(NEO::SegmentType::Instructions, segmentInstructions2);
}
@@ -972,9 +974,10 @@ TEST(LinkerTests, givenEmptyLinkerInputThenLinkerOutputIsEmpty) {
NEO::GraphicsAllocation *patchableConstVarSeg = nullptr;
NEO::Linker::PatchableSegments patchableInstructionSegments;
NEO::Linker::UnresolvedExternals unresolvedExternals;
auto linkResult = linker.link(globalVar, globalConst, exportedFunc,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
auto linkResult = linker.link(
globalVar, globalConst, exportedFunc, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
EXPECT_EQ(0U, unresolvedExternals.size());
auto relocatedSymbols = linker.extractRelocatedSymbols();
@@ -990,9 +993,10 @@ TEST(LinkerTests, givenInvalidLinkerInputThenLinkerFails) {
NEO::GraphicsAllocation *patchableConstVarSeg = nullptr;
NEO::Linker::PatchableSegments patchableInstructionSegments;
NEO::Linker::UnresolvedExternals unresolvedExternals;
auto linkResult = linker.link(globalVar, globalConst, exportedFunc,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
auto linkResult = linker.link(
globalVar, globalConst, exportedFunc, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::Error, linkResult);
}
@@ -1018,9 +1022,10 @@ TEST(LinkerTests, givenUnresolvedExternalWhenPatchingInstructionsThenLinkPartial
NEO::GraphicsAllocation *patchableConstVarSeg = nullptr;
NEO::Linker::PatchableSegments patchableInstructionSegments{seg0};
auto linkResult = linker.link(globalVar, globalConst, exportedFunc,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
auto linkResult = linker.link(
globalVar, globalConst, exportedFunc, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
auto relocatedSymbols = linker.extractRelocatedSymbols();
EXPECT_EQ(0U, relocatedSymbols.size());
@@ -1112,9 +1117,10 @@ TEST(LinkerTests, givenValidSymbolsAndRelocationsThenInstructionSegmentsArePrope
NEO::GraphicsAllocation *patchableGlobalVarSeg = nullptr;
NEO::GraphicsAllocation *patchableConstVarSeg = nullptr;
auto linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments, unresolvedExternals,
nullptr, nullptr, nullptr);
auto linkResult = linker.link(
globalVarSegment, globalConstSegment, exportedFuncSegment, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments, unresolvedExternals,
nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
auto relocatedSymbols = linker.extractRelocatedSymbols();
EXPECT_EQ(0U, unresolvedExternals.size());
@@ -1170,18 +1176,20 @@ TEST(LinkerTests, givenInvalidSymbolOffsetWhenPatchingInstructionsThenRelocation
NEO::GraphicsAllocation *patchableGlobalVarSeg = nullptr;
NEO::GraphicsAllocation *patchableConstVarSeg = nullptr;
auto linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
auto linkResult = linker.link(
globalVarSegment, globalConstSegment, exportedFuncSegment, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::Error, linkResult);
auto relocatedSymbols = linker.extractRelocatedSymbols();
EXPECT_EQ(0U, unresolvedExternals.size());
EXPECT_EQ(0U, relocatedSymbols.size());
globalVarSegment.segmentSize = symGlobalVariable.s_offset + symGlobalVariable.s_size;
linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments, unresolvedExternals,
nullptr, nullptr, nullptr);
linkResult = linker.link(
globalVarSegment, globalConstSegment, exportedFuncSegment, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments, unresolvedExternals,
nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
}
@@ -1218,9 +1226,10 @@ TEST(LinkerTests, givenInvalidRelocationOffsetThenPatchingOfInstructionsFails) {
NEO::GraphicsAllocation *patchableGlobalVarSeg = nullptr;
NEO::GraphicsAllocation *patchableConstVarSeg = nullptr;
auto linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
auto linkResult = linker.link(
globalVarSegment, globalConstSegment, exportedFuncSegment, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
auto relocatedSymbols = linker.extractRelocatedSymbols();
EXPECT_EQ(1U, relocatedSymbols.size());
@@ -1228,9 +1237,10 @@ TEST(LinkerTests, givenInvalidRelocationOffsetThenPatchingOfInstructionsFails) {
EXPECT_TRUE(unresolvedExternals[0].internalError);
patchableInstructionSegments[0].segmentSize = relocA.r_offset + sizeof(uintptr_t);
linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
linkResult = linker.link(
globalVarSegment, globalConstSegment, exportedFuncSegment, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
}
@@ -1269,21 +1279,71 @@ TEST(LinkerTests, givenUnknownSymbolTypeWhenPatchingInstructionsThenRelocationFa
ASSERT_EQ(1U, linkerInput.symbols.count("A"));
linkerInput.symbols["A"].segment = NEO::SegmentType::Unknown;
auto linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
auto linkResult = linker.link(
globalVarSegment, globalConstSegment, exportedFuncSegment, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::Error, linkResult);
auto relocatedSymbols = linker.extractRelocatedSymbols();
EXPECT_EQ(0U, relocatedSymbols.size());
ASSERT_EQ(0U, unresolvedExternals.size());
linkerInput.symbols["A"].segment = NEO::SegmentType::GlobalVariables;
linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment, {},
patchableGlobalVarSeg, patchableConstVarSeg, patchableInstructionSegments,
unresolvedExternals, nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
}
TEST(LinkerTests, givenValidStringSymbolsAndRelocationsWhenPatchingThenItIsProperlyPatched) {
NEO::Linker::SegmentInfo stringSegment;
stringSegment.gpuAddress = 0x1234;
stringSegment.segmentSize = 0x10;
uint8_t instructionSegment[32] = {};
NEO::Linker::PatchableSegment seg0;
seg0.hostPointer = instructionSegment;
seg0.segmentSize = sizeof(instructionSegment);
NEO::Linker::PatchableSegments patchableInstructionSegments{seg0};
WhiteBox<NEO::LinkerInput> linkerInput;
SymbolInfo strSymbol;
strSymbol.segment = SegmentType::GlobalStrings;
strSymbol.offset = 0U;
strSymbol.size = 8U;
linkerInput.symbols.insert({".str", strSymbol});
NEO::LinkerInput::RelocationInfo relocation;
relocation.offset = 0x8U;
relocation.relocationSegment = NEO::SegmentType::Instructions;
relocation.symbolName = ".str";
relocation.type = NEO::LinkerInput::RelocationInfo::Type::Address;
linkerInput.relocations.push_back({relocation});
linkerInput.traits.requiresPatchingOfInstructionSegments = true;
NEO::Linker linker(linkerInput);
NEO::Linker::UnresolvedExternals unresolvedExternals;
auto linkResult = linker.link(
{}, {}, {}, stringSegment,
nullptr, nullptr, patchableInstructionSegments, unresolvedExternals,
nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
EXPECT_EQ(0U, unresolvedExternals.size());
EXPECT_EQ(1U, linker.extractRelocatedSymbols().size());
uintptr_t strAddr = stringSegment.gpuAddress + strSymbol.offset;
uintptr_t patchAddr = reinterpret_cast<uintptr_t>(instructionSegment) + static_cast<uintptr_t>(relocation.offset);
constexpr bool is64Bit = sizeof(void *) == 8;
if (is64Bit) {
EXPECT_EQ(static_cast<uint64_t>(strAddr), *reinterpret_cast<const uint64_t *>(patchAddr));
} else {
EXPECT_EQ(static_cast<uint32_t>(strAddr), *reinterpret_cast<const uint32_t *>(patchAddr));
}
}
TEST(LinkerTests, givenValidSymbolsAndRelocationsWhenPatchingDataSegmentsThenTheyAreProperlyPatched) {
uint64_t initGlobalConstantData[3];
initGlobalConstantData[0] = 0x10; // var1 address will be added here
@@ -1420,7 +1480,7 @@ TEST(LinkerTests, givenValidSymbolsAndRelocationsWhenPatchingDataSegmentsThenThe
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,
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, exportedFunctionsSegmentInfo, {},
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
@@ -1477,7 +1537,7 @@ TEST(LinkerTests, givenInvalidSymbolWhenPatchingDataSegmentsThenRelocationIsUnre
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, {},
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, {}, {},
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
@@ -1514,7 +1574,7 @@ TEST(LinkerTests, givenInvalidRelocationOffsetWhenPatchingDataSegmentsThenReloca
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, {},
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, {}, {},
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
@@ -1536,7 +1596,7 @@ TEST(LinkerTests, givenInvalidRelocationSegmentWhenPatchingDataSegmentsThenReloc
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({}, {}, {},
auto linkResult = linker.link({}, {}, {}, {},
nullptr, nullptr, {},
unresolvedExternals, device.get(), nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedPartially, linkResult);
@@ -1574,7 +1634,7 @@ TEST(LinkerTests, given32BitBinaryWithValidSymbolsAndRelocationsWhenPatchingData
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, {},
auto linkResult = linker.link(globalVariablesSegmentInfo, globalConstantsSegmentInfo, {}, {},
&globalVariablesPatchableSegment, &globalConstantsPatchableSegment, {},
unresolvedExternals, device.get(), initGlobalConstantData, initGlobalVariablesData);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);
@@ -1862,7 +1922,7 @@ TEST(LinkerTests, givenImplicitArgRelocationThenPatchRelocationWithSizeOfImplici
seg0.segmentSize = instructionSegment.size();
NEO::Linker::PatchableSegments patchableInstructionSegments{seg0};
auto linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment,
auto linkResult = linker.link(globalVarSegment, globalConstSegment, exportedFuncSegment, {},
nullptr, nullptr, patchableInstructionSegments, unresolvedExternals,
nullptr, nullptr, nullptr);
EXPECT_EQ(NEO::LinkingStatus::LinkedFully, linkResult);

View File

@@ -86,6 +86,7 @@ TEST(ExtractZebinSections, GivenKnownSectionsThenCapturesThemProperly) {
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::textPrefix.str() + "someOtherKernel", std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataConst, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataGlobal, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataConstString, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugInfo, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::debugAbbrev, std::string{});
elfEncoder.appendSection(NEO::Elf::SHT_SYMTAB, NEO::Elf::SectionsNamesZebin::symtab, std::string{});
@@ -112,6 +113,7 @@ TEST(ExtractZebinSections, GivenKnownSectionsThenCapturesThemProperly) {
ASSERT_EQ(2U, sections.textKernelSections.size());
ASSERT_EQ(1U, sections.globalDataSections.size());
ASSERT_EQ(1U, sections.constDataSections.size());
ASSERT_EQ(1U, sections.constDataStringSections.size());
ASSERT_EQ(1U, sections.zeInfoSections.size());
ASSERT_EQ(1U, sections.symtabSections.size());
ASSERT_EQ(1U, sections.spirvSections.size());
@@ -122,6 +124,7 @@ TEST(ExtractZebinSections, GivenKnownSectionsThenCapturesThemProperly) {
EXPECT_STREQ((NEO::Elf::SectionsNamesZebin::textPrefix.str() + "someOtherKernel").c_str(), strings + sections.textKernelSections[1]->header->name);
EXPECT_STREQ(NEO::Elf::SectionsNamesZebin::dataGlobal.data(), strings + sections.globalDataSections[0]->header->name);
EXPECT_STREQ(NEO::Elf::SectionsNamesZebin::dataConst.data(), strings + sections.constDataSections[0]->header->name);
EXPECT_STREQ(NEO::Elf::SectionsNamesZebin::dataConstString.data(), strings + sections.constDataStringSections[0]->header->name);
EXPECT_STREQ(NEO::Elf::SectionsNamesZebin::zeInfo.data(), strings + sections.zeInfoSections[0]->header->name);
EXPECT_STREQ(NEO::Elf::SectionsNamesZebin::symtab.data(), strings + sections.symtabSections[0]->header->name);
EXPECT_STREQ(NEO::Elf::SectionsNamesZebin::spv.data(), strings + sections.spirvSections[0]->header->name);
@@ -2210,6 +2213,26 @@ TEST(DecodeSingleDeviceBinaryZebin, GivenConstDataSectionThenSetsUpInitDataAndSi
EXPECT_EQ(nullptr, programInfo.globalVariables.initData);
}
TEST(DecodeSingleDeviceBinaryZebin, GivenConstDataStringsSectionThenSetsUpInitDataAndSize) {
ZebinTestData::ValidEmptyProgram zebin;
const uint8_t data[] = {'H', 'e', 'l', 'l', 'o', '!'};
zebin.appendSection(NEO::Elf::SHT_PROGBITS, NEO::Elf::SectionsNamesZebin::dataConstString, data);
NEO::ProgramInfo programInfo;
NEO::SingleDeviceBinary singleBinary;
singleBinary.deviceBinary = zebin.storage;
std::string decodeErrors;
std::string decodeWarnings;
auto error = NEO::decodeSingleDeviceBinary<NEO::DeviceBinaryFormat::Zebin>(programInfo, singleBinary, decodeErrors, decodeWarnings);
EXPECT_EQ(NEO::DecodeError::Success, error);
EXPECT_TRUE(decodeWarnings.empty()) << decodeWarnings;
EXPECT_TRUE(decodeErrors.empty()) << decodeErrors;
EXPECT_EQ(sizeof(data), programInfo.globalStrings.size);
EXPECT_NE(nullptr, programInfo.globalStrings.initData);
EXPECT_EQ(sizeof(data), programInfo.globalStrings.size);
EXPECT_EQ(0, memcmp(programInfo.globalStrings.initData, data, sizeof(data)));
}
TEST(DecodeSingleDeviceBinaryZebin, GivenIntelGTNoteSectionThenAddsItToZebinSections) {
ZebinTestData::ValidEmptyProgram zebin;
NEO::Elf::IntelGTNote note = {};