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

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

CLRadeonExtender: ROCm: Add handling MetadataV3 to ROCm binary format (only reading).

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