source: CLRX/CLRadeonExtender/trunk/amdbin/ROCmBinaries.cpp @ 4926

Last change on this file since 4926 was 4926, checked in by matszpk, 3 months ago

CLRadeonExtender: ROCm: Add stuff to handle LLVM10 ROCm binary format (kernel descriptors). Copy Amd3KernelDescriptor to ROCmBinary.h as ROCmKernelDescriptor.

File size: 32.7 KB
RevLine 
[2500]1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
[3575]3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
[2500]4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
[2536]21#include <cassert>
[3671]22#include <cstdio>
[3679]23#include <cstring>
[2500]24#include <cstdint>
[3679]25#include <string>
26#include <vector>
[2534]27#include <algorithm>
[2500]28#include <utility>
[4430]29#include <memory>
[3727]30#include <unordered_set>
[2534]31#include <CLRX/amdbin/ElfBinaries.h>
[2500]32#include <CLRX/utils/Utilities.h>
33#include <CLRX/utils/MemAccess.h>
[2534]34#include <CLRX/utils/InputOutput.h>
35#include <CLRX/utils/Containers.h>
[2500]36#include <CLRX/amdbin/ROCmBinaries.h>
37
38using namespace CLRX;
39
[3679]40
41/*
42 * ROCm binary reader and generator
43 */
44
[2535]45/* TODO: add support for various kernel code offset (now only 256 is supported) */
46
[2501]47ROCmBinary::ROCmBinary(size_t binaryCodeSize, cxbyte* binaryCode, Flags creationFlags)
[2502]48        : ElfBinary64(binaryCodeSize, binaryCode, creationFlags),
[3666]49          regionsNum(0), codeSize(0), code(nullptr),
50          globalDataSize(0), globalData(nullptr), metadataSize(0), metadata(nullptr),
[4926]51          newBinFormat(false), llvm10BinFormat(false), metadataV3Format(false)
[2500]52{
[2502]53    cxuint textIndex = SHN_UNDEF;
54    try
55    { textIndex = getSectionIndex(".text"); }
56    catch(const Exception& ex)
57    { } // ignore failed
[2506]58    uint64_t codeOffset = 0;
[3420]59    // find '.text' section
[2502]60    if (textIndex!=SHN_UNDEF)
61    {
62        code = getSectionContent(textIndex);
[2506]63        const Elf64_Shdr& textShdr = getSectionHeader(textIndex);
64        codeSize = ULEV(textShdr.sh_size);
65        codeOffset = ULEV(textShdr.sh_offset);
[2502]66    }
67   
[4926]68    if (getHeader().e_ident[EI_ABIVERSION] == 1)
69        llvm10BinFormat = true; // likely llvm10 bin format
70   
[3666]71    cxuint rodataIndex = SHN_UNDEF;
[4926]72    const cxbyte* rodataContent = nullptr;
[3666]73    try
74    { rodataIndex = getSectionIndex(".rodata"); }
75    catch(const Exception& ex)
76    { } // ignore failed
77    // find '.text' section
78    if (rodataIndex!=SHN_UNDEF)
79    {
[4926]80        rodataContent = globalData = getSectionContent(rodataIndex);
[3666]81        const Elf64_Shdr& rodataShdr = getSectionHeader(rodataIndex);
82        globalDataSize = ULEV(rodataShdr.sh_size);
83    }
84   
85    cxuint gpuConfigIndex = SHN_UNDEF;
86    try
87    { gpuConfigIndex = getSectionIndex(".AMDGPU.config"); }
88    catch(const Exception& ex)
89    { } // ignore failed
90    newBinFormat = (gpuConfigIndex == SHN_UNDEF);
91   
[3794]92    cxuint relaDynIndex = SHN_UNDEF;
93    try
94    { relaDynIndex = getSectionIndex(".rela.dyn"); }
95    catch(const Exception& ex)
96    { } // ignore failed
97   
98    cxuint gotIndex = SHN_UNDEF;
99    try
100    { gotIndex = getSectionIndex(".got"); }
101    catch(const Exception& ex)
102    { } // ignore failed
103   
[3420]104    // counts regions (symbol or kernel)
[4926]105    std::vector<std::pair<CString, size_t> > tmpKernelDescs;
[2518]106    regionsNum = 0;
[2502]107    const size_t symbolsNum = getSymbolsNum();
108    for (size_t i = 0; i < symbolsNum; i++)
[3396]109    {
110        // count regions number
[2502]111        const Elf64_Sym& sym = getSymbol(i);
[2518]112        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
[2530]113        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
[4926]114        Elf64_Half shndx = ULEV(sym.st_shndx);
115        if (shndx==textIndex &&
[4817]116            (symType==STT_GNU_IFUNC || (symType==STT_FUNC && !newBinFormat) ||
[2599]117                (bind==STB_GLOBAL && symType==STT_OBJECT)))
[2518]118            regionsNum++;
[4926]119        if (llvm10BinFormat && shndx==rodataIndex && symType==STT_OBJECT)
120        {
121            const char* symName = getSymbolName(i);
122            size_t symNameLen = ::strlen(symName);
123            // if symname have '.kd' at end
124            if (symNameLen > 3 && symName[symNameLen-3]=='.' &&
125                symName[symNameLen-2]=='k' && symName[symNameLen-1]=='d')
126                tmpKernelDescs.push_back({ CString(symName, symName+symNameLen-3),
127                            ULEV(sym.st_value) });
128        }
[2502]129    }
[4926]130    if (llvm10BinFormat)
131    {
132        if (rodataContent==nullptr)
133            throw BinException("No rodata section in ROCm LLVM10Bin format");
134        mapSort(tmpKernelDescs.begin(), tmpKernelDescs.end());
135        kernelDescs.resize(regionsNum);
136    }
137   
[2518]138    if (code==nullptr && regionsNum!=0)
[3457]139        throw BinException("No code if regions number is not zero");
[2518]140    regions.reset(new ROCmRegion[regionsNum]);
141    size_t j = 0;
142    typedef std::pair<uint64_t, size_t> RegionOffsetEntry;
143    std::unique_ptr<RegionOffsetEntry[]> symOffsets(new RegionOffsetEntry[regionsNum]);
[2504]144   
[3420]145    // get regions info
[2502]146    for (size_t i = 0; i < symbolsNum; i++)
147    {
148        const Elf64_Sym& sym = getSymbol(i);
[2579]149        if (ULEV(sym.st_shndx)!=textIndex)
[2530]150            continue;   // if not in '.text' section
[2502]151        const size_t value = ULEV(sym.st_value);
[2506]152        if (value < codeOffset)
[3457]153            throw BinException("Region offset is too small!");
[2504]154        const size_t size = ULEV(sym.st_size);
[2512]155       
[2518]156        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
[2530]157        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
[2599]158        if (symType==STT_GNU_IFUNC || symType==STT_FUNC ||
159                (bind==STB_GLOBAL && symType==STT_OBJECT))
[2519]160        {
[2599]161            ROCmRegionType type = ROCmRegionType::DATA;
[3420]162            // if kernel
[2599]163            if (symType==STT_GNU_IFUNC) 
164                type = ROCmRegionType::KERNEL;
[3420]165            // if function kernel
[2599]166            else if (symType==STT_FUNC)
[4817]167            {
168                if (newBinFormat)
169                    continue;
[2600]170                type = ROCmRegionType::FKERNEL;
[4817]171            }
[2518]172            symOffsets[j] = std::make_pair(value, j);
[2599]173            if (type!=ROCmRegionType::DATA && value+0x100 > codeOffset+codeSize)
[3457]174                throw BinException("Kernel or code offset is too big!");
[4926]175            const char* symName = getSymbolName(i);
176            regions[j++] = { symName, size, value, type };
177            if (llvm10BinFormat)
178            {
179                auto it = binaryMapFind(tmpKernelDescs.begin(), tmpKernelDescs.end(),
180                                        CString(symName));
181                if (it != tmpKernelDescs.end())
182                    kernelDescs[i] = reinterpret_cast<const ROCmKernelDescriptor*>(
183                                rodataContent + it->second);
184                else
185                    kernelDescs[i] = nullptr;
186            }
[2519]187        }
[2502]188    }
[3420]189    // sort regions by offset
[2518]190    std::sort(symOffsets.get(), symOffsets.get()+regionsNum,
191            [](const RegionOffsetEntry& a, const RegionOffsetEntry& b)
[2504]192            { return a.first < b.first; });
[2518]193    // checking distance between regions
194    for (size_t i = 1; i <= regionsNum; i++)
[2504]195    {
[2518]196        size_t end = (i<regionsNum) ? symOffsets[i].first : codeOffset+codeSize;
197        ROCmRegion& region = regions[symOffsets[i-1].second];
[2599]198        if (region.type==ROCmRegionType::KERNEL && symOffsets[i-1].first+0x100 > end)
[3457]199            throw BinException("Kernel size is too small!");
[2518]200       
[2533]201        const size_t regSize = end - symOffsets[i-1].first;
[2518]202        if (region.size==0)
203            region.size = regSize;
[2512]204        else
[2518]205            region.size = std::min(regSize, region.size);
[2504]206    }
[2503]207   
[3794]208    // load got symbols
209    if (relaDynIndex != SHN_UNDEF && gotIndex != SHN_UNDEF)
210    {
211        const Elf64_Shdr& relaShdr = getSectionHeader(relaDynIndex);
212        const Elf64_Shdr& gotShdr = getSectionHeader(gotIndex);
213       
214        size_t relaEntrySize = ULEV(relaShdr.sh_entsize);
215        if (relaEntrySize==0)
216            relaEntrySize = sizeof(Elf64_Rela);
217        const size_t relaEntriesNum = ULEV(relaShdr.sh_size)/relaEntrySize;
218        const size_t gotEntriesNum = ULEV(gotShdr.sh_size) >> 3;
219        if (gotEntriesNum != relaEntriesNum)
220            throw BinException("RelaDyn entries number and GOT entries "
221                        "number doesn't match!");
222       
223        // initialize GOT symbols table
224        gotSymbols.resize(gotEntriesNum);
225        const cxbyte* relaDyn = getSectionContent(relaDynIndex);
226        for (size_t i = 0; i < relaEntriesNum; i++)
227        {
228            const Elf64_Rela& rela = *reinterpret_cast<const Elf64_Rela*>(
229                            relaDyn + relaEntrySize*i);
230            // check rela entry fields
231            if (ULEV(rela.r_offset) != ULEV(gotShdr.sh_offset) + i*8)
232                throw BinException("Wrong dyn relocation offset");
233            if (ULEV(rela.r_addend) != 0ULL)
234                throw BinException("Wrong dyn relocation addend");
235            size_t symIndex = ELF64_R_SYM(ULEV(rela.r_info));
236            if (symIndex >= getDynSymbolsNum())
237                throw BinException("Dyn relocation symbol index out of range");
238            // just set in gotSymbols
239            gotSymbols[i] = symIndex;
240        }
241    }
242   
[3665]243    // get metadata
244    const size_t notesSize = getNotesSize();
245    const cxbyte* noteContent = (const cxbyte*)getNotes();
[4895]246    bool isMetadataV3 = false;
[3665]247   
248    for (size_t offset = 0; offset < notesSize; )
249    {
250        const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
251        size_t namesz = ULEV(nhdr->n_namesz);
252        size_t descsz = ULEV(nhdr->n_descsz);
253        if (usumGt(offset, namesz+descsz, notesSize))
254            throw BinException("Note offset+size out of range");
255       
[4895]256        const size_t alignedNamesz = ((namesz+3)&~size_t(3));
257        if ((namesz==4 &&
258            ::strcmp((const char*)noteContent+offset+ sizeof(Elf64_Nhdr), "AMD")==0) ||
259            (namesz==7 &&
260            ::strcmp((const char*)noteContent+offset+ sizeof(Elf64_Nhdr), "AMDGPU")==0))
[3665]261        {
262            const uint32_t noteType = ULEV(nhdr->n_type);
[4895]263            if ((noteType == 0xa && namesz==4) || (noteType == 0x20 && namesz==7))
[3665]264            {
[4895]265                if (namesz==7)
266                    isMetadataV3 = true;
267                if (namesz==4 && isMetadataV3)
268                    throw Exception("MetadataV2 in MetadataV3 compliant binary!");
269                metadata = (char*)(noteContent+offset+sizeof(Elf64_Nhdr) + alignedNamesz);
[3665]270                metadataSize = descsz;
271            }
[4895]272            else if (noteType == 0xb && namesz==4)
273                target.assign((char*)(noteContent+offset+sizeof(Elf64_Nhdr) +
274                                        alignedNamesz), descsz);
[3665]275        }
[4895]276        size_t align = (((alignedNamesz+descsz)&3)!=0) ? 4-((alignedNamesz+descsz)&3) : 0;
277        offset += sizeof(Elf64_Nhdr) + alignedNamesz + descsz + align;
[3665]278    }
279   
[2518]280    if (hasRegionMap())
[3396]281    {
282        // create region map
[2518]283        regionsMap.resize(regionsNum);
284        for (size_t i = 0; i < regionsNum; i++)
285            regionsMap[i] = std::make_pair(regions[i].regionName, i);
[3420]286        // sort region map
[2518]287        mapSort(regionsMap.begin(), regionsMap.end());
[2502]288    }
[3683]289   
[3685]290    if ((creationFlags & ROCMBIN_CREATE_METADATAINFO) != 0 &&
291        metadata != nullptr && metadataSize != 0)
[3683]292    {
293        metadataInfo.reset(new ROCmMetadata());
[4895]294        if (!isMetadataV3)
295            parseROCmMetadata(metadataSize, metadata, *metadataInfo);
296        else
297            parseROCmMetadataMsgPack(metadataSize,
298                    reinterpret_cast<const cxbyte*>(metadata), *metadataInfo);
[3683]299       
300        if (hasKernelInfoMap())
301        {
302            const std::vector<ROCmKernelMetadata>& kernels = metadataInfo->kernels;
303            kernelInfosMap.resize(kernels.size());
304            for (size_t i = 0; i < kernelInfosMap.size(); i++)
305                kernelInfosMap[i] = std::make_pair(kernels[i].name, i);
306            // sort region map
307            mapSort(kernelInfosMap.begin(), kernelInfosMap.end());
308        }
309    }
[2500]310}
311
[3420]312/// determint GPU device from ROCm notes
[2710]313GPUDeviceType ROCmBinary::determineGPUDeviceType(uint32_t& outArchMinor,
314                     uint32_t& outArchStepping) const
315{
316    uint32_t archMajor = 0;
317    uint32_t archMinor = 0;
318    uint32_t archStepping = 0;
319   
320    {
321        const cxbyte* noteContent = (const cxbyte*)getNotes();
322        if (noteContent==nullptr)
[3457]323            throw BinException("Missing notes in inner binary!");
[2710]324        size_t notesSize = getNotesSize();
325        // find note about AMDGPU
326        for (size_t offset = 0; offset < notesSize; )
327        {
328            const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
329            size_t namesz = ULEV(nhdr->n_namesz);
330            size_t descsz = ULEV(nhdr->n_descsz);
331            if (usumGt(offset, namesz+descsz, notesSize))
[3457]332                throw BinException("Note offset+size out of range");
[2710]333            if (ULEV(nhdr->n_type) == 0x3 && namesz==4 && descsz>=0x1a &&
334                ::strcmp((const char*)noteContent+offset+sizeof(Elf64_Nhdr), "AMD")==0)
335            {    // AMDGPU type
336                const uint32_t* content = (const uint32_t*)
337                        (noteContent+offset+sizeof(Elf64_Nhdr) + 4);
338                archMajor = ULEV(content[1]);
339                archMinor = ULEV(content[2]);
340                archStepping = ULEV(content[3]);
341            }
342            size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
343            offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
344        }
345    }
346    // determine device type
[3444]347    GPUDeviceType deviceType = getGPUDeviceTypeFromArchVersion(archMajor, archMinor,
[3443]348                                    archStepping);
[2710]349    outArchMinor = archMinor;
350    outArchStepping = archStepping;
351    return deviceType;
352}
353
[2518]354const ROCmRegion& ROCmBinary::getRegion(const char* name) const
[2500]355{
[2518]356    RegionMap::const_iterator it = binaryMapFind(regionsMap.begin(),
357                             regionsMap.end(), name);
358    if (it == regionsMap.end())
[3457]359        throw BinException("Can't find region name");
[2518]360    return regions[it->second];
[2500]361}
[2501]362
[3683]363const ROCmKernelMetadata& ROCmBinary::getKernelInfo(const char* name) const
364{
365    if (!hasMetadataInfo())
366        throw BinException("Can't find kernel info name");
367    RegionMap::const_iterator it = binaryMapFind(kernelInfosMap.begin(),
368                             kernelInfosMap.end(), name);
369    if (it == kernelInfosMap.end())
370        throw BinException("Can't find kernel info name");
371    return metadataInfo->kernels[it->second];
372}
373
[3420]374// if ROCm binary
[2501]375bool CLRX::isROCmBinary(size_t binarySize, const cxbyte* binary)
376{
377    if (!isElfBinary(binarySize, binary))
378        return false;
379    if (binary[EI_CLASS] != ELFCLASS64)
380        return false;
381    const Elf64_Ehdr* ehdr = reinterpret_cast<const Elf64_Ehdr*>(binary);
[3660]382    if (ULEV(ehdr->e_machine) != 0xe0)
[2501]383        return false;
384    return true;
385}
[2534]386
[2582]387
388void ROCmInput::addEmptyKernel(const char* kernelName)
389{
[2599]390    symbols.push_back({ kernelName, 0, 0, ROCmRegionType::KERNEL });
[2582]391}
[3666]392
[3793]393/* ROCm section generators */
394
395class CLRX_INTERNAL ROCmGotGen: public ElfRegionContent
396{
397private:
398    const ROCmInput* input;
399public:
400    explicit ROCmGotGen(const ROCmInput* _input) : input(_input)
401    { }
402   
403    void operator()(FastOutputBuffer& fob) const
404    {
405        fob.fill(input->gotSymbols.size()*8, 0);
406    }
407};
408
409class CLRX_INTERNAL ROCmRelaDynGen: public ElfRegionContent
410{
411private:
412    size_t gotOffset;
413    const ROCmInput* input;
414public:
415    explicit ROCmRelaDynGen(const ROCmInput* _input) : gotOffset(0), input(_input)
416    { }
417   
418    void setGotOffset(size_t _gotOffset)
419    { gotOffset = _gotOffset; }
420   
421    void operator()(FastOutputBuffer& fob) const
422    {
423        for (size_t i = 0; i < input->gotSymbols.size(); i++)
424        {
425            size_t symIndex = input->gotSymbols[i];
426            Elf64_Rela rela{};
427            SLEV(rela.r_offset, gotOffset + 8*i);
[3794]428            SLEV(rela.r_info, ELF64_R_INFO(symIndex + 1, 3));
[3793]429            rela.r_addend = 0;
430            fob.writeObject(rela);
431        }
432    }
433};
434
[3721]435/*
[2534]436 * ROCm Binary Generator
437 */
438
439ROCmBinGenerator::ROCmBinGenerator() : manageable(false), input(nullptr)
440{ }
441
442ROCmBinGenerator::ROCmBinGenerator(const ROCmInput* rocmInput)
[3793]443        : manageable(false), input(rocmInput), rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
[2534]444{ }
445
446ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
447        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
[3666]448        size_t globalDataSize, const cxbyte* globalData,
[3793]449        const std::vector<ROCmSymbolInput>& symbols) :
450        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
[2534]451{
[4430]452    std::unique_ptr<ROCmInput> _input(new ROCmInput{});
453    _input->deviceType = deviceType;
454    _input->archMinor = archMinor;
455    _input->archStepping = archStepping;
456    _input->eflags = 0;
457    _input->newBinFormat = false;
458    _input->globalDataSize = globalDataSize;
459    _input->globalData = globalData;
460    _input->symbols = symbols;
461    _input->codeSize = codeSize;
462    _input->code = code;
463    _input->commentSize = 0;
464    _input->comment = nullptr;
465    _input->target = "";
466    _input->targetTripple = "";
467    _input->metadataSize = 0;
468    _input->metadata = nullptr;
469    _input->useMetadataInfo = false;
470    _input->metadataInfo = ROCmMetadata{};
471    input = _input.release();
[2534]472}
473
474ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
475        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
[3666]476        size_t globalDataSize, const cxbyte* globalData,
[3793]477        std::vector<ROCmSymbolInput>&& symbols) :
478        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
[2534]479{
[4430]480    std::unique_ptr<ROCmInput> _input(new ROCmInput{});
481    _input->deviceType = deviceType;
482    _input->archMinor = archMinor;
483    _input->archStepping = archStepping;
484    _input->eflags = 0;
485    _input->newBinFormat = false;
486    _input->globalDataSize = globalDataSize;
487    _input->globalData = globalData;
488    _input->symbols = std::move(symbols);
489    _input->codeSize = codeSize;
490    _input->code = code;
491    _input->commentSize = 0;
492    _input->comment = nullptr;
493    _input->target = "";
494    _input->targetTripple = "";
495    _input->metadataSize = 0;
496    _input->metadata = nullptr;
497    _input->useMetadataInfo = false;
498    _input->metadataInfo = ROCmMetadata{};
499    input = _input.release();
[2534]500}
501
502ROCmBinGenerator::~ROCmBinGenerator()
503{
504    if (manageable)
505        delete input;
[3793]506    if (rocmGotGen!=nullptr)
507        delete (ROCmGotGen*)rocmGotGen;
508    if (rocmRelaDynGen!=nullptr)
509        delete (ROCmRelaDynGen*)rocmRelaDynGen;
[2534]510}
511
512void ROCmBinGenerator::setInput(const ROCmInput* input)
513{
514    if (manageable)
515        delete input;
516    manageable = false;
517    this->input = input;
518}
519
[3420]520// ELF notes contents
[2554]521static const cxbyte noteDescType1[8] =
522{ 2, 0, 0, 0, 1, 0, 0, 0 };
523
524static const cxbyte noteDescType3[27] =
525{ 4, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
526  'A', 'M', 'D', 0, 'A', 'M', 'D', 'G', 'P', 'U', 0 };
527
[3666]528static inline void addMainSectionToTable(cxuint& sectionsNum, uint16_t* builtinTable,
529                cxuint elfSectId)
530{ builtinTable[elfSectId - ELFSECTID_START] = sectionsNum++; }
[2576]531
[3763]532void ROCmBinGenerator::prepareBinaryGen()
[2534]533{
[3444]534    AMDGPUArchVersion amdGpuArchValues = getGPUArchVersion(input->deviceType,
[3677]535                GPUArchVersionTable::ROCM);
[2561]536    if (input->archMinor!=UINT32_MAX)
537        amdGpuArchValues.minor = input->archMinor;
538    if (input->archStepping!=UINT32_MAX)
539        amdGpuArchValues.stepping = input->archStepping;
540   
[3763]541    comment = "CLRX ROCmBinGenerator " CLRX_VERSION;
542    commentSize = ::strlen(comment);
[2535]543    if (input->comment!=nullptr)
[3396]544    {
545        // if comment, store comment section
[2535]546        comment = input->comment;
547        commentSize = input->commentSize;
548        if (commentSize==0)
549            commentSize = ::strlen(comment);
550    }
551   
[3666]552    uint32_t eflags = input->newBinFormat ? 2 : 0;
553    if (input->eflags != BINGEN_DEFAULT)
554        eflags = input->eflags;
555   
[3669]556    std::fill(mainBuiltinSectTable,
557              mainBuiltinSectTable + ROCMSECTID_MAX-ELFSECTID_START+1, SHN_UNDEF);
[3784]558    mainSectionsNum = 1;
[3669]559   
560    // generate main builtin section table (for section id translation)
561    if (input->newBinFormat)
562        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
563    if (input->globalData != nullptr)
564        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_RODATA);
565    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSYM);
566    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_HASH);
567    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSTR);
[3793]568    if (!input->gotSymbols.empty())
569        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_RELADYN);
[3669]570    const cxuint execProgHeaderRegionIndex = mainSectionsNum;
571    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_TEXT);
572    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_DYNAMIC);
[3793]573    if (!input->gotSymbols.empty())
574        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GOT);
[3669]575    if (!input->newBinFormat)
576    {
577        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
578        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GPUCONFIG);
579    }
580    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_COMMENT);
581    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SYMTAB);
582    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SHSTRTAB);
583    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_STRTAB);
584   
[3796]585    elfBinGen64.reset(new ElfBinaryGen64({ 0U, 0U, 0x40, 0, ET_DYN, 0xe0, EV_CURRENT,
586            cxuint(input->newBinFormat ? execProgHeaderRegionIndex : UINT_MAX), 0, eflags },
587            true, true, true, PHREGION_FILESTART));
588   
[2554]589    static const int32_t dynTags[] = {
590        DT_SYMTAB, DT_SYMENT, DT_STRTAB, DT_STRSZ, DT_HASH };
[3763]591    elfBinGen64->addDynamics(sizeof(dynTags)/sizeof(int32_t), dynTags);
[3666]592   
[2561]593    // elf program headers
[3763]594    elfBinGen64->addProgramHeader({ PT_PHDR, PF_R, 0, 1,
[2568]595                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
[3763]596    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R, PHREGION_FILESTART,
[3667]597                    execProgHeaderRegionIndex,
[2568]598                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 0x1000 });
[3763]599    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_X, execProgHeaderRegionIndex, 1,
[2568]600                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
[3793]601    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_W, execProgHeaderRegionIndex+1,
602                    cxuint(1 + (!input->gotSymbols.empty())),
[2568]603                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
[3763]604    elfBinGen64->addProgramHeader({ PT_DYNAMIC, PF_R|PF_W, execProgHeaderRegionIndex+1, 1,
[2568]605                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 8 });
[3793]606    elfBinGen64->addProgramHeader({ PT_GNU_RELRO, PF_R, execProgHeaderRegionIndex+1,
607                    cxuint(1 + (!input->gotSymbols.empty())),
[2568]608                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 1 });
[3763]609    elfBinGen64->addProgramHeader({ PT_GNU_STACK, PF_R|PF_W, PHREGION_FILESTART, 0,
[2564]610                    true, 0, 0, 0 });
[2554]611   
[3667]612    if (input->newBinFormat)
613        // program header for note (new binary format)
[3763]614        elfBinGen64->addProgramHeader({ PT_NOTE, PF_R, 1, 1, true,
[3668]615                    Elf64Types::nobase, Elf64Types::nobase, 0, 4 });
[3667]616   
[3763]617    target = input->target.c_str();
[3671]618    if (target.empty() && !input->targetTripple.empty())
619    {
620        target = input->targetTripple.c_str();
621        char dbuf[20];
622        snprintf(dbuf, 20, "-gfx%u%u%u", amdGpuArchValues.major, amdGpuArchValues.minor,
623                 amdGpuArchValues.stepping);
624        target += dbuf;
625    }
[2561]626    // elf notes
[3763]627    elfBinGen64->addNote({"AMD", sizeof noteDescType1, noteDescType1, 1U});
628    noteBuf.reset(new cxbyte[0x1b]);
[2557]629    ::memcpy(noteBuf.get(), noteDescType3, 0x1b);
[2561]630    SULEV(*(uint32_t*)(noteBuf.get()+4), amdGpuArchValues.major);
631    SULEV(*(uint32_t*)(noteBuf.get()+8), amdGpuArchValues.minor);
632    SULEV(*(uint32_t*)(noteBuf.get()+12), amdGpuArchValues.stepping);
[3763]633    elfBinGen64->addNote({"AMD", 0x1b, noteBuf.get(), 3U});
[3671]634    if (!target.empty())
[3763]635        elfBinGen64->addNote({"AMD", target.size(), (const cxbyte*)target.c_str(), 0xbU});
[2554]636   
[3763]637    metadataSize = input->metadataSize;
638    metadata = input->metadata;
[3724]639    if (input->useMetadataInfo)
640    {
641        // generate ROCm metadata
642        std::vector<std::pair<CString, size_t> > symbolIndices(input->symbols.size());
643        // create sorted indices of symbols by its name
644        for (size_t k = 0; k < input->symbols.size(); k++)
645            symbolIndices[k] = std::make_pair(input->symbols[k].symbolName, k);
646        mapSort(symbolIndices.begin(), symbolIndices.end());
647       
648        const size_t mdKernelsNum = input->metadataInfo.kernels.size();
649        std::unique_ptr<const ROCmKernelConfig*[]> kernelConfigPtrs(
650                new const ROCmKernelConfig*[mdKernelsNum]);
[3726]651        // generate ROCm kernel config pointers
[3724]652        for (size_t k = 0; k < mdKernelsNum; k++)
653        {
654            auto it = binaryMapFind(symbolIndices.begin(), symbolIndices.end(), 
655                        input->metadataInfo.kernels[k].name);
[3726]656            if (it == symbolIndices.end() ||
657                (input->symbols[it->second].type != ROCmRegionType::FKERNEL &&
658                 input->symbols[it->second].type != ROCmRegionType::KERNEL))
[3724]659                throw BinGenException("Kernel in metadata doesn't exists in code");
660            kernelConfigPtrs[k] = reinterpret_cast<const ROCmKernelConfig*>(
661                        input->code + input->symbols[it->second].offset);
662        }
[3726]663        // just generate ROCm metadata from info
[3725]664        generateROCmMetadata(input->metadataInfo, kernelConfigPtrs.get(), metadataStr);
[3724]665        metadataSize = metadataStr.size();
666        metadata = metadataStr.c_str();
667    }
668   
669    if (metadataSize != 0)
[3763]670        elfBinGen64->addNote({"AMD", metadataSize, (const cxbyte*)metadata, 0xaU});
[3724]671   
[2561]672    /// region and sections
[3763]673    elfBinGen64->addRegion(ElfRegion64::programHeaderTable());
[3666]674    if (input->newBinFormat)
[3763]675        elfBinGen64->addRegion(ElfRegion64::noteSection());
[3666]676    if (input->globalData != nullptr)
[3763]677        elfBinGen64->addRegion(ElfRegion64(input->globalDataSize, input->globalData, 4,
[3666]678                ".rodata", SHT_PROGBITS, SHF_ALLOC, 0, 0, Elf64Types::nobase));
679   
[3763]680    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
[3738]681                ".dynsym", SHT_DYNSYM, SHF_ALLOC, 0, BINGEN_DEFAULT, Elf64Types::nobase));
[3763]682    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 4,
[3666]683                ".hash", SHT_HASH, SHF_ALLOC,
684                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
685                Elf64Types::nobase));
[3763]686    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".dynstr", SHT_STRTAB,
[2564]687                SHF_ALLOC, 0, 0, Elf64Types::nobase));
[3793]688    if (!input->gotSymbols.empty())
689    {
[3796]690        ROCmRelaDynGen* sgen = new ROCmRelaDynGen(input);
691        rocmRelaDynGen = (void*)sgen;
[3793]692        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*sizeof(Elf64_Rela),
[3796]693                sgen, 8, ".rela.dyn", SHT_RELA, SHF_ALLOC,
[3793]694                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
695                Elf64Types::nobase, sizeof(Elf64_Rela)));
696    }
[3420]697    // '.text' with alignment=4096
[3763]698    elfBinGen64->addRegion(ElfRegion64(input->codeSize, (const cxbyte*)input->code, 
[2564]699              0x1000, ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 0, 0,
700              Elf64Types::nobase, 0, false, 256));
[3763]701    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 0x1000,
[3666]702                ".dynamic", SHT_DYNAMIC, SHF_ALLOC|SHF_WRITE,
703                mainBuiltinSectTable[ELFSECTID_DYNSTR-ELFSECTID_START], 0,
[2564]704                Elf64Types::nobase, 0, false, 8));
[3793]705    if (!input->gotSymbols.empty())
706    {
[3796]707        ROCmGotGen* sgen = new ROCmGotGen(input);
708        rocmGotGen = (void*)sgen;
709        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*8, sgen,
710                8, ".got", SHT_PROGBITS,
[3793]711                SHF_ALLOC|SHF_WRITE, 0, 0, Elf64Types::nobase));
712    }
[3666]713    if (!input->newBinFormat)
714    {
[3763]715        elfBinGen64->addRegion(ElfRegion64::noteSection());
716        elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1,
[3666]717                    ".AMDGPU.config", SHT_PROGBITS, 0));
718    }
[3763]719    elfBinGen64->addRegion(ElfRegion64(commentSize, (const cxbyte*)comment, 1, ".comment",
[2564]720              SHT_PROGBITS, SHF_MERGE|SHF_STRINGS, 0, 0, 0, 1));
[3763]721    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
[3738]722                ".symtab", SHT_SYMTAB, 0, 0, BINGEN_DEFAULT));
[3763]723    elfBinGen64->addRegion(ElfRegion64::shstrtabSection());
724    elfBinGen64->addRegion(ElfRegion64::strtabSection());
725    elfBinGen64->addRegion(ElfRegion64::sectionHeaderTable());
[2535]726   
[2576]727    /* extra sections */
728    for (const BinSection& section: input->extraSections)
[3763]729        elfBinGen64->addRegion(ElfRegion64(section, mainBuiltinSectTable,
[3666]730                         ROCMSECTID_MAX, mainSectionsNum));
[3784]731    updateSymbols();
732    binarySize = elfBinGen64->countSize();
[3793]733   
734    if (rocmRelaDynGen != nullptr)
735        ((ROCmRelaDynGen*)rocmRelaDynGen)->setGotOffset(
736                elfBinGen64->getRegionOffset(
737                        mainBuiltinSectTable[ROCMSECTID_GOT - ELFSECTID_START]));
[3784]738}
739
740void ROCmBinGenerator::updateSymbols()
741{
742    elfBinGen64->clearSymbols();
743    elfBinGen64->clearDynSymbols();
744    // add symbols (kernels, function kernels and data symbols)
745    elfBinGen64->addSymbol(ElfSymbol64("_DYNAMIC",
746                  mainBuiltinSectTable[ROCMSECTID_DYNAMIC-ELFSECTID_START],
747                  ELF64_ST_INFO(STB_LOCAL, STT_NOTYPE), STV_HIDDEN, true, 0, 0));
748    const uint16_t textSectIndex = mainBuiltinSectTable[ELFSECTID_TEXT-ELFSECTID_START];
749    for (const ROCmSymbolInput& symbol: input->symbols)
750    {
751        ElfSymbol64 elfsym;
752        switch (symbol.type)
753        {
754            case ROCmRegionType::KERNEL:
755                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
756                      ELF64_ST_INFO(STB_GLOBAL, STT_GNU_IFUNC), 0, true,
757                      symbol.offset, symbol.size);
758                break;
759            case ROCmRegionType::FKERNEL:
760                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
761                      ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), 0, true,
762                      symbol.offset, symbol.size);
763                break;
764            case ROCmRegionType::DATA:
765                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
766                      ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT), 0, true,
767                      symbol.offset, symbol.size);
768                break;
769            default:
770                break;
771        }
772        // add to symbols and dynamic symbols table
773        elfBinGen64->addSymbol(elfsym);
774        elfBinGen64->addDynSymbol(elfsym);
775    }
[2576]776    /* extra symbols */
777    for (const BinSymbol& symbol: input->extraSymbols)
[3760]778    {
779        ElfSymbol64 sym(symbol, mainBuiltinSectTable,
780                         ROCMSECTID_MAX, mainSectionsNum);
[3763]781        elfBinGen64->addSymbol(sym);
782        elfBinGen64->addDynSymbol(sym);
[3760]783    }
[3763]784}
785
786void ROCmBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
787             Array<cxbyte>* aPtr)
788{
[3772]789    if (elfBinGen64 == nullptr)
790        prepareBinaryGen();
[2534]791    /****
792     * prepare for write binary to output
793     ****/
794    std::unique_ptr<std::ostream> outStreamHolder;
795    std::ostream* os = nullptr;
796    if (aPtr != nullptr)
797    {
798        aPtr->resize(binarySize);
799        outStreamHolder.reset(
800                new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
801        os = outStreamHolder.get();
802    }
803    else if (vPtr != nullptr)
804    {
805        vPtr->resize(binarySize);
806        outStreamHolder.reset(new VectorOStream(*vPtr));
807        os = outStreamHolder.get();
808    }
809    else // from argument
810        os = osPtr;
811   
812    const std::ios::iostate oldExceptions = os->exceptions();
813    try
814    {
815    os->exceptions(std::ios::failbit | std::ios::badbit);
816    /****
817     * write binary to output
818     ****/
[2536]819    FastOutputBuffer bos(256, *os);
[3763]820    elfBinGen64->generate(bos);
[2536]821    assert(bos.getWritten() == binarySize);
[3793]822   
823    if (rocmGotGen != nullptr)
824    {
825        delete (ROCmGotGen*)rocmGotGen;
826        rocmGotGen = nullptr;
[2534]827    }
[3793]828    if (rocmRelaDynGen != nullptr)
829    {
830        delete (ROCmGotGen*)rocmRelaDynGen;
831        rocmRelaDynGen = nullptr;
832    }
833    }
[2534]834    catch(...)
835    {
836        os->exceptions(oldExceptions);
837        throw;
838    }
839    os->exceptions(oldExceptions);
840}
841
[3763]842void ROCmBinGenerator::generate(Array<cxbyte>& array)
[2534]843{
844    generateInternal(nullptr, nullptr, &array);
845}
846
[3763]847void ROCmBinGenerator::generate(std::ostream& os)
[2534]848{
849    generateInternal(&os, nullptr, nullptr);
850}
851
[3763]852void ROCmBinGenerator::generate(std::vector<char>& v)
[2534]853{
854    generateInternal(nullptr, &v, nullptr);
855}
Note: See TracBrowser for help on using the repository browser.