/* * Copyright (C) 2020 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/source/device_binary_format/elf/elf_encoder.h" #include "shared/source/utilities/range.h" #include namespace NEO { namespace Elf { template ElfEncoder::ElfEncoder(bool addUndefSectionHeader, bool addHeaderSectionNamesSection, uint64_t defaultDataAlignemnt) : addUndefSectionHeader(addUndefSectionHeader), addHeaderSectionNamesSection(addHeaderSectionNamesSection), defaultDataAlignment(defaultDataAlignemnt) { // add special strings UNRECOVERABLE_IF(defaultDataAlignment == 0); stringTable.push_back('\0'); specialStringsOffsets.undef = 0U; specialStringsOffsets.shStrTab = this->appendSectionName(SpecialSectionNames::shStrTab); if (addUndefSectionHeader) { ElfSectionHeader undefSection; sectionHeaders.push_back(undefSection); } } template void ElfEncoder::appendSection(const ElfSectionHeader §ionHeader, const ArrayRef sectionData) { sectionHeaders.push_back(sectionHeader); if ((SHT_NOBITS != sectionHeader.type) && (false == sectionData.empty())) { auto sectionDataAlignment = std::min(defaultDataAlignment, 8U); auto alignedOffset = alignUp(this->data.size(), static_cast(sectionDataAlignment)); auto alignedSize = alignUp(sectionData.size(), static_cast(sectionDataAlignment)); this->data.reserve(alignedOffset + alignedSize); this->data.resize(alignedOffset, 0U); this->data.insert(this->data.end(), sectionData.begin(), sectionData.end()); this->data.resize(alignedOffset + alignedSize, 0U); sectionHeaders.rbegin()->offset = static_castoffset)>(alignedOffset); sectionHeaders.rbegin()->size = static_castsize)>(sectionData.size()); } } template void ElfEncoder::appendSegment(const ElfProgramHeader &programHeader, const ArrayRef segmentData) { maxDataAlignmentNeeded = std::max(maxDataAlignmentNeeded, static_cast(programHeader.align)); programHeaders.push_back(programHeader); if (false == segmentData.empty()) { UNRECOVERABLE_IF(programHeader.align == 0); auto alignedOffset = alignUp(this->data.size(), static_cast(programHeader.align)); auto alignedSize = alignUp(segmentData.size(), static_cast(programHeader.align)); this->data.reserve(alignedOffset + alignedSize); this->data.resize(alignedOffset, 0U); this->data.insert(this->data.end(), segmentData.begin(), segmentData.end()); this->data.resize(alignedOffset + alignedSize, 0U); programHeaders.rbegin()->offset = static_castoffset)>(alignedOffset); programHeaders.rbegin()->fileSz = static_castfileSz)>(segmentData.size()); } } template ElfSectionHeader &ElfEncoder::appendSection(SECTION_HEADER_TYPE sectionType, ConstStringRef sectionLabel, const ArrayRef sectionData) { ElfSectionHeader section = {}; section.type = static_cast(sectionType); section.flags = static_cast(SHF_NONE); section.offset = 0U; section.name = appendSectionName(sectionLabel); section.addralign = 8U; appendSection(section, sectionData); return *sectionHeaders.rbegin(); } template ElfProgramHeader &ElfEncoder::appendSegment(PROGRAM_HEADER_TYPE segmentType, const ArrayRef segmentData) { ElfProgramHeader segment = {}; segment.type = static_cast(segmentType); segment.flags = static_cast(PF_NONE); segment.offset = 0U; segment.align = static_cast(defaultDataAlignment); appendSegment(segment, segmentData); return *programHeaders.rbegin(); } template uint32_t ElfEncoder::appendSectionName(ConstStringRef str) { if (str.empty() || (false == addHeaderSectionNamesSection)) { return specialStringsOffsets.undef; } uint32_t offset = static_cast(stringTable.size()); stringTable.insert(stringTable.end(), str.begin(), str.end()); if (str[str.size() - 1] != '\0') { stringTable.push_back('\0'); } return offset; } template std::vector ElfEncoder::encode() const { ElfFileHeader elfFileHeader = this->elfFileHeader; StackVec, 32> programHeaders = this->programHeaders; StackVec, 32> sectionHeaders = this->sectionHeaders; if (addUndefSectionHeader && (1U == sectionHeaders.size())) { sectionHeaders.clear(); } ElfSectionHeader sectionHeaderNamesSection; size_t alignedSectionNamesDataSize = 0U; size_t dataPaddingBeforeSectionNames = 0U; if ((false == sectionHeaders.empty()) && addHeaderSectionNamesSection) { auto alignedDataSize = alignUp(data.size(), static_cast(defaultDataAlignment)); dataPaddingBeforeSectionNames = alignedDataSize - data.size(); sectionHeaderNamesSection.type = SHT_STRTAB; sectionHeaderNamesSection.name = specialStringsOffsets.shStrTab; sectionHeaderNamesSection.offset = static_cast(alignedDataSize); sectionHeaderNamesSection.size = static_cast(stringTable.size()); sectionHeaderNamesSection.addralign = static_cast(defaultDataAlignment); elfFileHeader.shStrNdx = static_cast(sectionHeaders.size()); sectionHeaders.push_back(sectionHeaderNamesSection); alignedSectionNamesDataSize = alignUp(stringTable.size(), static_cast(sectionHeaderNamesSection.addralign)); } elfFileHeader.phNum = static_cast(programHeaders.size()); elfFileHeader.shNum = static_cast(sectionHeaders.size()); auto programHeadersOffset = elfFileHeader.ehSize; auto sectionHeadersOffset = programHeadersOffset + elfFileHeader.phEntSize * elfFileHeader.phNum; if (false == programHeaders.empty()) { elfFileHeader.phOff = static_cast(programHeadersOffset); } if (false == sectionHeaders.empty()) { elfFileHeader.shOff = static_cast(sectionHeadersOffset); } auto dataOffset = alignUp(sectionHeadersOffset + elfFileHeader.shEntSize * elfFileHeader.shNum, static_cast(maxDataAlignmentNeeded)); auto stringTabOffset = dataOffset + data.size(); std::vector ret; ret.reserve(stringTabOffset + alignedSectionNamesDataSize); ret.insert(ret.end(), reinterpret_cast(&elfFileHeader), reinterpret_cast(&elfFileHeader + 1)); ret.resize(programHeadersOffset, 0U); for (auto &programHeader : programHeaders) { if (0 != programHeader.fileSz) { programHeader.offset = static_cast(programHeader.offset + dataOffset); } ret.insert(ret.end(), reinterpret_cast(&programHeader), reinterpret_cast(&programHeader + 1)); ret.resize(ret.size() + elfFileHeader.phEntSize - sizeof(programHeader), 0U); } for (auto §ionHeader : sectionHeaders) { if ((SHT_NOBITS != sectionHeader.type) && (0 != sectionHeader.size)) { sectionHeader.offset = static_cast(sectionHeader.offset + dataOffset); } ret.insert(ret.end(), reinterpret_cast(§ionHeader), reinterpret_cast(§ionHeader + 1)); ret.resize(ret.size() + elfFileHeader.shEntSize - sizeof(sectionHeader), 0U); } ret.resize(dataOffset, 0U); ret.insert(ret.end(), data.begin(), data.end()); ret.resize(ret.size() + dataPaddingBeforeSectionNames, 0U); ret.insert(ret.end(), reinterpret_cast(stringTable.data()), reinterpret_cast(stringTable.data() + static_cast(sectionHeaderNamesSection.size))); ret.resize(ret.size() + alignedSectionNamesDataSize - static_cast(sectionHeaderNamesSection.size), 0U); return ret; } template struct ElfEncoder; template struct ElfEncoder; } // namespace Elf } // namespace NEO