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

Last change on this file since 4927 was 4927, checked in by matszpk, 4 months ago

CLRadeonExtender: ROCm: Some changes in ROCm binary.

File size: 32.8 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   
247    for (size_t offset = 0; offset < notesSize; )
248    {
249        const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
250        size_t namesz = ULEV(nhdr->n_namesz);
251        size_t descsz = ULEV(nhdr->n_descsz);
252        if (usumGt(offset, namesz+descsz, notesSize))
253            throw BinException("Note offset+size out of range");
254       
255        const size_t alignedNamesz = ((namesz+3)&~size_t(3));
256        if ((namesz==4 &&
257            ::strcmp((const char*)noteContent+offset+ sizeof(Elf64_Nhdr), "AMD")==0) ||
258            (namesz==7 &&
259            ::strcmp((const char*)noteContent+offset+ sizeof(Elf64_Nhdr), "AMDGPU")==0))
260        {
261            const uint32_t noteType = ULEV(nhdr->n_type);
262            if ((noteType == 0xa && namesz==4) || (noteType == 0x20 && namesz==7))
263            {
264                if (namesz==7)
265                    metadataV3Format = true;
266                if (namesz==4 && metadataV3Format)
267                    throw Exception("MetadataV2 in MetadataV3 compliant binary!");
268                metadata = (char*)(noteContent+offset+sizeof(Elf64_Nhdr) + alignedNamesz);
269                metadataSize = descsz;
270            }
271            else if (noteType == 0xb && namesz==4)
272                target.assign((char*)(noteContent+offset+sizeof(Elf64_Nhdr) +
273                                        alignedNamesz), descsz);
274        }
275        size_t align = (((alignedNamesz+descsz)&3)!=0) ? 4-((alignedNamesz+descsz)&3) : 0;
276        offset += sizeof(Elf64_Nhdr) + alignedNamesz + descsz + align;
277    }
278   
279    if (hasRegionMap())
280    {
281        // create region map
282        regionsMap.resize(regionsNum);
283        for (size_t i = 0; i < regionsNum; i++)
284            regionsMap[i] = std::make_pair(regions[i].regionName, i);
285        // sort region map
286        mapSort(regionsMap.begin(), regionsMap.end());
287    }
288   
289    if ((creationFlags & ROCMBIN_CREATE_METADATAINFO) != 0 &&
290        metadata != nullptr && metadataSize != 0)
291    {
292        metadataInfo.reset(new ROCmMetadata());
293        if (!metadataV3Format)
294            parseROCmMetadata(metadataSize, metadata, *metadataInfo);
295        else
296            parseROCmMetadataMsgPack(metadataSize,
297                    reinterpret_cast<const cxbyte*>(metadata), *metadataInfo);
298       
299        if (hasKernelInfoMap())
300        {
301            const std::vector<ROCmKernelMetadata>& kernels = metadataInfo->kernels;
302            kernelInfosMap.resize(kernels.size());
303            for (size_t i = 0; i < kernelInfosMap.size(); i++)
304                kernelInfosMap[i] = std::make_pair(kernels[i].name, i);
305            // sort region map
306            mapSort(kernelInfosMap.begin(), kernelInfosMap.end());
307        }
308    }
309   
310    if (llvm10BinFormat)
311    {
312        // remove global data for LLVM10 bin format
313        globalData = nullptr;
314        globalDataSize = 0;
315    }
316}
317
318/// determint GPU device from ROCm notes
319GPUDeviceType ROCmBinary::determineGPUDeviceType(uint32_t& outArchMinor,
320                     uint32_t& outArchStepping) const
321{
322    uint32_t archMajor = 0;
323    uint32_t archMinor = 0;
324    uint32_t archStepping = 0;
325   
326    {
327        const cxbyte* noteContent = (const cxbyte*)getNotes();
328        if (noteContent==nullptr)
329            throw BinException("Missing notes in inner binary!");
330        size_t notesSize = getNotesSize();
331        // find note about AMDGPU
332        for (size_t offset = 0; offset < notesSize; )
333        {
334            const Elf64_Nhdr* nhdr = (const Elf64_Nhdr*)(noteContent + offset);
335            size_t namesz = ULEV(nhdr->n_namesz);
336            size_t descsz = ULEV(nhdr->n_descsz);
337            if (usumGt(offset, namesz+descsz, notesSize))
338                throw BinException("Note offset+size out of range");
339            if (ULEV(nhdr->n_type) == 0x3 && namesz==4 && descsz>=0x1a &&
340                ::strcmp((const char*)noteContent+offset+sizeof(Elf64_Nhdr), "AMD")==0)
341            {    // AMDGPU type
342                const uint32_t* content = (const uint32_t*)
343                        (noteContent+offset+sizeof(Elf64_Nhdr) + 4);
344                archMajor = ULEV(content[1]);
345                archMinor = ULEV(content[2]);
346                archStepping = ULEV(content[3]);
347            }
348            size_t align = (((namesz+descsz)&3)!=0) ? 4-((namesz+descsz)&3) : 0;
349            offset += sizeof(Elf64_Nhdr) + namesz + descsz + align;
350        }
351    }
352    // determine device type
353    GPUDeviceType deviceType = getGPUDeviceTypeFromArchVersion(archMajor, archMinor,
354                                    archStepping);
355    outArchMinor = archMinor;
356    outArchStepping = archStepping;
357    return deviceType;
358}
359
360const ROCmRegion& ROCmBinary::getRegion(const char* name) const
361{
362    RegionMap::const_iterator it = binaryMapFind(regionsMap.begin(),
363                             regionsMap.end(), name);
364    if (it == regionsMap.end())
365        throw BinException("Can't find region name");
366    return regions[it->second];
367}
368
369const ROCmKernelMetadata& ROCmBinary::getKernelInfo(const char* name) const
370{
371    if (!hasMetadataInfo())
372        throw BinException("Can't find kernel info name");
373    RegionMap::const_iterator it = binaryMapFind(kernelInfosMap.begin(),
374                             kernelInfosMap.end(), name);
375    if (it == kernelInfosMap.end())
376        throw BinException("Can't find kernel info name");
377    return metadataInfo->kernels[it->second];
378}
379
380// if ROCm binary
381bool CLRX::isROCmBinary(size_t binarySize, const cxbyte* binary)
382{
383    if (!isElfBinary(binarySize, binary))
384        return false;
385    if (binary[EI_CLASS] != ELFCLASS64)
386        return false;
387    const Elf64_Ehdr* ehdr = reinterpret_cast<const Elf64_Ehdr*>(binary);
388    if (ULEV(ehdr->e_machine) != 0xe0)
389        return false;
390    return true;
391}
392
393
394void ROCmInput::addEmptyKernel(const char* kernelName)
395{
396    symbols.push_back({ kernelName, 0, 0, ROCmRegionType::KERNEL });
397}
398
399/* ROCm section generators */
400
401class CLRX_INTERNAL ROCmGotGen: public ElfRegionContent
402{
403private:
404    const ROCmInput* input;
405public:
406    explicit ROCmGotGen(const ROCmInput* _input) : input(_input)
407    { }
408   
409    void operator()(FastOutputBuffer& fob) const
410    {
411        fob.fill(input->gotSymbols.size()*8, 0);
412    }
413};
414
415class CLRX_INTERNAL ROCmRelaDynGen: public ElfRegionContent
416{
417private:
418    size_t gotOffset;
419    const ROCmInput* input;
420public:
421    explicit ROCmRelaDynGen(const ROCmInput* _input) : gotOffset(0), input(_input)
422    { }
423   
424    void setGotOffset(size_t _gotOffset)
425    { gotOffset = _gotOffset; }
426   
427    void operator()(FastOutputBuffer& fob) const
428    {
429        for (size_t i = 0; i < input->gotSymbols.size(); i++)
430        {
431            size_t symIndex = input->gotSymbols[i];
432            Elf64_Rela rela{};
433            SLEV(rela.r_offset, gotOffset + 8*i);
434            SLEV(rela.r_info, ELF64_R_INFO(symIndex + 1, 3));
435            rela.r_addend = 0;
436            fob.writeObject(rela);
437        }
438    }
439};
440
441/*
442 * ROCm Binary Generator
443 */
444
445ROCmBinGenerator::ROCmBinGenerator() : manageable(false), input(nullptr)
446{ }
447
448ROCmBinGenerator::ROCmBinGenerator(const ROCmInput* rocmInput)
449        : manageable(false), input(rocmInput), rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
450{ }
451
452ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
453        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
454        size_t globalDataSize, const cxbyte* globalData,
455        const std::vector<ROCmSymbolInput>& symbols) :
456        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
457{
458    std::unique_ptr<ROCmInput> _input(new ROCmInput{});
459    _input->deviceType = deviceType;
460    _input->archMinor = archMinor;
461    _input->archStepping = archStepping;
462    _input->eflags = 0;
463    _input->newBinFormat = false;
464    _input->globalDataSize = globalDataSize;
465    _input->globalData = globalData;
466    _input->symbols = symbols;
467    _input->codeSize = codeSize;
468    _input->code = code;
469    _input->commentSize = 0;
470    _input->comment = nullptr;
471    _input->target = "";
472    _input->targetTripple = "";
473    _input->metadataSize = 0;
474    _input->metadata = nullptr;
475    _input->useMetadataInfo = false;
476    _input->metadataInfo = ROCmMetadata{};
477    input = _input.release();
478}
479
480ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
481        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
482        size_t globalDataSize, const cxbyte* globalData,
483        std::vector<ROCmSymbolInput>&& symbols) :
484        rocmGotGen(nullptr), rocmRelaDynGen(nullptr)
485{
486    std::unique_ptr<ROCmInput> _input(new ROCmInput{});
487    _input->deviceType = deviceType;
488    _input->archMinor = archMinor;
489    _input->archStepping = archStepping;
490    _input->eflags = 0;
491    _input->newBinFormat = false;
492    _input->globalDataSize = globalDataSize;
493    _input->globalData = globalData;
494    _input->symbols = std::move(symbols);
495    _input->codeSize = codeSize;
496    _input->code = code;
497    _input->commentSize = 0;
498    _input->comment = nullptr;
499    _input->target = "";
500    _input->targetTripple = "";
501    _input->metadataSize = 0;
502    _input->metadata = nullptr;
503    _input->useMetadataInfo = false;
504    _input->metadataInfo = ROCmMetadata{};
505    input = _input.release();
506}
507
508ROCmBinGenerator::~ROCmBinGenerator()
509{
510    if (manageable)
511        delete input;
512    if (rocmGotGen!=nullptr)
513        delete (ROCmGotGen*)rocmGotGen;
514    if (rocmRelaDynGen!=nullptr)
515        delete (ROCmRelaDynGen*)rocmRelaDynGen;
516}
517
518void ROCmBinGenerator::setInput(const ROCmInput* input)
519{
520    if (manageable)
521        delete input;
522    manageable = false;
523    this->input = input;
524}
525
526// ELF notes contents
527static const cxbyte noteDescType1[8] =
528{ 2, 0, 0, 0, 1, 0, 0, 0 };
529
530static const cxbyte noteDescType3[27] =
531{ 4, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
532  'A', 'M', 'D', 0, 'A', 'M', 'D', 'G', 'P', 'U', 0 };
533
534static inline void addMainSectionToTable(cxuint& sectionsNum, uint16_t* builtinTable,
535                cxuint elfSectId)
536{ builtinTable[elfSectId - ELFSECTID_START] = sectionsNum++; }
537
538void ROCmBinGenerator::prepareBinaryGen()
539{
540    AMDGPUArchVersion amdGpuArchValues = getGPUArchVersion(input->deviceType,
541                GPUArchVersionTable::ROCM);
542    if (input->archMinor!=UINT32_MAX)
543        amdGpuArchValues.minor = input->archMinor;
544    if (input->archStepping!=UINT32_MAX)
545        amdGpuArchValues.stepping = input->archStepping;
546   
547    comment = "CLRX ROCmBinGenerator " CLRX_VERSION;
548    commentSize = ::strlen(comment);
549    if (input->comment!=nullptr)
550    {
551        // if comment, store comment section
552        comment = input->comment;
553        commentSize = input->commentSize;
554        if (commentSize==0)
555            commentSize = ::strlen(comment);
556    }
557   
558    uint32_t eflags = input->newBinFormat ? 2 : 0;
559    if (input->eflags != BINGEN_DEFAULT)
560        eflags = input->eflags;
561   
562    std::fill(mainBuiltinSectTable,
563              mainBuiltinSectTable + ROCMSECTID_MAX-ELFSECTID_START+1, SHN_UNDEF);
564    mainSectionsNum = 1;
565   
566    // generate main builtin section table (for section id translation)
567    if (input->newBinFormat)
568        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
569    if (input->globalData != nullptr)
570        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_RODATA);
571    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSYM);
572    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_HASH);
573    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_DYNSTR);
574    if (!input->gotSymbols.empty())
575        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_RELADYN);
576    const cxuint execProgHeaderRegionIndex = mainSectionsNum;
577    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_TEXT);
578    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_DYNAMIC);
579    if (!input->gotSymbols.empty())
580        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GOT);
581    if (!input->newBinFormat)
582    {
583        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_NOTE);
584        addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ROCMSECTID_GPUCONFIG);
585    }
586    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_COMMENT);
587    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SYMTAB);
588    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_SHSTRTAB);
589    addMainSectionToTable(mainSectionsNum, mainBuiltinSectTable, ELFSECTID_STRTAB);
590   
591    elfBinGen64.reset(new ElfBinaryGen64({ 0U, 0U, 0x40, 0, ET_DYN, 0xe0, EV_CURRENT,
592            cxuint(input->newBinFormat ? execProgHeaderRegionIndex : UINT_MAX), 0, eflags },
593            true, true, true, PHREGION_FILESTART));
594   
595    static const int32_t dynTags[] = {
596        DT_SYMTAB, DT_SYMENT, DT_STRTAB, DT_STRSZ, DT_HASH };
597    elfBinGen64->addDynamics(sizeof(dynTags)/sizeof(int32_t), dynTags);
598   
599    // elf program headers
600    elfBinGen64->addProgramHeader({ PT_PHDR, PF_R, 0, 1,
601                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
602    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R, PHREGION_FILESTART,
603                    execProgHeaderRegionIndex,
604                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 0x1000 });
605    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_X, execProgHeaderRegionIndex, 1,
606                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
607    elfBinGen64->addProgramHeader({ PT_LOAD, PF_R|PF_W, execProgHeaderRegionIndex+1,
608                    cxuint(1 + (!input->gotSymbols.empty())),
609                    true, Elf64Types::nobase, Elf64Types::nobase, 0 });
610    elfBinGen64->addProgramHeader({ PT_DYNAMIC, PF_R|PF_W, execProgHeaderRegionIndex+1, 1,
611                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 8 });
612    elfBinGen64->addProgramHeader({ PT_GNU_RELRO, PF_R, execProgHeaderRegionIndex+1,
613                    cxuint(1 + (!input->gotSymbols.empty())),
614                    true, Elf64Types::nobase, Elf64Types::nobase, 0, 1 });
615    elfBinGen64->addProgramHeader({ PT_GNU_STACK, PF_R|PF_W, PHREGION_FILESTART, 0,
616                    true, 0, 0, 0 });
617   
618    if (input->newBinFormat)
619        // program header for note (new binary format)
620        elfBinGen64->addProgramHeader({ PT_NOTE, PF_R, 1, 1, true,
621                    Elf64Types::nobase, Elf64Types::nobase, 0, 4 });
622   
623    target = input->target.c_str();
624    if (target.empty() && !input->targetTripple.empty())
625    {
626        target = input->targetTripple.c_str();
627        char dbuf[20];
628        snprintf(dbuf, 20, "-gfx%u%u%u", amdGpuArchValues.major, amdGpuArchValues.minor,
629                 amdGpuArchValues.stepping);
630        target += dbuf;
631    }
632    // elf notes
633    elfBinGen64->addNote({"AMD", sizeof noteDescType1, noteDescType1, 1U});
634    noteBuf.reset(new cxbyte[0x1b]);
635    ::memcpy(noteBuf.get(), noteDescType3, 0x1b);
636    SULEV(*(uint32_t*)(noteBuf.get()+4), amdGpuArchValues.major);
637    SULEV(*(uint32_t*)(noteBuf.get()+8), amdGpuArchValues.minor);
638    SULEV(*(uint32_t*)(noteBuf.get()+12), amdGpuArchValues.stepping);
639    elfBinGen64->addNote({"AMD", 0x1b, noteBuf.get(), 3U});
640    if (!target.empty())
641        elfBinGen64->addNote({"AMD", target.size(), (const cxbyte*)target.c_str(), 0xbU});
642   
643    metadataSize = input->metadataSize;
644    metadata = input->metadata;
645    if (input->useMetadataInfo)
646    {
647        // generate ROCm metadata
648        std::vector<std::pair<CString, size_t> > symbolIndices(input->symbols.size());
649        // create sorted indices of symbols by its name
650        for (size_t k = 0; k < input->symbols.size(); k++)
651            symbolIndices[k] = std::make_pair(input->symbols[k].symbolName, k);
652        mapSort(symbolIndices.begin(), symbolIndices.end());
653       
654        const size_t mdKernelsNum = input->metadataInfo.kernels.size();
655        std::unique_ptr<const ROCmKernelConfig*[]> kernelConfigPtrs(
656                new const ROCmKernelConfig*[mdKernelsNum]);
657        // generate ROCm kernel config pointers
658        for (size_t k = 0; k < mdKernelsNum; k++)
659        {
660            auto it = binaryMapFind(symbolIndices.begin(), symbolIndices.end(), 
661                        input->metadataInfo.kernels[k].name);
662            if (it == symbolIndices.end() ||
663                (input->symbols[it->second].type != ROCmRegionType::FKERNEL &&
664                 input->symbols[it->second].type != ROCmRegionType::KERNEL))
665                throw BinGenException("Kernel in metadata doesn't exists in code");
666            kernelConfigPtrs[k] = reinterpret_cast<const ROCmKernelConfig*>(
667                        input->code + input->symbols[it->second].offset);
668        }
669        // just generate ROCm metadata from info
670        generateROCmMetadata(input->metadataInfo, kernelConfigPtrs.get(), metadataStr);
671        metadataSize = metadataStr.size();
672        metadata = metadataStr.c_str();
673    }
674   
675    if (metadataSize != 0)
676        elfBinGen64->addNote({"AMD", metadataSize, (const cxbyte*)metadata, 0xaU});
677   
678    /// region and sections
679    elfBinGen64->addRegion(ElfRegion64::programHeaderTable());
680    if (input->newBinFormat)
681        elfBinGen64->addRegion(ElfRegion64::noteSection());
682    if (input->globalData != nullptr)
683        elfBinGen64->addRegion(ElfRegion64(input->globalDataSize, input->globalData, 4,
684                ".rodata", SHT_PROGBITS, SHF_ALLOC, 0, 0, Elf64Types::nobase));
685   
686    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
687                ".dynsym", SHT_DYNSYM, SHF_ALLOC, 0, BINGEN_DEFAULT, Elf64Types::nobase));
688    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 4,
689                ".hash", SHT_HASH, SHF_ALLOC,
690                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
691                Elf64Types::nobase));
692    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1, ".dynstr", SHT_STRTAB,
693                SHF_ALLOC, 0, 0, Elf64Types::nobase));
694    if (!input->gotSymbols.empty())
695    {
696        ROCmRelaDynGen* sgen = new ROCmRelaDynGen(input);
697        rocmRelaDynGen = (void*)sgen;
698        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*sizeof(Elf64_Rela),
699                sgen, 8, ".rela.dyn", SHT_RELA, SHF_ALLOC,
700                mainBuiltinSectTable[ELFSECTID_DYNSYM-ELFSECTID_START], 0,
701                Elf64Types::nobase, sizeof(Elf64_Rela)));
702    }
703    // '.text' with alignment=4096
704    elfBinGen64->addRegion(ElfRegion64(input->codeSize, (const cxbyte*)input->code, 
705              0x1000, ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 0, 0,
706              Elf64Types::nobase, 0, false, 256));
707    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 0x1000,
708                ".dynamic", SHT_DYNAMIC, SHF_ALLOC|SHF_WRITE,
709                mainBuiltinSectTable[ELFSECTID_DYNSTR-ELFSECTID_START], 0,
710                Elf64Types::nobase, 0, false, 8));
711    if (!input->gotSymbols.empty())
712    {
713        ROCmGotGen* sgen = new ROCmGotGen(input);
714        rocmGotGen = (void*)sgen;
715        elfBinGen64->addRegion(ElfRegion64(input->gotSymbols.size()*8, sgen,
716                8, ".got", SHT_PROGBITS,
717                SHF_ALLOC|SHF_WRITE, 0, 0, Elf64Types::nobase));
718    }
719    if (!input->newBinFormat)
720    {
721        elfBinGen64->addRegion(ElfRegion64::noteSection());
722        elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 1,
723                    ".AMDGPU.config", SHT_PROGBITS, 0));
724    }
725    elfBinGen64->addRegion(ElfRegion64(commentSize, (const cxbyte*)comment, 1, ".comment",
726              SHT_PROGBITS, SHF_MERGE|SHF_STRINGS, 0, 0, 0, 1));
727    elfBinGen64->addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 8,
728                ".symtab", SHT_SYMTAB, 0, 0, BINGEN_DEFAULT));
729    elfBinGen64->addRegion(ElfRegion64::shstrtabSection());
730    elfBinGen64->addRegion(ElfRegion64::strtabSection());
731    elfBinGen64->addRegion(ElfRegion64::sectionHeaderTable());
732   
733    /* extra sections */
734    for (const BinSection& section: input->extraSections)
735        elfBinGen64->addRegion(ElfRegion64(section, mainBuiltinSectTable,
736                         ROCMSECTID_MAX, mainSectionsNum));
737    updateSymbols();
738    binarySize = elfBinGen64->countSize();
739   
740    if (rocmRelaDynGen != nullptr)
741        ((ROCmRelaDynGen*)rocmRelaDynGen)->setGotOffset(
742                elfBinGen64->getRegionOffset(
743                        mainBuiltinSectTable[ROCMSECTID_GOT - ELFSECTID_START]));
744}
745
746void ROCmBinGenerator::updateSymbols()
747{
748    elfBinGen64->clearSymbols();
749    elfBinGen64->clearDynSymbols();
750    // add symbols (kernels, function kernels and data symbols)
751    elfBinGen64->addSymbol(ElfSymbol64("_DYNAMIC",
752                  mainBuiltinSectTable[ROCMSECTID_DYNAMIC-ELFSECTID_START],
753                  ELF64_ST_INFO(STB_LOCAL, STT_NOTYPE), STV_HIDDEN, true, 0, 0));
754    const uint16_t textSectIndex = mainBuiltinSectTable[ELFSECTID_TEXT-ELFSECTID_START];
755    for (const ROCmSymbolInput& symbol: input->symbols)
756    {
757        ElfSymbol64 elfsym;
758        switch (symbol.type)
759        {
760            case ROCmRegionType::KERNEL:
761                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
762                      ELF64_ST_INFO(STB_GLOBAL, STT_GNU_IFUNC), 0, true,
763                      symbol.offset, symbol.size);
764                break;
765            case ROCmRegionType::FKERNEL:
766                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
767                      ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), 0, true,
768                      symbol.offset, symbol.size);
769                break;
770            case ROCmRegionType::DATA:
771                elfsym = ElfSymbol64(symbol.symbolName.c_str(), textSectIndex,
772                      ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT), 0, true,
773                      symbol.offset, symbol.size);
774                break;
775            default:
776                break;
777        }
778        // add to symbols and dynamic symbols table
779        elfBinGen64->addSymbol(elfsym);
780        elfBinGen64->addDynSymbol(elfsym);
781    }
782    /* extra symbols */
783    for (const BinSymbol& symbol: input->extraSymbols)
784    {
785        ElfSymbol64 sym(symbol, mainBuiltinSectTable,
786                         ROCMSECTID_MAX, mainSectionsNum);
787        elfBinGen64->addSymbol(sym);
788        elfBinGen64->addDynSymbol(sym);
789    }
790}
791
792void ROCmBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
793             Array<cxbyte>* aPtr)
794{
795    if (elfBinGen64 == nullptr)
796        prepareBinaryGen();
797    /****
798     * prepare for write binary to output
799     ****/
800    std::unique_ptr<std::ostream> outStreamHolder;
801    std::ostream* os = nullptr;
802    if (aPtr != nullptr)
803    {
804        aPtr->resize(binarySize);
805        outStreamHolder.reset(
806                new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
807        os = outStreamHolder.get();
808    }
809    else if (vPtr != nullptr)
810    {
811        vPtr->resize(binarySize);
812        outStreamHolder.reset(new VectorOStream(*vPtr));
813        os = outStreamHolder.get();
814    }
815    else // from argument
816        os = osPtr;
817   
818    const std::ios::iostate oldExceptions = os->exceptions();
819    try
820    {
821    os->exceptions(std::ios::failbit | std::ios::badbit);
822    /****
823     * write binary to output
824     ****/
825    FastOutputBuffer bos(256, *os);
826    elfBinGen64->generate(bos);
827    assert(bos.getWritten() == binarySize);
828   
829    if (rocmGotGen != nullptr)
830    {
831        delete (ROCmGotGen*)rocmGotGen;
832        rocmGotGen = nullptr;
833    }
834    if (rocmRelaDynGen != nullptr)
835    {
836        delete (ROCmGotGen*)rocmRelaDynGen;
837        rocmRelaDynGen = nullptr;
838    }
839    }
840    catch(...)
841    {
842        os->exceptions(oldExceptions);
843        throw;
844    }
845    os->exceptions(oldExceptions);
846}
847
848void ROCmBinGenerator::generate(Array<cxbyte>& array)
849{
850    generateInternal(nullptr, nullptr, &array);
851}
852
853void ROCmBinGenerator::generate(std::ostream& os)
854{
855    generateInternal(&os, nullptr, nullptr);
856}
857
858void ROCmBinGenerator::generate(std::vector<char>& v)
859{
860    generateInternal(nullptr, &v, nullptr);
861}
Note: See TracBrowser for help on using the repository browser.