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

Last change on this file since 2535 was 2535, checked in by matszpk, 3 years ago

CLRadeonExtender: Add next stuff to ROCmBinGenerator. Add CLRX version to default Gallium comment (ROCm comment).

File size: 9.0 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2016 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 <cstdint>
22#include <algorithm>
23#include <utility>
24#include <CLRX/amdbin/ElfBinaries.h>
25#include <CLRX/utils/Utilities.h>
26#include <CLRX/utils/MemAccess.h>
27#include <CLRX/utils/InputOutput.h>
28#include <CLRX/utils/Containers.h>
29#include <CLRX/amdbin/ROCmBinaries.h>
30
31using namespace CLRX;
32
33/* TODO: add support for various kernel code offset (now only 256 is supported) */
34
35ROCmBinary::ROCmBinary(size_t binaryCodeSize, cxbyte* binaryCode, Flags creationFlags)
36        : ElfBinary64(binaryCodeSize, binaryCode, creationFlags),
37          regionsNum(0), codeSize(0), code(nullptr)
38{
39    cxuint textIndex = SHN_UNDEF;
40    try
41    { textIndex = getSectionIndex(".text"); }
42    catch(const Exception& ex)
43    { } // ignore failed
44    uint64_t codeOffset = 0;
45    if (textIndex!=SHN_UNDEF)
46    {
47        code = getSectionContent(textIndex);
48        const Elf64_Shdr& textShdr = getSectionHeader(textIndex);
49        codeSize = ULEV(textShdr.sh_size);
50        codeOffset = ULEV(textShdr.sh_offset);
51    }
52   
53    regionsNum = 0;
54    const size_t symbolsNum = getSymbolsNum();
55    for (size_t i = 0; i < symbolsNum; i++)
56    {   // count regions number
57        const Elf64_Sym& sym = getSymbol(i);
58        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
59        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
60        if (sym.st_shndx==textIndex &&
61            (symType==STT_GNU_IFUNC || (bind==STB_GLOBAL && symType==STT_OBJECT)))
62            regionsNum++;
63    }
64    if (code==nullptr && regionsNum!=0)
65        throw Exception("No code if regions number is not zero");
66    regions.reset(new ROCmRegion[regionsNum]);
67    size_t j = 0;
68    typedef std::pair<uint64_t, size_t> RegionOffsetEntry;
69    std::unique_ptr<RegionOffsetEntry[]> symOffsets(new RegionOffsetEntry[regionsNum]);
70   
71    for (size_t i = 0; i < symbolsNum; i++)
72    {
73        const Elf64_Sym& sym = getSymbol(i);
74        if (sym.st_shndx!=textIndex)
75            continue;   // if not in '.text' section
76        const size_t value = ULEV(sym.st_value);
77        if (value < codeOffset)
78            throw Exception("Region offset is too small!");
79        const size_t size = ULEV(sym.st_size);
80       
81        const cxbyte symType = ELF64_ST_TYPE(sym.st_info);
82        const cxbyte bind = ELF64_ST_BIND(sym.st_info);
83        if (symType==STT_GNU_IFUNC || (bind==STB_GLOBAL && symType==STT_OBJECT))
84        {
85            const bool isKernel = (symType==STT_GNU_IFUNC);
86            symOffsets[j] = std::make_pair(value, j);
87            if (isKernel && value+0x100 > codeOffset+codeSize)
88                throw Exception("Kernel offset is too big!");
89            regions[j++] = { getSymbolName(i), size, value, isKernel };
90        }
91    }
92    std::sort(symOffsets.get(), symOffsets.get()+regionsNum,
93            [](const RegionOffsetEntry& a, const RegionOffsetEntry& b)
94            { return a.first < b.first; });
95    // checking distance between regions
96    for (size_t i = 1; i <= regionsNum; i++)
97    {
98        size_t end = (i<regionsNum) ? symOffsets[i].first : codeOffset+codeSize;
99        ROCmRegion& region = regions[symOffsets[i-1].second];
100        if (region.isKernel && symOffsets[i-1].first+0x100 > end)
101            throw Exception("Kernel size is too small!");
102       
103        const size_t regSize = end - symOffsets[i-1].first;
104        if (region.size==0)
105            region.size = regSize;
106        else
107            region.size = std::min(regSize, region.size);
108    }
109   
110    if (hasRegionMap())
111    {   // create region map
112        regionsMap.resize(regionsNum);
113        for (size_t i = 0; i < regionsNum; i++)
114            regionsMap[i] = std::make_pair(regions[i].regionName, i);
115        mapSort(regionsMap.begin(), regionsMap.end());
116    }
117}
118
119const ROCmRegion& ROCmBinary::getRegion(const char* name) const
120{
121    RegionMap::const_iterator it = binaryMapFind(regionsMap.begin(),
122                             regionsMap.end(), name);
123    if (it == regionsMap.end())
124        throw Exception("Can't find region name");
125    return regions[it->second];
126}
127
128bool CLRX::isROCmBinary(size_t binarySize, const cxbyte* binary)
129{
130    if (!isElfBinary(binarySize, binary))
131        return false;
132    if (binary[EI_CLASS] != ELFCLASS64)
133        return false;
134    const Elf64_Ehdr* ehdr = reinterpret_cast<const Elf64_Ehdr*>(binary);
135    if (ULEV(ehdr->e_machine) != 0xe0 || ULEV(ehdr->e_flags)!=0)
136        return false;
137    return true;
138}
139
140/*
141 * ROCm Binary Generator
142 */
143
144ROCmBinGenerator::ROCmBinGenerator() : manageable(false), input(nullptr)
145{ }
146
147ROCmBinGenerator::ROCmBinGenerator(const ROCmInput* rocmInput)
148        : manageable(false), input(rocmInput)
149{ }
150
151ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
152        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
153        const std::vector<ROCmSymbolInput>& symbols)
154{
155    input = new ROCmInput{ deviceType, archMinor, archStepping, symbols, codeSize, code };
156}
157
158ROCmBinGenerator::ROCmBinGenerator(GPUDeviceType deviceType,
159        uint32_t archMinor, uint32_t archStepping, size_t codeSize, const cxbyte* code,
160        std::vector<ROCmSymbolInput>&& symbols)
161{
162    input = new ROCmInput{ deviceType, archMinor, archStepping, std::move(symbols),
163                codeSize, code };
164}
165
166ROCmBinGenerator::~ROCmBinGenerator()
167{
168    if (manageable)
169        delete input;
170}
171
172void ROCmBinGenerator::setInput(const ROCmInput* input)
173{
174    if (manageable)
175        delete input;
176    manageable = false;
177    this->input = input;
178}
179
180void ROCmBinGenerator::generateInternal(std::ostream* osPtr, std::vector<char>* vPtr,
181             Array<cxbyte>* aPtr) const
182{
183    ElfBinaryGen64 elfBinGen64;
184   
185    const char* comment = "CLRX ROCmBinGenerator " CLRX_VERSION;
186    uint32_t commentSize = ::strlen(comment);
187    if (input->comment!=nullptr)
188    {   // if comment, store comment section
189        comment = input->comment;
190        commentSize = input->commentSize;
191        if (commentSize==0)
192            commentSize = ::strlen(comment);
193    }
194   
195    elfBinGen64.addRegion(ElfRegion64::programHeaderTable());
196    elfBinGen64.addRegion(ElfRegion64::dynsymSection());
197    elfBinGen64.addRegion(ElfRegion64::dynstrSection());
198    elfBinGen64.addRegion(ElfRegion64(input->codeSize, (const cxbyte*)input->code, 
199              0x1000, ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 0, 0, 0, 0,
200              false, 256));
201    elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 0x1000, ".dynamic",
202              SHT_DYNAMIC, SHF_ALLOC|SHF_WRITE, 2, 0, 0, 0, false, 8));
203    elfBinGen64.addRegion(ElfRegion64(0, (const cxbyte*)nullptr, 4, ".note",
204              SHT_NOTE, 0));
205    elfBinGen64.addRegion(ElfRegion64(commentSize, (const cxbyte*)comment, 1, ".comment",
206              SHT_PROGBITS, SHF_MERGE|SHF_STRINGS));
207    elfBinGen64.addRegion(ElfRegion64::symtabSection());
208    elfBinGen64.addRegion(ElfRegion64::shstrtabSection());
209    elfBinGen64.addRegion(ElfRegion64::strtabSection());
210    elfBinGen64.addRegion(ElfRegion64::sectionHeaderTable());
211   
212    size_t binarySize;
213    /****
214     * prepare for write binary to output
215     ****/
216    std::unique_ptr<std::ostream> outStreamHolder;
217    std::ostream* os = nullptr;
218    if (aPtr != nullptr)
219    {
220        aPtr->resize(binarySize);
221        outStreamHolder.reset(
222                new ArrayOStream(binarySize, reinterpret_cast<char*>(aPtr->data())));
223        os = outStreamHolder.get();
224    }
225    else if (vPtr != nullptr)
226    {
227        vPtr->resize(binarySize);
228        outStreamHolder.reset(new VectorOStream(*vPtr));
229        os = outStreamHolder.get();
230    }
231    else // from argument
232        os = osPtr;
233   
234    const std::ios::iostate oldExceptions = os->exceptions();
235    try
236    {
237    os->exceptions(std::ios::failbit | std::ios::badbit);
238    /****
239     * write binary to output
240     ****/
241    //elfBinGen64->generate(bos);
242    //assert(bos.getWritten() == binarySize);
243    }
244    catch(...)
245    {
246        os->exceptions(oldExceptions);
247        throw;
248    }
249    os->exceptions(oldExceptions);
250}
251
252void ROCmBinGenerator::generate(Array<cxbyte>& array) const
253{
254    generateInternal(nullptr, nullptr, &array);
255}
256
257void ROCmBinGenerator::generate(std::ostream& os) const
258{
259    generateInternal(&os, nullptr, nullptr);
260}
261
262void ROCmBinGenerator::generate(std::vector<char>& v) const
263{
264    generateInternal(nullptr, &v, nullptr);
265}
Note: See TracBrowser for help on using the repository browser.