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
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
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>
21#include <cassert>
22#include <cstdio>
23#include <cstring>
24#include <cstdint>
25#include <string>
26#include <vector>
27#include <algorithm>
28#include <utility>
29#include <memory>
30#include <unordered_set>
31#include <CLRX/amdbin/ElfBinaries.h>
32#include <CLRX/utils/Utilities.h>
33#include <CLRX/utils/MemAccess.h>
34#include <CLRX/utils/InputOutput.h>
35#include <CLRX/utils/Containers.h>
36#include <CLRX/amdbin/ROCmBinaries.h>
37
38using namespace CLRX;
39
40
41/*
42 * ROCm binary reader and generator
43 */
44
45/* TODO: add support for various kernel code offset (now only 256 is supported) */
46
47ROCmBinary::ROCmBinary(size_t binaryCodeSize, cxbyte* binaryCode, Flags creationFlags)
48        : ElfBinary64(binaryCodeSize, binaryCode, creationFlags),
49          regionsNum(0), codeSize(0), code(nullptr),
50          globalDataSize(0), globalData(nullptr), metadataSize(0), metadata(nullptr),
51          newBinFormat(false), llvm10BinFormat(false), metadataV3Format(false)
52{
53    cxuint textIndex = SHN_UNDEF;
54    try
55    { textIndex = getSectionIndex(".text"); }
56    catch(const Exception& ex)
57    { } // ignore failed
58    uint64_t codeOffset = 0;
59    // find '.text' section
60    if (textIndex!=SHN_UNDEF)
61    {
62        code = getSectionContent(textIndex);
63        const Elf64_Shdr& textShdr = getSectionHeader(textIndex);
64        codeSize = ULEV(textShdr.sh_size);
65        codeOffset = ULEV(textShdr.sh_offset);
66    }
67   
68    if (getHeader().e_ident[EI_ABIVERSION] == 1)
69        llvm10BinFormat = true; // likely llvm10 bin format
70   
71    cxuint rodataIndex = SHN_UNDEF;
72    const cxbyte* rodataContent = nullptr;
73    try
74    { rodataIndex = getSectionIndex(".rodata"); }
75    catch(const Exception& ex)
76    { } // ignore failed
77    // find '.text' section
78    if (rodataIndex!=SHN_UNDEF)
79    {
80        rodataContent = globalData = getSectionContent(rodataIndex);
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   
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   
104    // counts regions (symbol or kernel)
105    std::vector<std::pair<CString, size_t> > tmpKernelDescs;
106    regionsNum = 0;
107    const size_t symbolsNum = getSymbolsNum();
108    for (size_t i = 0; i < symbolsNum; i++)
109    {
110        // count regions number
111        const Elf64_Sym& sym = getSymbol(i);
112        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
113        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
114        Elf64_Half shndx = ULEV(sym.st_shndx);
115        if (shndx==textIndex &&
116            (symType==STT_GNU_IFUNC || (symType==STT_FUNC && !newBinFormat) ||
117                (bind==STB_GLOBAL && symType==STT_OBJECT)))
118            regionsNum++;
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        }
129    }
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   
138    if (code==nullptr && regionsNum!=0)
139        throw BinException("No code if regions number is not zero");
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]);
144   
145    // get regions info
146    for (size_t i = 0; i < symbolsNum; i++)
147    {
148        const Elf64_Sym& sym = getSymbol(i);
149        if (ULEV(sym.st_shndx)!=textIndex)
150            continue;   // if not in '.text' section
151        const size_t value = ULEV(sym.st_value);
152        if (value < codeOffset)
153            throw BinException("Region offset is too small!");
154        const size_t size = ULEV(sym.st_size);
155       
156        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
157        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
158        if (symType==STT_GNU_IFUNC || symType==STT_FUNC ||
159                (bind==STB_GLOBAL && symType==STT_OBJECT))
160        {
161            ROCmRegionType type = ROCmRegionType::DATA;
162            // if kernel
163            if (symType==STT_GNU_IFUNC) 
164                type = ROCmRegionType::KERNEL;
165            // if function kernel
166            else if (symType==STT_FUNC)
167            {
168                if (newBinFormat)
169                    continue;
170                type = ROCmRegionType::FKERNEL;
171            }
172            symOffsets[j] = std::make_pair(value, j);
173            if (type!=ROCmRegionType::DATA && value+0x100 > codeOffset+codeSize)
174                throw BinException("Kernel or code offset is too big!");
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            }
187        }
188    }
189    // sort regions by offset
190    std::sort(symOffsets.get(), symOffsets.get()+regionsNum,
191            [](const RegionOffsetEntry& a, const RegionOffsetEntry& b)
192            { return a.first < b.first; });
193    // checking distance between regions
194    for (size_t i = 1; i <= regionsNum; i++)
195    {
196        size_t end = (i<regionsNum) ? symOffsets[i].first : codeOffset+codeSize;
197        ROCmRegion& region = regions[symOffsets[i-1].second];
198        if (region.type==ROCmRegionType::KERNEL && symOffsets[i-1].first+0x100 > end)
199            throw BinException("Kernel size is too small!");
200       
201        const size_t regSize = end - symOffsets[i-1].first;
202        if (region.size==0)
203            region.size = regSize;
204        else
205            region.size = std::min(regSize, region.size);
206    }
207   
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   
243    // get metadata
244    const size_t notesSize = getNotesSize();
245    const cxbyte* noteContent = (const cxbyte*)getNotes();
246    bool isMetadataV3 = false;
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       
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))
261        {
262            const uint32_t noteType = ULEV(nhdr->n_type);
263            if ((noteType == 0xa && namesz==4) || (noteType == 0x20 && namesz==7))
264            {
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);
270                metadataSize = descsz;
271            }
272            else if (noteType == 0xb && namesz==4)
273                target.assign((char*)(noteContent+offset+sizeof(Elf64_Nhdr) +
274                                        alignedNamesz), descsz);
275        }
276        size_t align = (((alignedNamesz+descsz)&3)!=0) ? 4-((alignedNamesz+descsz)&3) : 0;
277        offset += sizeof(Elf64_Nhdr) + alignedNamesz + descsz + align;
278    }
279   
280    if (hasRegionMap())
281    {
282        // create region map
283        regionsMap.resize(regionsNum);
284        for (size_t i = 0; i < regionsNum; i++)
285            regionsMap[i] = std::make_pair(regions[i].regionName, i);
286        // sort region map
287        mapSort(regionsMap.begin(), regionsMap.end());
288    }
289   
290    if ((creationFlags & ROCMBIN_CREATE_METADATAINFO) != 0 &&
291        metadata != nullptr && metadataSize != 0)
292    {
293        metadataInfo.reset(new ROCmMetadata());
294        if (!isMetadataV3)
295            parseROCmMetadata(metadataSize, metadata, *metadataInfo);
296        else
297            parseROCmMetadataMsgPack(metadataSize,
298                    reinterpret_cast<const cxbyte*>(metadata), *metadataInfo);
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    }
310}
311
312/// determint GPU device from ROCm notes
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)
323            throw BinException("Missing notes in inner binary!");
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))
332                throw BinException("Note offset+size out of range");
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
347    GPUDeviceType deviceType = getGPUDeviceTypeFromArchVersion(archMajor, archMinor,
348                                    archStepping);
349    outArchMinor = archMinor;
350    outArchStepping = archStepping;
351    return deviceType;
352}
353
354const ROCmRegion& ROCmBinary::getRegion(const char* name) const
355{
356    RegionMap::const_iterator it = binaryMapFind(regionsMap.begin(),
357                             regionsMap.end(), name);
358    if (it == regionsMap.end())
359        throw BinException("Can't find region name");
360    return regions[it->second];
361}
362
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
374// if ROCm binary
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);
382    if (ULEV(ehdr->e_machine) != 0xe0)
383        return false;
384    return true;
385}
386
387
388void ROCmInput::addEmptyKernel(const char* kernelName)
389{
390    symbols.push_back({ kernelName, 0, 0, ROCmRegionType::KERNEL });
391}
392
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);
428            SLEV(rela.r_info, ELF64_R_INFO(symIndex + 1, 3));
429            rela.r_addend = 0;
430            fob.writeObject(rela);
431        }
432    }
433};
434
435/*
436 * ROCm Binary Generator
437 */
438
439ROCmBinGenerator::ROCmBinGenerator() : manageable(false), input(nullptr)
440{ }
441
442ROCmBinGenerator::ROCmBinGenerator(const ROCmInput* rocmInput)
443        : manageable(false), input(rocmInput), rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
444{ }
445
446ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
447        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
448        size_t globalDataSize, const cxbyte* globalData,
449        const std::vector<ROCmSymbolInput>& symbols) :
450        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
451{
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();
472}
473
474ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
475        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
476        size_t globalDataSize, const cxbyte* globalData,
477        std::vector<ROCmSymbolInput>&& symbols) :
478        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
479{
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();
500}
501
502ROCmBinGenerator::~ROCmBinGenerator()
503{
504    if (manageable)
505        delete input;
506    if (rocmGotGen!=nullptr)
507        delete (ROCmGotGen*)rocmGotGen;
508    if (rocmRelaDynGen!=nullptr)
509        delete (ROCmRelaDynGen*)rocmRelaDynGen;
510}
511
512void ROCmBinGenerator::setInput(const ROCmInput* input)
513{
514    if (manageable)
515        delete input;
516    manageable = false;
517    this->input = input;
518}
519
520// ELF notes contents
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
528static inline void addMainSectionToTable(cxuint& sectionsNum, uint16_t* builtinTable,
529                cxuint elfSectId)
530{ builtinTable[elfSectId - ELFSECTID_START] = sectionsNum++; }
531
532void ROCmBinGenerator::prepareBinaryGen()
533{
534    AMDGPUArchVersion amdGpuArchValues = getGPUArchVersion(input->deviceType,
535                GPUArchVersionTable::ROCM);
536    if (input->archMinor!=UINT32_MAX)
537        amdGpuArchValues.minor = input->archMinor;
538    if (input->archStepping!=UINT32_MAX)
539        amdGpuArchValues.stepping = input->archStepping;
540   
541    comment = "CLRX ROCmBinGenerator " CLRX_VERSION;
542    commentSize = ::strlen(comment);
543    if (input->comment!=nullptr)
544    {
545        // if comment, store comment section
546        comment = input->comment;
547        commentSize = input->commentSize;
548        if (commentSize==0)
549            commentSize = ::strlen(comment);
550    }
551   
552    uint32_t eflags = input->newBinFormat ? 2 : 0;
553    if (input->eflags != BINGEN_DEFAULT)
554        eflags = input->eflags;
555   
556    std::fill(mainBuiltinSectTable,
557              mainBuiltinSectTable + ROCMSECTID_MAX-ELFSECTID_START+1, SHN_UNDEF);
558    mainSectionsNum = 1;
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);
568    if (!input->gotSymbols.empty())
569        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_RELADYN);
570    const cxuint execProgHeaderRegionIndex = mainSectionsNum;
571    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_TEXT);
572    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_DYNAMIC);
573    if (!input->gotSymbols.empty())
574        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GOT);
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   
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   
589    static const int32_t dynTags[] = {
590        DT_SYMTAB, DT_SYMENT, DT_STRTAB, DT_STRSZ, DT_HASH };
591    elfBinGen64->addDynamics(sizeof(dynTags)/sizeof(int32_t), dynTags);
592   
593    // elf program headers
594    elfBinGen64->addProgramHeader({ PT_PHDR, PF_R, 0, 1,
595                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
596    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R, PHREGION_FILESTART,
597                    execProgHeaderRegionIndex,
598                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 0x1000 });
599    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_X, execProgHeaderRegionIndex, 1,
600                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
601    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_W, execProgHeaderRegionIndex+1,
602                    cxuint(1 + (!input->gotSymbols.empty())),
603                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
604    elfBinGen64->addProgramHeader({ PT_DYNAMIC, PF_R|PF_W, execProgHeaderRegionIndex+1, 1,
605                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 8 });
606    elfBinGen64->addProgramHeader({ PT_GNU_RELRO, PF_R, execProgHeaderRegionIndex+1,
607                    cxuint(1 + (!input->gotSymbols.empty())),
608                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 1 });
609    elfBinGen64->addProgramHeader({ PT_GNU_STACK, PF_R|PF_W, PHREGION_FILESTART, 0,
610                    true, 0, 0, 0 });
611   
612    if (input->newBinFormat)
613        // program header for note (new binary format)
614        elfBinGen64->addProgramHeader({ PT_NOTE, PF_R, 1, 1, true,
615                    Elf64Types::nobase, Elf64Types::nobase, 0, 4 });
616   
617    target = input->target.c_str();
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    }
626    // elf notes
627    elfBinGen64->addNote({"AMD", sizeof noteDescType1, noteDescType1, 1U});
628    noteBuf.reset(new cxbyte[0x1b]);
629    ::memcpy(noteBuf.get(), noteDescType3, 0x1b);
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);
633    elfBinGen64->addNote({"AMD", 0x1b, noteBuf.get(), 3U});
634    if (!target.empty())
635        elfBinGen64->addNote({"AMD", target.size(), (const cxbyte*)target.c_str(), 0xbU});
636   
637    metadataSize = input->metadataSize;
638    metadata = input->metadata;
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]);
651        // generate ROCm kernel config pointers
652        for (size_t k = 0; k < mdKernelsNum; k++)
653        {
654            auto it = binaryMapFind(symbolIndices.begin(), symbolIndices.end(), 
655                        input->metadataInfo.kernels[k].name);
656            if (it == symbolIndices.end() ||
657                (input->symbols[it->second].type != ROCmRegionType::FKERNEL &&
658                 input->symbols[it->second].type != ROCmRegionType::KERNEL))
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        }
663        // just generate ROCm metadata from info
664        generateROCmMetadata(input->metadataInfo, kernelConfigPtrs.get(), metadataStr);
665        metadataSize = metadataStr.size();
666        metadata = metadataStr.c_str();
667    }
668   
669    if (metadataSize != 0)
670        elfBinGen64->addNote({"AMD", metadataSize, (const cxbyte*)metadata, 0xaU});
671   
672    /// region and sections
673    elfBinGen64->addRegion(ElfRegion64::programHeaderTable());
674    if (input->newBinFormat)
675        elfBinGen64->addRegion(ElfRegion64::noteSection());
676    if (input->globalData != nullptr)
677        elfBinGen64->addRegion(ElfRegion64(input->globalDataSize, input->globalData, 4,
678                ".rodata", SHT_PROGBITS, SHF_ALLOC, 0, 0, Elf64Types::nobase));
679   
680    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
681                ".dynsym", SHT_DYNSYM, SHF_ALLOC, 0, BINGEN_DEFAULT, Elf64Types::nobase));
682    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 4,
683                ".hash", SHT_HASH, SHF_ALLOC,
684                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
685                Elf64Types::nobase));
686    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".dynstr", SHT_STRTAB,
687                SHF_ALLOC, 0, 0, Elf64Types::nobase));
688    if (!input->gotSymbols.empty())
689    {
690        ROCmRelaDynGen* sgen = new ROCmRelaDynGen(input);
691        rocmRelaDynGen = (void*)sgen;
692        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*sizeof(Elf64_Rela),
693                sgen, 8, ".rela.dyn", SHT_RELA, SHF_ALLOC,
694                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
695                Elf64Types::nobase, sizeof(Elf64_Rela)));
696    }
697    // '.text' with alignment=4096
698    elfBinGen64->addRegion(ElfRegion64(input->codeSize, (const cxbyte*)input->code, 
699              0x1000, ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 0, 0,
700              Elf64Types::nobase, 0, false, 256));
701    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 0x1000,
702                ".dynamic", SHT_DYNAMIC, SHF_ALLOC|SHF_WRITE,
703                mainBuiltinSectTable[ELFSECTID_DYNSTR-ELFSECTID_START], 0,
704                Elf64Types::nobase, 0, false, 8));
705    if (!input->gotSymbols.empty())
706    {
707        ROCmGotGen* sgen = new ROCmGotGen(input);
708        rocmGotGen = (void*)sgen;
709        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*8, sgen,
710                8, ".got", SHT_PROGBITS,
711                SHF_ALLOC|SHF_WRITE, 0, 0, Elf64Types::nobase));
712    }
713    if (!input->newBinFormat)
714    {
715        elfBinGen64->addRegion(ElfRegion64::noteSection());
716        elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1,
717                    ".AMDGPU.config", SHT_PROGBITS, 0));
718    }
719    elfBinGen64->addRegion(ElfRegion64(commentSize, (const cxbyte*)comment, 1, ".comment",
720              SHT_PROGBITS, SHF_MERGE|SHF_STRINGS, 0, 0, 0, 1));
721    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
722                ".symtab", SHT_SYMTAB, 0, 0, BINGEN_DEFAULT));
723    elfBinGen64->addRegion(ElfRegion64::shstrtabSection());
724    elfBinGen64->addRegion(ElfRegion64::strtabSection());
725    elfBinGen64->addRegion(ElfRegion64::sectionHeaderTable());
726   
727    /* extra sections */
728    for (const BinSection& section: input->extraSections)
729        elfBinGen64->addRegion(ElfRegion64(section, mainBuiltinSectTable,
730                         ROCMSECTID_MAX, mainSectionsNum));
731    updateSymbols();
732    binarySize = elfBinGen64->countSize();
733   
734    if (rocmRelaDynGen != nullptr)
735        ((ROCmRelaDynGen*)rocmRelaDynGen)->setGotOffset(
736                elfBinGen64->getRegionOffset(
737                        mainBuiltinSectTable[ROCMSECTID_GOT - ELFSECTID_START]));
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    }
776    /* extra symbols */
777    for (const BinSymbol& symbol: input->extraSymbols)
778    {
779        ElfSymbol64 sym(symbol, mainBuiltinSectTable,
780                         ROCMSECTID_MAX, mainSectionsNum);
781        elfBinGen64->addSymbol(sym);
782        elfBinGen64->addDynSymbol(sym);
783    }
784}
785
786void ROCmBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
787             Array<cxbyte>* aPtr)
788{
789    if (elfBinGen64 == nullptr)
790        prepareBinaryGen();
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     ****/
819    FastOutputBuffer bos(256, *os);
820    elfBinGen64->generate(bos);
821    assert(bos.getWritten() == binarySize);
822   
823    if (rocmGotGen != nullptr)
824    {
825        delete (ROCmGotGen*)rocmGotGen;
826        rocmGotGen = nullptr;
827    }
828    if (rocmRelaDynGen != nullptr)
829    {
830        delete (ROCmGotGen*)rocmRelaDynGen;
831        rocmRelaDynGen = nullptr;
832    }
833    }
834    catch(...)
835    {
836        os->exceptions(oldExceptions);
837        throw;
838    }
839    os->exceptions(oldExceptions);
840}
841
842void ROCmBinGenerator::generate(Array<cxbyte>& array)
843{
844    generateInternal(nullptr, nullptr, &array);
845}
846
847void ROCmBinGenerator::generate(std::ostream& os)
848{
849    generateInternal(&os, nullptr, nullptr);
850}
851
852void ROCmBinGenerator::generate(std::vector<char>& v)
853{
854    generateInternal(nullptr, &v, nullptr);
855}
Note: See TracBrowser for help on using the repository browser.