2019-07-04 23:14:51 +08:00
|
|
|
/*
|
2022-01-11 02:32:25 +08:00
|
|
|
* Copyright (C) 2019-2022 Intel Corporation
|
2019-07-04 23:14:51 +08:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
2021-01-20 00:29:20 +08:00
|
|
|
#include "shared/source/device_binary_format/elf/elf_decoder.h"
|
2019-07-04 23:14:51 +08:00
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
#include <limits>
|
|
|
|
#include <string>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace NEO {
|
|
|
|
|
2020-07-14 22:44:28 +08:00
|
|
|
class Device;
|
|
|
|
class GraphicsAllocation;
|
2021-11-15 22:06:31 +08:00
|
|
|
struct KernelDescriptor;
|
2020-07-14 22:44:28 +08:00
|
|
|
|
2020-01-12 01:25:26 +08:00
|
|
|
enum class SegmentType : uint32_t {
|
|
|
|
Unknown,
|
|
|
|
GlobalConstants,
|
2021-11-02 23:29:09 +08:00
|
|
|
GlobalStrings,
|
2020-01-12 01:25:26 +08:00
|
|
|
GlobalVariables,
|
|
|
|
Instructions,
|
|
|
|
};
|
|
|
|
|
2020-07-14 00:42:11 +08:00
|
|
|
enum class LinkingStatus : uint32_t {
|
|
|
|
Error,
|
|
|
|
LinkedFully,
|
|
|
|
LinkedPartially
|
|
|
|
};
|
|
|
|
|
2020-01-12 01:25:26 +08:00
|
|
|
inline const char *asString(SegmentType segment) {
|
|
|
|
switch (segment) {
|
|
|
|
default:
|
|
|
|
return "UNKOWN";
|
|
|
|
case SegmentType::GlobalConstants:
|
|
|
|
return "GLOBAL_CONSTANTS";
|
|
|
|
case SegmentType::GlobalVariables:
|
|
|
|
return "GLOBAL_VARIABLES";
|
|
|
|
case SegmentType::Instructions:
|
|
|
|
return "INSTRUCTIONS";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 23:14:51 +08:00
|
|
|
struct SymbolInfo {
|
|
|
|
uint32_t offset = std::numeric_limits<uint32_t>::max();
|
|
|
|
uint32_t size = std::numeric_limits<uint32_t>::max();
|
2020-01-12 01:25:26 +08:00
|
|
|
SegmentType segment = SegmentType::Unknown;
|
2019-07-04 23:14:51 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct LinkerInput {
|
|
|
|
union Traits {
|
2020-01-12 01:25:26 +08:00
|
|
|
enum PointerSize : uint8_t {
|
|
|
|
Ptr32bit = 0,
|
|
|
|
Ptr64bit = 1
|
|
|
|
};
|
2019-07-04 23:14:51 +08:00
|
|
|
Traits() : packed(0) {
|
2020-01-12 01:25:26 +08:00
|
|
|
pointerSize = (sizeof(void *) == 4) ? PointerSize::Ptr32bit : PointerSize::Ptr64bit;
|
2019-07-04 23:14:51 +08:00
|
|
|
}
|
|
|
|
struct {
|
|
|
|
bool exportsGlobalVariables : 1;
|
|
|
|
bool exportsGlobalConstants : 1;
|
|
|
|
bool exportsFunctions : 1;
|
|
|
|
bool requiresPatchingOfInstructionSegments : 1;
|
2020-01-12 01:25:26 +08:00
|
|
|
bool requiresPatchingOfGlobalVariablesBuffer : 1;
|
|
|
|
bool requiresPatchingOfGlobalConstantsBuffer : 1;
|
|
|
|
uint8_t pointerSize : 1;
|
2019-07-04 23:14:51 +08:00
|
|
|
};
|
|
|
|
uint32_t packed;
|
|
|
|
};
|
|
|
|
static_assert(sizeof(Traits) == sizeof(Traits::packed), "");
|
|
|
|
|
|
|
|
struct RelocationInfo {
|
2019-11-26 05:43:21 +08:00
|
|
|
enum class Type : uint32_t {
|
|
|
|
Unknown,
|
|
|
|
Address,
|
2020-09-07 08:28:32 +08:00
|
|
|
AddressLow,
|
2021-07-15 20:03:00 +08:00
|
|
|
AddressHigh,
|
|
|
|
PerThreadPayloadOffset,
|
|
|
|
RelocTypeMax
|
2019-11-26 05:43:21 +08:00
|
|
|
};
|
|
|
|
|
2019-07-04 23:14:51 +08:00
|
|
|
std::string symbolName;
|
2020-01-12 01:25:26 +08:00
|
|
|
uint64_t offset = std::numeric_limits<uint64_t>::max();
|
2019-11-26 05:43:21 +08:00
|
|
|
Type type = Type::Unknown;
|
2020-01-12 01:25:26 +08:00
|
|
|
SegmentType relocationSegment = SegmentType::Unknown;
|
2019-07-04 23:14:51 +08:00
|
|
|
};
|
2021-01-20 00:29:20 +08:00
|
|
|
using SectionNameToSegmentIdMap = std::unordered_map<std::string, uint32_t>;
|
2019-07-04 23:14:51 +08:00
|
|
|
using Relocations = std::vector<RelocationInfo>;
|
|
|
|
using SymbolMap = std::unordered_map<std::string, SymbolInfo>;
|
|
|
|
using RelocationsPerInstSegment = std::vector<Relocations>;
|
|
|
|
|
2020-01-12 01:25:26 +08:00
|
|
|
virtual ~LinkerInput() = default;
|
|
|
|
|
2021-01-20 00:29:20 +08:00
|
|
|
static SegmentType getSegmentForSection(ConstStringRef name);
|
|
|
|
|
2020-01-12 01:25:26 +08:00
|
|
|
MOCKABLE_VIRTUAL bool decodeGlobalVariablesSymbolTable(const void *data, uint32_t numEntries);
|
|
|
|
MOCKABLE_VIRTUAL bool decodeExportedFunctionsSymbolTable(const void *data, uint32_t numEntries, uint32_t instructionsSegmentId);
|
|
|
|
MOCKABLE_VIRTUAL bool decodeRelocationTable(const void *data, uint32_t numEntries, uint32_t instructionsSegmentId);
|
|
|
|
void addDataRelocationInfo(const RelocationInfo &relocationInfo);
|
2019-07-04 23:14:51 +08:00
|
|
|
|
2021-01-20 00:29:20 +08:00
|
|
|
void addElfTextSegmentRelocation(RelocationInfo relocationInfo, uint32_t instructionsSegmentId);
|
|
|
|
void decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64> &elf, const SectionNameToSegmentIdMap &nameToSegmentId);
|
|
|
|
|
2019-07-04 23:14:51 +08:00
|
|
|
const Traits &getTraits() const {
|
|
|
|
return traits;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t getExportedFunctionsSegmentId() const {
|
|
|
|
return exportedFunctionsSegmentId;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SymbolMap &getSymbols() const {
|
|
|
|
return symbols;
|
|
|
|
}
|
|
|
|
|
2021-08-19 19:28:34 +08:00
|
|
|
void addSymbol(const std::string &symbolName, const SymbolInfo &symbolInfo) {
|
|
|
|
symbols.emplace(std::make_pair(symbolName, symbolInfo));
|
|
|
|
}
|
|
|
|
|
2020-01-12 01:25:26 +08:00
|
|
|
const RelocationsPerInstSegment &getRelocationsInInstructionSegments() const {
|
2019-07-04 23:14:51 +08:00
|
|
|
return relocations;
|
|
|
|
}
|
|
|
|
|
2020-01-12 01:25:26 +08:00
|
|
|
const Relocations &getDataRelocations() const {
|
|
|
|
return dataRelocations;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setPointerSize(Traits::PointerSize pointerSize) {
|
|
|
|
traits.pointerSize = pointerSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isValid() const {
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
2021-07-10 04:00:18 +08:00
|
|
|
bool undefinedSymbolsAllowed = false;
|
|
|
|
|
2019-07-04 23:14:51 +08:00
|
|
|
protected:
|
|
|
|
Traits traits;
|
|
|
|
SymbolMap symbols;
|
|
|
|
RelocationsPerInstSegment relocations;
|
2020-01-12 01:25:26 +08:00
|
|
|
Relocations dataRelocations;
|
2019-07-04 23:14:51 +08:00
|
|
|
int32_t exportedFunctionsSegmentId = -1;
|
2020-01-12 01:25:26 +08:00
|
|
|
bool valid = true;
|
2019-07-04 23:14:51 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Linker {
|
2022-01-11 02:32:25 +08:00
|
|
|
inline static const std::string subDeviceID = "__SubDeviceID";
|
|
|
|
|
2019-07-04 23:14:51 +08:00
|
|
|
using RelocationInfo = LinkerInput::RelocationInfo;
|
|
|
|
|
2020-01-12 01:25:26 +08:00
|
|
|
struct SegmentInfo {
|
2019-07-04 23:14:51 +08:00
|
|
|
uintptr_t gpuAddress = std::numeric_limits<uintptr_t>::max();
|
|
|
|
size_t segmentSize = std::numeric_limits<size_t>::max();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PatchableSegment {
|
|
|
|
void *hostPointer = nullptr;
|
|
|
|
size_t segmentSize = std::numeric_limits<size_t>::max();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct UnresolvedExternal {
|
|
|
|
RelocationInfo unresolvedRelocation;
|
|
|
|
uint32_t instructionsSegmentId = std::numeric_limits<uint32_t>::max();
|
|
|
|
bool internalError = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct RelocatedSymbol {
|
|
|
|
SymbolInfo symbol;
|
|
|
|
uintptr_t gpuAddress = std::numeric_limits<uintptr_t>::max();
|
|
|
|
};
|
|
|
|
|
|
|
|
using RelocatedSymbolsMap = std::unordered_map<std::string, RelocatedSymbol>;
|
|
|
|
using PatchableSegments = std::vector<PatchableSegment>;
|
|
|
|
using UnresolvedExternals = std::vector<UnresolvedExternal>;
|
2021-11-15 22:06:31 +08:00
|
|
|
using KernelDescriptorsT = std::vector<KernelDescriptor *>;
|
2019-07-04 23:14:51 +08:00
|
|
|
|
|
|
|
Linker(const LinkerInput &data)
|
|
|
|
: data(data) {
|
|
|
|
}
|
|
|
|
|
2021-11-02 23:29:09 +08:00
|
|
|
LinkingStatus link(const SegmentInfo &globalVariablesSegInfo, const SegmentInfo &globalConstantsSegInfo, const SegmentInfo &exportedFunctionsSegInfo, const SegmentInfo &globalStringsSegInfo,
|
2020-07-14 00:42:11 +08:00
|
|
|
GraphicsAllocation *globalVariablesSeg, GraphicsAllocation *globalConstantsSeg, const PatchableSegments &instructionsSegments,
|
2021-11-15 22:06:31 +08:00
|
|
|
UnresolvedExternals &outUnresolvedExternals, Device *pDevice, const void *constantsInitData, const void *variablesInitData, const KernelDescriptorsT &kernelDescriptors) {
|
2020-01-12 01:25:26 +08:00
|
|
|
bool success = data.isValid();
|
2020-07-14 00:42:11 +08:00
|
|
|
auto initialUnresolvedExternalsCount = outUnresolvedExternals.size();
|
2021-11-02 23:29:09 +08:00
|
|
|
success = success && processRelocations(globalVariablesSegInfo, globalConstantsSegInfo, exportedFunctionsSegInfo, globalStringsSegInfo);
|
2020-07-14 00:42:11 +08:00
|
|
|
if (!success) {
|
|
|
|
return LinkingStatus::Error;
|
|
|
|
}
|
|
|
|
patchInstructionsSegments(instructionsSegments, outUnresolvedExternals);
|
|
|
|
patchDataSegments(globalVariablesSegInfo, globalConstantsSegInfo, globalVariablesSeg, globalConstantsSeg,
|
|
|
|
outUnresolvedExternals, pDevice, constantsInitData, variablesInitData);
|
2021-11-15 22:06:31 +08:00
|
|
|
resolveImplicitArgs(kernelDescriptors, pDevice);
|
2022-01-11 02:32:25 +08:00
|
|
|
resolveBuiltins(pDevice, outUnresolvedExternals, instructionsSegments);
|
2020-07-14 00:42:11 +08:00
|
|
|
if (initialUnresolvedExternalsCount < outUnresolvedExternals.size()) {
|
|
|
|
return LinkingStatus::LinkedPartially;
|
|
|
|
}
|
|
|
|
return LinkingStatus::LinkedFully;
|
2019-07-04 23:14:51 +08:00
|
|
|
}
|
2020-07-14 21:40:00 +08:00
|
|
|
static void patchAddress(void *relocAddress, const RelocatedSymbol &symbol, const RelocationInfo &relocation);
|
2019-07-04 23:14:51 +08:00
|
|
|
RelocatedSymbolsMap extractRelocatedSymbols() {
|
|
|
|
return RelocatedSymbolsMap(std::move(relocatedSymbols));
|
|
|
|
}
|
|
|
|
|
2021-02-09 22:57:16 +08:00
|
|
|
static void applyDebugDataRelocations(const NEO::Elf::Elf<NEO::Elf::EI_CLASS_64> &decodedElf, ArrayRef<uint8_t> inputOutputElf,
|
|
|
|
const SegmentInfo &text,
|
|
|
|
const SegmentInfo &globalData,
|
|
|
|
const SegmentInfo &constData);
|
|
|
|
|
2019-07-04 23:14:51 +08:00
|
|
|
protected:
|
|
|
|
const LinkerInput &data;
|
|
|
|
RelocatedSymbolsMap relocatedSymbols;
|
|
|
|
|
2021-11-02 23:29:09 +08:00
|
|
|
bool processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings);
|
2019-07-04 23:14:51 +08:00
|
|
|
|
2020-07-14 00:42:11 +08:00
|
|
|
void patchInstructionsSegments(const std::vector<PatchableSegment> &instructionsSegments, std::vector<UnresolvedExternal> &outUnresolvedExternals);
|
2020-01-12 01:25:26 +08:00
|
|
|
|
2020-07-14 00:42:11 +08:00
|
|
|
void patchDataSegments(const SegmentInfo &globalVariablesSegInfo, const SegmentInfo &globalConstantsSegInfo,
|
2020-07-14 22:44:28 +08:00
|
|
|
GraphicsAllocation *globalVariablesSeg, GraphicsAllocation *globalConstantsSeg,
|
|
|
|
std::vector<UnresolvedExternal> &outUnresolvedExternals, Device *pDevice,
|
|
|
|
const void *constantsInitData, const void *variablesInitData);
|
2020-10-07 21:32:03 +08:00
|
|
|
|
2021-11-15 22:06:31 +08:00
|
|
|
void resolveImplicitArgs(const KernelDescriptorsT &kernelDescriptors, Device *pDevice);
|
2022-01-11 02:32:25 +08:00
|
|
|
void resolveBuiltins(Device *pDevice, UnresolvedExternals &outUnresolvedExternals, const std::vector<PatchableSegment> &instructionsSegments);
|
2021-11-15 22:06:31 +08:00
|
|
|
|
2020-10-07 21:32:03 +08:00
|
|
|
template <typename PatchSizeT>
|
|
|
|
void patchIncrement(Device *pDevice, GraphicsAllocation *dstAllocation, size_t relocationOffset, const void *initData, uint64_t incrementValue);
|
2021-11-15 22:06:31 +08:00
|
|
|
|
|
|
|
std::unordered_map<uint32_t /*ISA segment id*/, uint32_t * /*implicit args relocation address to patch*/> pImplicitArgsRelocationAddresses;
|
2019-07-04 23:14:51 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
std::string constructLinkerErrorMessage(const Linker::UnresolvedExternals &unresolvedExternals, const std::vector<std::string> &instructionsSegmentsNames);
|
2020-04-28 20:00:15 +08:00
|
|
|
std::string constructRelocationsDebugMessage(const Linker::RelocatedSymbolsMap &relocatedSymbols);
|
2020-09-07 08:28:32 +08:00
|
|
|
constexpr bool shouldIgnoreRelocation(const LinkerInput::RelocationInfo &relocation) {
|
|
|
|
return LinkerInput::RelocationInfo::Type::PerThreadPayloadOffset == relocation.type;
|
|
|
|
}
|
2019-07-04 23:14:51 +08:00
|
|
|
|
|
|
|
} // namespace NEO
|