compute-runtime/runtime/program/process_elf_binary.cpp

165 lines
6.5 KiB
C++

/*
* Copyright (C) 2017-2019 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "common/compiler_support.h"
#include "core/elf/reader.h"
#include "core/elf/writer.h"
#include "core/helpers/string.h"
#include "program.h"
namespace NEO {
cl_int Program::processElfBinary(
const void *pBinary,
size_t binarySize,
uint32_t &binaryVersion) {
const CLElfLib::SElf64Header *pElfHeader = nullptr;
binaryVersion = iOpenCL::CURRENT_ICBE_VERSION;
elfBinarySize = binarySize;
elfBinary = CLElfLib::ElfBinaryStorage(reinterpret_cast<const char *>(pBinary), reinterpret_cast<const char *>(reinterpret_cast<const char *>(pBinary) + binarySize));
try {
CLElfLib::CElfReader elfReader(elfBinary);
pElfHeader = elfReader.getElfHeader();
switch (pElfHeader->Type) {
case CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE:
programBinaryType = CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
break;
case CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY:
programBinaryType = CL_PROGRAM_BINARY_TYPE_LIBRARY;
break;
case CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_OBJECTS:
programBinaryType = CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT;
break;
default:
return CL_INVALID_BINARY;
}
// section 0 is always null
for (size_t i = 1u; i < elfReader.getSectionHeaders().size(); ++i) {
const auto &sectionHeader = elfReader.getSectionHeaders()[i];
switch (sectionHeader.Type) {
case CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV:
this->isSpirV = true;
CPP_ATTRIBUTE_FALLTHROUGH;
case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY:
if (sectionHeader.DataSize > 0) {
this->irBinary = makeCopy(elfReader.getSectionData(sectionHeader.DataOffset), static_cast<size_t>(sectionHeader.DataSize));
this->irBinarySize = static_cast<size_t>(sectionHeader.DataSize);
}
break;
case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY:
if (sectionHeader.DataSize > 0 && validateGenBinaryHeader(reinterpret_cast<SProgramBinaryHeader *>(elfReader.getSectionData(sectionHeader.DataOffset)))) {
this->genBinary = makeCopy(elfReader.getSectionData(sectionHeader.DataOffset), static_cast<size_t>(sectionHeader.DataSize));
this->genBinarySize = static_cast<size_t>(sectionHeader.DataSize);
isCreatedFromBinary = true;
} else {
getProgramCompilerVersion(reinterpret_cast<SProgramBinaryHeader *>(elfReader.getSectionData(sectionHeader.DataOffset)), binaryVersion);
return CL_INVALID_BINARY;
}
break;
case CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS:
if (sectionHeader.DataSize > 0) {
options = std::string(elfReader.getSectionData(sectionHeader.DataOffset), static_cast<size_t>(sectionHeader.DataSize));
}
break;
case CLElfLib::E_SH_TYPE::SH_TYPE_STR_TBL:
// We can skip the string table
break;
default:
return CL_INVALID_BINARY;
}
}
isProgramBinaryResolved = true;
// Create an empty build log since program is effectively built
updateBuildLog(pDevice, "", 1);
} catch (const CLElfLib::ElfException &) {
return CL_INVALID_BINARY;
}
return CL_SUCCESS;
}
cl_int Program::resolveProgramBinary() {
CLElfLib::E_EH_TYPE headerType;
if (isProgramBinaryResolved == false) {
elfBinary.clear();
elfBinarySize = 0;
switch (programBinaryType) {
case CL_PROGRAM_BINARY_TYPE_EXECUTABLE:
headerType = CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_EXECUTABLE;
if (!genBinary || !genBinarySize) {
return CL_INVALID_BINARY;
}
break;
case CL_PROGRAM_BINARY_TYPE_LIBRARY:
headerType = CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY;
if (!irBinary || !irBinarySize) {
return CL_INVALID_BINARY;
}
break;
case CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT:
headerType = CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_OBJECTS;
if (!irBinary || !irBinarySize) {
return CL_INVALID_BINARY;
}
break;
default:
return CL_INVALID_BINARY;
}
CLElfLib::CElfWriter elfWriter(headerType, CLElfLib::E_EH_MACHINE::EH_MACHINE_NONE, 0);
elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_OPTIONS, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "BuildOptions", options, static_cast<uint32_t>(strlen(options.c_str()) + 1u)));
std::string irBinaryTemp = irBinary ? std::string(irBinary.get(), irBinarySize) : "";
// Add the LLVM component if available
elfWriter.addSection(CLElfLib::SSectionNode(getIsSpirV() ? CLElfLib::E_SH_TYPE::SH_TYPE_SPIRV : CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_LLVM_BINARY, CLElfLib::E_SH_FLAG::SH_FLAG_NONE,
headerType == CLElfLib::E_EH_TYPE::EH_TYPE_OPENCL_LIBRARY ? "Intel(R) OpenCL LLVM Archive" : "Intel(R) OpenCL LLVM Object", std::move(irBinaryTemp), static_cast<uint32_t>(irBinarySize)));
// Add the device binary if it exists
if (genBinary) {
std::string genBinaryTemp = genBinary ? std::string(genBinary.get(), genBinarySize) : "";
elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_BINARY, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "Intel(R) OpenCL Device Binary", std::move(genBinaryTemp), static_cast<uint32_t>(genBinarySize)));
}
// Add the device debug data if it exists
if (debugData != nullptr) {
std::string debugDataTemp = debugData ? std::string(debugData.get(), debugDataSize) : "";
elfWriter.addSection(CLElfLib::SSectionNode(CLElfLib::E_SH_TYPE::SH_TYPE_OPENCL_DEV_DEBUG, CLElfLib::E_SH_FLAG::SH_FLAG_NONE, "Intel(R) OpenCL Device Debug", std::move(debugDataTemp), static_cast<uint32_t>(debugDataSize)));
}
elfBinarySize = elfWriter.getTotalBinarySize();
elfBinary = CLElfLib::ElfBinaryStorage(elfBinarySize);
elfWriter.resolveBinary(elfBinary);
isProgramBinaryResolved = true;
} else {
return CL_OUT_OF_HOST_MEMORY;
}
return CL_SUCCESS;
}
} // namespace NEO