fix: correct resolving external functions dependencies

respect scenario when dependency comes from separate module

Related-To: NEO-15211
Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
Mateusz Jablonski
2025-09-17 14:53:36 +00:00
committed by Compute-Runtime-Automation
parent a0ff19823b
commit 8310b10987
3 changed files with 114 additions and 16 deletions

View File

@@ -297,21 +297,41 @@ void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<numBits> &elf, con
}
void LinkerInput::parseRelocationForExtFuncUsage(const RelocationInfo &relocInfo, const std::string &kernelName) {
auto extFuncSymIt = std::find_if(extFuncSymbols.begin(), extFuncSymbols.end(), [relocInfo](auto &pair) {
return pair.first == relocInfo.symbolName;
});
if (extFuncSymIt != extFuncSymbols.end()) {
if (kernelName == Zebin::Elf::SectionNames::externalFunctions.str()) {
auto callerIt = std::find_if(extFuncSymbols.begin(), extFuncSymbols.end(), [relocInfo](auto &pair) {
auto &symbol = pair.second;
return relocInfo.offset >= symbol.offset && relocInfo.offset < symbol.offset + symbol.size;
});
if (callerIt != extFuncSymbols.end()) {
extFunDependencies.push_back({relocInfo.symbolName, callerIt->first});
}
} else {
kernelDependencies.push_back({relocInfo.symbolName, kernelName});
auto shouldIgnoreRelocation = [&](const RelocationInfo &relocInfo) {
if (relocInfo.symbolName.empty()) {
return true;
}
// ignore relocations for non-instruction symbols
if (std::find_if(symbols.begin(), symbols.end(), [relocInfo](auto &pair) {
auto &symbol = pair.second;
return relocInfo.symbolName == pair.first && symbol.segment != SegmentType::instructions;
}) != symbols.end()) {
return true;
}
for (auto specialRelocationName : {implicitArgsRelocationSymbolName, Linker::perThreadOff, Linker::subDeviceID}) {
if (relocInfo.symbolName == specialRelocationName) {
return true;
}
}
return false;
};
if (shouldIgnoreRelocation(relocInfo)) {
return;
}
if (kernelName == Zebin::Elf::SectionNames::externalFunctions.str()) {
auto callerIt = std::find_if(extFuncSymbols.begin(), extFuncSymbols.end(), [relocInfo](auto &pair) {
auto &symbol = pair.second;
return relocInfo.offset >= symbol.offset && relocInfo.offset < symbol.offset + symbol.size;
});
if (callerIt != extFuncSymbols.end()) {
extFunDependencies.push_back({relocInfo.symbolName, callerIt->first});
}
} else {
kernelDependencies.push_back({relocInfo.symbolName, kernelName});
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2024 Intel Corporation
* Copyright (C) 2021-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -12,6 +12,7 @@
#include <array>
#include <cstdint>
#include <optional>
#include <string>
#include <type_traits>
namespace NEO {
@@ -19,7 +20,7 @@ namespace NEO {
struct KernelDescriptor;
struct RootDeviceEnvironment;
inline constexpr const char *implicitArgsRelocationSymbolName = "__INTEL_PATCH_CROSS_THREAD_OFFSET_OFF_R0";
inline const std::string implicitArgsRelocationSymbolName = "__INTEL_PATCH_CROSS_THREAD_OFFSET_OFF_R0";
namespace ImplicitArgsHelper {
std::array<uint8_t, 3> getDimensionOrderForLocalIds(const uint8_t *workgroupDimensionsOrder, std::optional<std::pair<bool /* localIdsGeneratedByRuntime */, uint32_t /* walkOrderForHwGenerationOfLocalIds */>> hwGenerationOfLocalIdsParams);

View File

@@ -745,6 +745,83 @@ TEST(LinkerInputTests, GivenInvalidFunctionsSymbolsUsedInFunctionsRelocationsWhe
EXPECT_TRUE(mockLinkerInput.extFunDependencies.empty());
}
TEST(LinkerInputTests, GivenFunctionSymbolsUsedInFunctionsRelocationsWhenParsingRelocationsForExtFuncUsageThenAddDependency) {
WhiteBox<NEO::LinkerInput> mockLinkerInput;
auto &extFuncSymbols = mockLinkerInput.extFuncSymbols;
extFuncSymbols.resize(2);
auto &funSym = extFuncSymbols[0];
funSym.first = "fun";
funSym.second.offset = 4U;
funSym.second.size = 4U;
auto &fun2Sym = extFuncSymbols[1];
fun2Sym.first = "fun2";
fun2Sym.second.offset = 8U;
fun2Sym.second.size = 4U;
NEO::LinkerInput::RelocationInfo relocInfo{};
relocInfo.symbolName = "fun3";
relocInfo.offset = 6U;
mockLinkerInput.parseRelocationForExtFuncUsage(relocInfo, NEO::Zebin::Elf::SectionNames::externalFunctions.str());
EXPECT_EQ(1u, mockLinkerInput.extFunDependencies.size());
EXPECT_EQ(relocInfo.symbolName, mockLinkerInput.extFunDependencies[0].usedFuncName);
EXPECT_EQ(funSym.first, mockLinkerInput.extFunDependencies[0].callerFuncName);
mockLinkerInput.extFunDependencies.clear();
relocInfo.offset = 8U;
mockLinkerInput.parseRelocationForExtFuncUsage(relocInfo, NEO::Zebin::Elf::SectionNames::externalFunctions.str());
EXPECT_EQ(1u, mockLinkerInput.extFunDependencies.size());
EXPECT_EQ(relocInfo.symbolName, mockLinkerInput.extFunDependencies[0].usedFuncName);
EXPECT_EQ(fun2Sym.first, mockLinkerInput.extFunDependencies[0].callerFuncName);
}
TEST(LinkerInputTests, GivenExternalFunctionsSymbolsUsedInKernelRelocationsWhenParsingRelocationsForExtFuncUsageForKernelThenAddKernelDependency) {
WhiteBox<NEO::LinkerInput> mockLinkerInput;
NEO::LinkerInput::RelocationInfo relocInfo{};
relocInfo.symbolName = "fun";
std::string kernelName = "kernel";
mockLinkerInput.parseRelocationForExtFuncUsage(relocInfo, kernelName);
EXPECT_TRUE(mockLinkerInput.extFunDependencies.empty());
EXPECT_EQ(1u, mockLinkerInput.kernelDependencies.size());
EXPECT_EQ(relocInfo.symbolName, mockLinkerInput.kernelDependencies[0].usedFuncName);
EXPECT_EQ(kernelName, mockLinkerInput.kernelDependencies[0].kernelName);
}
TEST(LinkerInputTests, GivenNonFunctionRelocationInKernelRelocationsWhenParsingRelocationsForExtFuncUsageForKernelThenDoNotAddKernelDependency) {
WhiteBox<NEO::LinkerInput> mockLinkerInput;
auto &symbols = mockLinkerInput.symbols;
SymbolInfo symbol0 = {
.segment = SegmentType::globalStrings};
SymbolInfo symbol1 = {
.segment = SegmentType::globalVariables};
SymbolInfo symbol2 = {
.segment = SegmentType::instructions};
symbols.emplace(".str", symbol0);
symbols.emplace("globalVar", symbol1);
symbols.emplace("fun", symbol2);
for (auto nonFuncRelocationName : {
implicitArgsRelocationSymbolName,
std::string(".str"),
std::string("globalVar"),
Linker::perThreadOff,
Linker::subDeviceID,
std::string("")}) {
NEO::LinkerInput::RelocationInfo relocInfo{};
relocInfo.symbolName = nonFuncRelocationName;
std::string kernelName = "kernel";
mockLinkerInput.parseRelocationForExtFuncUsage(relocInfo, kernelName);
EXPECT_TRUE(mockLinkerInput.extFunDependencies.empty());
EXPECT_EQ(0u, mockLinkerInput.kernelDependencies.size());
}
}
HWTEST_F(LinkerTests, givenEmptyLinkerInputThenLinkerOutputIsEmpty) {
NEO::LinkerInput linkerInput;
NEO::Linker linker(linkerInput);