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

Last change on this file since 2534 was 2534, checked in by matszpk, 4 years ago

CLRadeonExtender: Add first code for ROCm binary generator.

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