/* * Copyright (C) 2020-2022 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, typename ElfSectionHeaderTypes::AddrAlign defaultDataAlignemnt) : addUndefSectionHeader(addUndefSectionHeader), addHeaderSectionNamesSection(addHeaderSectionNamesSection), defaultDataAlignment(defaultDataAlignemnt) { // add special strings UNRECOVERABLE_IF(defaultDataAlignment == 0); shStrTabNameOffset = 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 uint32_t ElfEncoder::getSectionHeaderIndex(const ElfSectionHeader §ionHeader) { UNRECOVERABLE_IF(§ionHeader < sectionHeaders.begin()); UNRECOVERABLE_IF(§ionHeader >= sectionHeaders.begin() + sectionHeaders.size()); return static_cast(§ionHeader - &*sectionHeaders.begin()); } 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 = defaultDataAlignment; switch (sectionType) { case SHT_REL: section.entsize = sizeof(ElfRel); break; case SHT_RELA: section.entsize = sizeof(ElfRela); break; case SHT_SYMTAB: section.entsize = sizeof(ElfSymbolEntry); break; default: break; } 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 void ElfEncoder::appendProgramHeaderLoad(size_t sectionId, uint64_t vAddr, uint64_t segSize) { programSectionLookupTable.push_back({programHeaders.size(), sectionId}); auto &programHeader = appendSegment(PROGRAM_HEADER_TYPE::PT_LOAD, {}); programHeader.vAddr = static_cast(vAddr); programHeader.memSz = static_cast(segSize); } template uint32_t ElfEncoder::appendSectionName(ConstStringRef str) { if (false == addHeaderSectionNamesSection) { return strSecBuilder.undef(); } return strSecBuilder.appendString(str); } 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 = shStrTabNameOffset; sectionHeaderNamesSection.offset = static_cast(alignedDataSize); sectionHeaderNamesSection.size = static_cast(strSecBuilder.data().size()); sectionHeaderNamesSection.addralign = static_cast(defaultDataAlignment); elfFileHeader.shStrNdx = static_cast(sectionHeaders.size()); sectionHeaders.push_back(sectionHeaderNamesSection); alignedSectionNamesDataSize = alignUp(strSecBuilder.data().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 &progSecLookup : programSectionLookupTable) { programHeaders[progSecLookup.programId].offset = sectionHeaders[progSecLookup.sectionId].offset; programHeaders[progSecLookup.programId].fileSz = sectionHeaders[progSecLookup.sectionId].size; } std::sort(programHeaders.begin(), programHeaders.end(), [](auto &p1, auto &p2) { return p1.vAddr < p2.vAddr; }); 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); if (alignedSectionNamesDataSize > 0U) { auto sectionNames = strSecBuilder.data(); ret.insert(ret.end(), sectionNames.begin(), sectionNames.end()); } ret.resize(ret.size() + alignedSectionNamesDataSize - static_cast(sectionHeaderNamesSection.size), 0U); return ret; } template struct ElfEncoder; template struct ElfEncoder; } // namespace Elf } // namespace NEO