mirror of
https://github.com/intel/compute-runtime.git
synced 2026-01-09 22:43:00 +08:00
fix: improve propagating external functions info to kernel
When relocation points to symbol that is not defined within module mark it as optional. When symbol is available at dynamic linking time then info from the function is retrieved but when the symbol is not available then ignore the dependency. Any unresolved symbol needed for module linking is already handled in a separate place. Related-To: NEO-16243, NEO-16263, NEO-16262, NEO-16268 Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
committed by
Compute-Runtime-Automation
parent
a440a3e8ea
commit
15d0feeda8
@@ -97,10 +97,16 @@ struct ExternalFunctionsTests : public ::testing::Test {
|
||||
nameToKernelDescriptor[kernelName] = kd.get();
|
||||
}
|
||||
void addFuncDependency(const std::string &calleeName, const std::string &callerName) {
|
||||
funcDependenciesStorage.push_back({calleeName, callerName});
|
||||
funcDependenciesStorage.push_back({calleeName, callerName, false});
|
||||
}
|
||||
void addKernelDependency(const std::string &calleeName, const std::string &kernelCallerName) {
|
||||
kernelDependenciesStorage.push_back({calleeName, kernelCallerName});
|
||||
kernelDependenciesStorage.push_back({calleeName, kernelCallerName, false});
|
||||
}
|
||||
void addOptionalFuncDependency(const std::string &calleeName, const std::string &callerName) {
|
||||
funcDependenciesStorage.push_back({calleeName, callerName, true});
|
||||
}
|
||||
void addOptionalKernelDependency(const std::string &calleeName, const std::string &kernelCallerName) {
|
||||
kernelDependenciesStorage.push_back({calleeName, kernelCallerName, true});
|
||||
}
|
||||
|
||||
void clear() {
|
||||
@@ -157,6 +163,27 @@ TEST_F(ExternalFunctionsTests, GivenMissingExtFuncInLookupMapWhenResolvingExtFun
|
||||
EXPECT_EQ(ERROR_EXTERNAL_FUNCTION_INFO_MISSING, error);
|
||||
}
|
||||
|
||||
TEST_F(ExternalFunctionsTests, GivenMissingOptionalExtFuncInLookupMapWhenResolvingExtFuncDependenciesThenReturnSuccess) {
|
||||
addOptionalFuncDependency("fun1", "fun0");
|
||||
set();
|
||||
auto error = resolveExtFuncDependencies(extFuncInfo, funcNameToId, functionDependencies);
|
||||
EXPECT_EQ(RESOLVE_SUCCESS, error);
|
||||
clear();
|
||||
|
||||
addOptionalFuncDependency("fun1", "fun0");
|
||||
addExternalFunction("fun1", {});
|
||||
set();
|
||||
error = resolveExtFuncDependencies(extFuncInfo, funcNameToId, functionDependencies);
|
||||
EXPECT_EQ(RESOLVE_SUCCESS, error);
|
||||
clear();
|
||||
|
||||
addOptionalFuncDependency("fun1", "fun0");
|
||||
addExternalFunction("fun0", {});
|
||||
set();
|
||||
error = resolveExtFuncDependencies(extFuncInfo, funcNameToId, functionDependencies);
|
||||
EXPECT_EQ(RESOLVE_SUCCESS, error);
|
||||
}
|
||||
|
||||
TEST_F(ExternalFunctionsTests, GivenMissingExtFuncInLookupMapWhenResolvingKernelDependenciesThenReturnError) {
|
||||
addKernel("kernel");
|
||||
addKernelDependency("fun0", "kernel");
|
||||
@@ -164,6 +191,13 @@ TEST_F(ExternalFunctionsTests, GivenMissingExtFuncInLookupMapWhenResolvingKernel
|
||||
auto error = resolveKernelDependencies(extFuncInfo, funcNameToId, kernelDependencies, nameToKernelDescriptor);
|
||||
EXPECT_EQ(ERROR_EXTERNAL_FUNCTION_INFO_MISSING, error);
|
||||
}
|
||||
TEST_F(ExternalFunctionsTests, GivenMissingOptionalExtFuncInLookupMapWhenResolvingKernelDependenciesThenReturnSuccess) {
|
||||
addKernel("kernel");
|
||||
addOptionalKernelDependency("fun0", "kernel");
|
||||
set();
|
||||
auto error = resolveKernelDependencies(extFuncInfo, funcNameToId, kernelDependencies, nameToKernelDescriptor);
|
||||
EXPECT_EQ(RESOLVE_SUCCESS, error);
|
||||
}
|
||||
|
||||
TEST_F(ExternalFunctionsTests, GivenMissingKernelInLookupMapWhenResolvingKernelDependenciesThenReturnError) {
|
||||
addExternalFunction("fun0", {});
|
||||
@@ -294,3 +328,28 @@ TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelDependenciesWhenResolv
|
||||
EXPECT_FALSE(nameToKernelDescriptor["kernel1"]->kernelAttributes.flags.hasIndirectCalls);
|
||||
EXPECT_TRUE(nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.hasIndirectCalls);
|
||||
}
|
||||
|
||||
TEST_F(ExternalFunctionsTests, GivenValidFunctionAndKernelOptionalDependenciesWhenResolvingDependenciesThenSetAppropriateHasIndirectfCallsAndReturnSuccess) {
|
||||
addKernel("kernel0");
|
||||
addKernel("kernel1");
|
||||
addKernel("kernel2");
|
||||
addExternalFunction("fun0", {.hasIndirectCalls = false});
|
||||
addExternalFunction("fun1", {.hasIndirectCalls = true});
|
||||
addExternalFunction("fun2", {.hasIndirectCalls = false});
|
||||
|
||||
addOptionalFuncDependency("fun1", "fun0");
|
||||
addOptionalKernelDependency("fun0", "kernel0");
|
||||
addOptionalKernelDependency("fun2", "kernel1");
|
||||
addOptionalKernelDependency("fun2", "kernel2");
|
||||
set();
|
||||
|
||||
nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.hasIndirectCalls = true;
|
||||
auto error = resolveExternalDependencies(extFuncInfo, kernelDependencies, functionDependencies, nameToKernelDescriptor);
|
||||
EXPECT_EQ(RESOLVE_SUCCESS, error);
|
||||
EXPECT_TRUE(extFuncInfo[funcNameToId["fun0"]]->hasIndirectCalls);
|
||||
EXPECT_TRUE(extFuncInfo[funcNameToId["fun1"]]->hasIndirectCalls);
|
||||
EXPECT_FALSE(extFuncInfo[funcNameToId["fun2"]]->hasIndirectCalls);
|
||||
EXPECT_TRUE(nameToKernelDescriptor["kernel0"]->kernelAttributes.flags.hasIndirectCalls);
|
||||
EXPECT_FALSE(nameToKernelDescriptor["kernel1"]->kernelAttributes.flags.hasIndirectCalls);
|
||||
EXPECT_TRUE(nameToKernelDescriptor["kernel2"]->kernelAttributes.flags.hasIndirectCalls);
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ TEST(LinkerInputTests, GivenTwoGlobalSymbolsOfTypeFunctionEachPointingToDifferen
|
||||
sectionNames[1] = ".data.const";
|
||||
sectionNames[2] = ".text.hello";
|
||||
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.overrideSymbolName = true;
|
||||
|
||||
elf64.addSymbol(0, 0x1234000, 8, 0, Elf::STT_FUNC, Elf::STB_GLOBAL);
|
||||
@@ -405,7 +405,7 @@ TEST(LinkerInputTests, GivenGlobalSymbolOfTypeObjectPointingToDataGlobalSectionW
|
||||
std::unordered_map<uint32_t, std::string> sectionNames;
|
||||
sectionNames[0] = ".text.abc";
|
||||
sectionNames[1] = ".data.global";
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.overrideSymbolName = true;
|
||||
|
||||
elf64.addSymbol(0, 0x20, 8, 1, Elf::STT_OBJECT, Elf::STB_GLOBAL);
|
||||
@@ -428,7 +428,7 @@ TEST(LinkerInputTests, GivenGlobalSymbolOfTypeObjectPointingToDataConstSectionWh
|
||||
std::unordered_map<uint32_t, std::string> sectionNames;
|
||||
sectionNames[0] = ".text.abc";
|
||||
sectionNames[1] = ".data.const";
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.overrideSymbolName = true;
|
||||
|
||||
elf64.addSymbol(0, 0, 8, 1, Elf::STT_OBJECT, Elf::STB_GLOBAL);
|
||||
@@ -452,7 +452,7 @@ TEST(LinkerInputTests, GivenGlobalSymbolOfTypeFuncPointingToFunctionsSectionWhen
|
||||
std::unordered_map<uint32_t, std::string> sectionNames;
|
||||
sectionNames[0] = ".text.abc";
|
||||
sectionNames[1] = functionsSectionName.str();
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.overrideSymbolName = true;
|
||||
|
||||
elf64.addSymbol(0, 0, 32, 1, Elf::STT_FUNC, Elf::STB_GLOBAL);
|
||||
@@ -479,7 +479,7 @@ TEST(LinkerInputTests, GivenGlobalSymbolOfTypeDifferentThantObjectOrFuncWhenDeco
|
||||
std::unordered_map<uint32_t, std::string> sectionNames;
|
||||
sectionNames[0] = ".text.abc";
|
||||
sectionNames[1] = ".data.const";
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.overrideSymbolName = true;
|
||||
|
||||
elf64.addSymbol(0, 0, 8, 0, Elf::STT_NOTYPE, Elf::STB_GLOBAL);
|
||||
@@ -490,21 +490,24 @@ TEST(LinkerInputTests, GivenGlobalSymbolOfTypeDifferentThantObjectOrFuncWhenDeco
|
||||
EXPECT_EQ(0U, linkerInput.getSymbols().size());
|
||||
}
|
||||
|
||||
TEST(LinkerInputTests, GivenGlobalSymbolPointingToSectionDifferentThanInstructionsOrDataWhenDecodingElfThenItIsIgnored) {
|
||||
TEST(LinkerInputTests, GivenGlobalSymbolPointingToSectionDifferentThanInstructionsOrDataWhenDecodingElfThenItIsIgnoredAndAddedToExternalSymbols) {
|
||||
MockElf<NEO::Elf::EI_CLASS_64> elf64;
|
||||
|
||||
std::unordered_map<uint32_t, std::string> sectionNames;
|
||||
sectionNames[0] = ""; // UNDEF section
|
||||
sectionNames[1] = ".text.abc";
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.overrideSymbolName = true;
|
||||
|
||||
elf64.addSymbol(0, 0, 8, 0, Elf::STT_OBJECT, Elf::STB_GLOBAL);
|
||||
constexpr uint32_t externalSymbol = 3;
|
||||
elf64.addSymbol(externalSymbol, 0, 8, 0, Elf::STT_OBJECT, Elf::STB_GLOBAL);
|
||||
WhiteBox<NEO::LinkerInput> linkerInput;
|
||||
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId = {{"abc", 0}};
|
||||
NEO::LinkerInput linkerInput = {};
|
||||
linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId);
|
||||
EXPECT_TRUE(linkerInput.isValid());
|
||||
EXPECT_EQ(0U, linkerInput.getSymbols().size());
|
||||
EXPECT_EQ(1U, linkerInput.externalSymbols.size());
|
||||
EXPECT_EQ(std::to_string(externalSymbol), linkerInput.externalSymbols[0]);
|
||||
}
|
||||
|
||||
TEST(LInkerInputTests, GivenSymbolPointingToInstructionSegmentAndInvalidInstructionSectionNameMappingWhenDecodingElfThenLinkerInputIsInvalid) {
|
||||
@@ -513,7 +516,7 @@ TEST(LInkerInputTests, GivenSymbolPointingToInstructionSegmentAndInvalidInstruct
|
||||
|
||||
std::unordered_map<uint32_t, std::string> sectionNames;
|
||||
sectionNames[0] = ".text.abc";
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.overrideSymbolName = true;
|
||||
|
||||
elf64.addSymbol(0, 0, 8, 0, Elf::STT_FUNC, Elf::STB_GLOBAL);
|
||||
@@ -532,7 +535,7 @@ TEST(LinkerInputTests, GivenInstructionRelocationAndInvalidInstructionSectionNam
|
||||
sectionNames[0] = ".text.abc";
|
||||
sectionNames[1] = ".data.const";
|
||||
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.addReloc(64, 0, Zebin::Elf::R_ZE_SYM_ADDR, 0, 0, "0");
|
||||
|
||||
elf64.overrideSymbolName = true;
|
||||
@@ -548,7 +551,7 @@ TEST(LinkerInputTests, GivenRelocationWithSymbolIdOutOfBoundsOfSymbolTableWhenDe
|
||||
MockElf<NEO::Elf::EI_CLASS_64> elf64;
|
||||
|
||||
std::unordered_map<uint32_t, std::string> sectionNames = {{0, ".text.abc"}};
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
|
||||
elf64.addReloc(64, 0, Zebin::Elf::R_ZE_SYM_ADDR, 0, 2, "symbol");
|
||||
|
||||
@@ -564,7 +567,7 @@ TEST(LinkerInputTests, GivenRelocationToSectionDifferentThanDataOrInstructionsWh
|
||||
|
||||
std::unordered_map<uint32_t, std::string> sectionNames = {{0, ".text.abc"},
|
||||
{1, "unknown.section"}};
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.addReloc(64, 0, Zebin::Elf::R_ZE_SYM_ADDR, 1, 2, "symbol");
|
||||
|
||||
NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId;
|
||||
@@ -584,7 +587,7 @@ TEST(LinkerInputTests, GivenGlobalDataRelocationWithLocalSymbolPointingToConstDa
|
||||
sectionNames[1] = ".data.const";
|
||||
sectionNames[2] = ".data.global";
|
||||
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.addReloc(64, 10, Zebin::Elf::R_ZE_SYM_ADDR, 2, 0, "0");
|
||||
|
||||
elf64.overrideSymbolName = true;
|
||||
@@ -617,7 +620,7 @@ TEST(LinkerInputTests, GivenInstructionRelocationWithLocalSymbolPointingToFuncti
|
||||
sectionNames[0] = ".text.abc";
|
||||
sectionNames[1] = functionsSectionName.str();
|
||||
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
elf64.addReloc(64, 10, Zebin::Elf::R_ZE_SYM_ADDR, 0, 0, "0");
|
||||
|
||||
elf64.overrideSymbolName = true;
|
||||
@@ -791,7 +794,7 @@ TEST(LinkerInputTests, GivenExternalFunctionsSymbolsUsedInKernelRelocationsWhenP
|
||||
EXPECT_EQ(kernelName, mockLinkerInput.kernelDependencies[0].kernelName);
|
||||
}
|
||||
|
||||
TEST(LinkerInputTests, GivenNonFunctionRelocationInKernelRelocationsWhenParsingRelocationsForExtFuncUsageForKernelThenDoNotAddKernelDependency) {
|
||||
TEST(LinkerInputTests, GivenNonFunctionSymbolRelocationInKernelRelocationsWhenParsingRelocationsForExtFuncUsageForKernelThenDoNotAddKernelDependency) {
|
||||
WhiteBox<NEO::LinkerInput> mockLinkerInput;
|
||||
|
||||
auto &symbols = mockLinkerInput.symbols;
|
||||
@@ -806,11 +809,8 @@ TEST(LinkerInputTests, GivenNonFunctionRelocationInKernelRelocationsWhenParsingR
|
||||
symbols.emplace("fun", symbol2);
|
||||
|
||||
for (auto nonFuncRelocationName : {
|
||||
implicitArgsRelocationSymbolName,
|
||||
std::string_view(".str"),
|
||||
std::string_view("globalVar"),
|
||||
Linker::perThreadOff,
|
||||
Linker::subDeviceID,
|
||||
std::string_view("")}) {
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo{};
|
||||
@@ -822,6 +822,35 @@ TEST(LinkerInputTests, GivenNonFunctionRelocationInKernelRelocationsWhenParsingR
|
||||
EXPECT_EQ(0u, mockLinkerInput.kernelDependencies.size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LinkerInputTests, GivenExternalSymbolRelocationInKernelRelocationsWhenParsingRelocationsForExtFuncUsageForKernelThenAddOptionalKernelDependency) {
|
||||
WhiteBox<NEO::LinkerInput> mockLinkerInput;
|
||||
|
||||
auto &externalSymbols = mockLinkerInput.externalSymbols;
|
||||
|
||||
externalSymbols.push_back(std::string(implicitArgsRelocationSymbolName));
|
||||
externalSymbols.push_back(std::string(Linker::perThreadOff));
|
||||
externalSymbols.push_back(std::string(Linker::subDeviceID));
|
||||
|
||||
for (auto relocationName : {
|
||||
implicitArgsRelocationSymbolName,
|
||||
Linker::perThreadOff,
|
||||
Linker::subDeviceID}) {
|
||||
|
||||
NEO::LinkerInput::RelocationInfo relocInfo{};
|
||||
relocInfo.symbolName = relocationName;
|
||||
|
||||
std::string kernelName = "kernel";
|
||||
mockLinkerInput.parseRelocationForExtFuncUsage(relocInfo, kernelName);
|
||||
EXPECT_TRUE(mockLinkerInput.extFunDependencies.empty());
|
||||
}
|
||||
|
||||
EXPECT_EQ(3u, mockLinkerInput.kernelDependencies.size());
|
||||
for (auto &kernelDependency : mockLinkerInput.kernelDependencies) {
|
||||
EXPECT_TRUE(kernelDependency.optional);
|
||||
}
|
||||
}
|
||||
|
||||
HWTEST_F(LinkerTests, givenEmptyLinkerInputThenLinkerOutputIsEmpty) {
|
||||
NEO::LinkerInput linkerInput;
|
||||
NEO::Linker linker(linkerInput);
|
||||
@@ -2140,7 +2169,7 @@ TEST_F(LinkerTests, GivenDebugDataWhenApplyingDebugDataRelocationsThenRelocation
|
||||
sectionNames[4] = ".debug_line";
|
||||
sectionNames[5] = ".data.const";
|
||||
|
||||
elf64.setupSecionNames(std::move(sectionNames));
|
||||
elf64.setupSectionNames(std::move(sectionNames));
|
||||
|
||||
NEO::Elf::Elf<NEO::Elf::EI_CLASS_64>::RelocationInfo reloc0 = {};
|
||||
reloc0.offset = 64;
|
||||
|
||||
Reference in New Issue
Block a user