source: CLRX/CLRadeonExtender/trunk/amdasm/Disassembler.cpp @ 2526

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

CLRadeonExtender: Delegate writeLabelsTo... to public API. fix dontPrintLabelsAfterCode.
ROCm: Print labels between data regions and config.

File size: 21.2 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 <string>
22#include <cstring>
23#include <ostream>
24#include <cstring>
25#include <memory>
26#include <vector>
27#include <utility>
28#include <algorithm>
29#include <CLRX/utils/Utilities.h>
30#include <CLRX/amdbin/GalliumBinaries.h>
31#include <CLRX/utils/MemAccess.h>
32#include <CLRX/utils/GPUId.h>
33#include <CLRX/amdasm/Disassembler.h>
34#include "DisasmInternals.h"
35
36using namespace CLRX;
37
38ISADisassembler::ISADisassembler(Disassembler& _disassembler, cxuint outBufSize)
39        : disassembler(_disassembler), startOffset(0), labelStartOffset(0),
40          dontPrintLabelsAfterCode(false), output(outBufSize, _disassembler.getOutput())
41{ }
42
43ISADisassembler::~ISADisassembler()
44{ }
45
46void ISADisassembler::writeLabelsToPosition(size_t pos, LabelIter& labelIter,
47              NamedLabelIter& namedLabelIter)
48{
49    pos += startOffset; // fix
50    if ((namedLabelIter != namedLabels.end() && namedLabelIter->first <= pos) ||
51            (labelIter != labels.end() && *labelIter <= pos))
52    {
53        size_t curPos = SIZE_MAX;
54        if (labelIter != labels.end())
55            curPos = *labelIter;
56        if (namedLabelIter != namedLabels.end())
57            curPos = std::min(curPos, namedLabelIter->first);
58       
59        bool haveLabel;
60        do {
61            haveLabel = false;
62            const bool haveNumberedLabel =
63                    labelIter != labels.end() && *labelIter <= pos;
64            const bool haveNamedLabel =
65                    (namedLabelIter != namedLabels.end() && namedLabelIter->first <= pos);
66           
67            size_t namedPos = SIZE_MAX;
68            size_t numberedPos = SIZE_MAX;
69            if (haveNumberedLabel)
70                numberedPos = *labelIter;
71            if (haveNamedLabel)
72                namedPos = namedLabelIter->first;
73           
74            /// print numbered (not named) label in form .L[position]_[sectionCount]
75            if (numberedPos <= namedPos && haveNumberedLabel)
76            {
77                curPos = *labelIter;
78                char* buf = output.reserve(70);
79                size_t bufPos = 0;
80                buf[bufPos++] = '.';
81                buf[bufPos++] = 'L';
82                bufPos += itocstrCStyle(*labelIter, buf+bufPos, 22, 10, 0, false);
83                buf[bufPos++] = '_';
84                bufPos += itocstrCStyle(disassembler.sectionCount,
85                                buf+bufPos, 22, 10, 0, false);
86                if (curPos != pos)
87                {   // if label shifted back by some bytes before encoded instruction
88                    buf[bufPos++] = '=';
89                    buf[bufPos++] = '.';
90                    buf[bufPos++] = '-';
91                    bufPos += itocstrCStyle((pos-curPos), buf+bufPos, 22, 10, 0, false);
92                    buf[bufPos++] = '\n';
93                }
94                else
95                {
96                    buf[bufPos++] = ':';
97                    buf[bufPos++] = '\n';
98                }
99                output.forward(bufPos);
100                ++labelIter;
101                haveLabel = true;
102            }
103           
104            /// print named label
105            if(namedPos <= numberedPos && haveNamedLabel)
106            {
107                curPos = namedLabelIter->first;
108                output.write(namedLabelIter->second.size(),
109                       namedLabelIter->second.c_str());
110                char* buf = output.reserve(50);
111                size_t bufPos = 0;
112                if (curPos != pos)
113                {   // if label shifted back by some bytes before encoded instruction
114                    buf[bufPos++] = '=';
115                    buf[bufPos++] = '.';
116                    buf[bufPos++] = '-';
117                    bufPos += itocstrCStyle((pos-curPos), buf+bufPos, 22, 10, 0, false);
118                    buf[bufPos++] = '\n';
119                }
120                else
121                {
122                    buf[bufPos++] = ':';
123                    buf[bufPos++] = '\n';
124                }
125                output.forward(bufPos);
126                ++namedLabelIter;
127                haveLabel = true;
128            }
129           
130        } while(haveLabel);
131    }
132}
133
134void ISADisassembler::writeLabelsToEnd(size_t start, LabelIter labelIter,
135                   NamedLabelIter namedLabelIter)
136{
137    size_t pos = startOffset + start;
138    while (namedLabelIter != namedLabels.end() || labelIter != labels.end())
139    {
140        size_t namedPos = SIZE_MAX;
141        size_t numberedPos = SIZE_MAX;
142        if (labelIter != labels.end())
143            numberedPos = *labelIter;
144        if (namedLabelIter != namedLabels.end())
145            namedPos = namedLabelIter->first;
146        if (numberedPos <= namedPos && labelIter != labels.end())
147        {
148            if (pos != *labelIter)
149            {   // print shift position to label (.org pseudo-op)
150                char* buf = output.reserve(30);
151                size_t bufPos = 0;
152                memcpy(buf+bufPos, ".org ", 5);
153                bufPos += 5;
154                bufPos += itocstrCStyle(*labelIter, buf+bufPos, 20, 16);
155                buf[bufPos++] = '\n';
156                output.forward(bufPos);
157            }
158            char* buf = output.reserve(50);
159            size_t bufPos = 0;
160            buf[bufPos++] = '.';
161            buf[bufPos++] = 'L';
162            bufPos += itocstrCStyle(*labelIter, buf+bufPos, 22, 10, 0, false);
163            buf[bufPos++] = '_';
164            bufPos += itocstrCStyle(disassembler.sectionCount,
165                            buf+bufPos, 22, 10, 0, false);
166            buf[bufPos++] = ':';
167            buf[bufPos++] = '\n';
168            output.forward(bufPos);
169            pos = *labelIter;
170            ++labelIter;
171        }
172        if (namedPos <= numberedPos && namedLabelIter != namedLabels.end())
173        {
174            if (pos != namedLabelIter->first)
175            {   // print shift position to label (.org pseudo-op)
176                char* buf = output.reserve(30);
177                size_t bufPos = 0;
178                memcpy(buf+bufPos, ".org ", 5);
179                bufPos += 5;
180                bufPos += itocstrCStyle(namedLabelIter->first, buf+bufPos, 20, 16);
181                buf[bufPos++] = '\n';
182                output.forward(bufPos);
183            }
184            output.write(namedLabelIter->second.size(),
185                        namedLabelIter->second.c_str());
186            pos = namedLabelIter->first;
187            ++namedLabelIter;
188        }
189    }
190}
191
192void ISADisassembler::writeLocation(size_t pos)
193{
194    const auto namedLabelIt = binaryMapFind(namedLabels.begin(), namedLabels.end(), pos);
195    if (namedLabelIt != namedLabels.end())
196    {   /* print named label */
197        output.write(namedLabelIt->second.size(), namedLabelIt->second.c_str());
198        return;
199    }
200    /* otherwise we print numbered label */
201    char* buf = output.reserve(50);
202    size_t bufPos = 0;
203    buf[bufPos++] = '.';
204    buf[bufPos++] = 'L';
205    bufPos += itocstrCStyle(pos, buf+bufPos, 22, 10, 0, false);
206    buf[bufPos++] = '_';
207    bufPos += itocstrCStyle(disassembler.sectionCount, buf+bufPos, 22, 10, 0, false);
208    output.forward(bufPos);
209}
210
211bool ISADisassembler::writeRelocation(size_t pos, RelocIter& relocIter)
212{
213    while (relocIter != relocations.end() && relocIter->first < pos)
214        relocIter++;
215    if (relocIter == relocations.end() || relocIter->first != pos)
216        return false;
217    const Relocation& reloc = relocIter->second;
218    if (reloc.addend != 0 && 
219        (reloc.type==RELTYPE_LOW_32BIT || reloc.type==RELTYPE_HIGH_32BIT))
220        output.write(1, "(");
221    /// write name+value
222    output.writeString(relSymbols[reloc.symbol].c_str());
223    char* buf = output.reserve(50);
224    size_t bufPos = 0;
225    if (reloc.addend != 0)
226    {
227        if (reloc.addend > 0)
228            buf[bufPos++] = '+';
229        bufPos += itocstrCStyle(reloc.addend, buf+bufPos, 22, 10, 0, false);
230        if (reloc.type==RELTYPE_LOW_32BIT || reloc.type==RELTYPE_HIGH_32BIT)
231            buf[bufPos++] = ')';
232    }
233    if (reloc.type==RELTYPE_LOW_32BIT)
234    {
235        ::memcpy(buf+bufPos, "&0xffffffff", 11);
236        bufPos += 11;
237    }
238    else if (reloc.type==RELTYPE_HIGH_32BIT)
239    {
240        ::memcpy(buf+bufPos, ">>32", 4);
241        bufPos += 4;
242    }
243    output.forward(bufPos);
244    ++relocIter;
245    return true;
246}
247
248void ISADisassembler::clearNumberedLabels()
249{
250    labels.clear();
251}
252
253void ISADisassembler::prepareLabelsAndRelocations()
254{
255    std::sort(labels.begin(), labels.end());
256    const auto newEnd = std::unique(labels.begin(), labels.end());
257    labels.resize(newEnd-labels.begin());
258    mapSort(namedLabels.begin(), namedLabels.end());
259    mapSort(relocations.begin(), relocations.end());
260}
261
262void ISADisassembler::beforeDisassemble()
263{
264    clearNumberedLabels();
265    analyzeBeforeDisassemble();
266    prepareLabelsAndRelocations();
267}
268
269Disassembler::Disassembler(const AmdMainGPUBinary32& binary, std::ostream& _output,
270            Flags _flags) : fromBinary(true), binaryFormat(BinaryFormat::AMD),
271            amdInput(nullptr), output(_output), flags(_flags), sectionCount(0)
272{
273    isaDisassembler.reset(new GCNDisassembler(*this));
274    amdInput = getAmdDisasmInputFromBinary32(binary, flags);
275}
276
277Disassembler::Disassembler(const AmdMainGPUBinary64& binary, std::ostream& _output,
278            Flags _flags) : fromBinary(true), binaryFormat(BinaryFormat::AMD),
279            amdInput(nullptr), output(_output), flags(_flags), sectionCount(0)
280{
281    isaDisassembler.reset(new GCNDisassembler(*this));
282    amdInput = getAmdDisasmInputFromBinary64(binary, flags);
283}
284
285Disassembler::Disassembler(const AmdCL2MainGPUBinary& binary, std::ostream& _output,
286           Flags _flags) : fromBinary(true), binaryFormat(BinaryFormat::AMDCL2),
287            amdCL2Input(nullptr), output(_output), flags(_flags), sectionCount(0)
288{
289    isaDisassembler.reset(new GCNDisassembler(*this));
290    amdCL2Input = getAmdCL2DisasmInputFromBinary(binary);
291}
292
293Disassembler::Disassembler(const ROCmBinary& binary, std::ostream& _output, Flags _flags)
294         : fromBinary(true), binaryFormat(BinaryFormat::ROCM),
295           rocmInput(nullptr), output(_output), flags(_flags), sectionCount(0)
296{
297    isaDisassembler.reset(new GCNDisassembler(*this));
298    rocmInput = getROCmDisasmInputFromBinary(binary);
299}
300
301Disassembler::Disassembler(const AmdDisasmInput* disasmInput, std::ostream& _output,
302            Flags _flags) : fromBinary(false), binaryFormat(BinaryFormat::AMD),
303            amdInput(disasmInput), output(_output), flags(_flags), sectionCount(0)
304{
305    isaDisassembler.reset(new GCNDisassembler(*this));
306}
307
308Disassembler::Disassembler(const AmdCL2DisasmInput* disasmInput, std::ostream& _output,
309            Flags _flags) : fromBinary(false), binaryFormat(BinaryFormat::AMDCL2),
310            amdCL2Input(disasmInput), output(_output), flags(_flags), sectionCount(0)
311{
312    isaDisassembler.reset(new GCNDisassembler(*this));
313}
314
315Disassembler::Disassembler(const ROCmDisasmInput* disasmInput, std::ostream& _output,
316                 Flags _flags) : fromBinary(false), binaryFormat(BinaryFormat::ROCM),
317            rocmInput(disasmInput), output(_output), flags(_flags), sectionCount(0)
318{
319    isaDisassembler.reset(new GCNDisassembler(*this));
320}
321
322Disassembler::Disassembler(GPUDeviceType deviceType, const GalliumBinary& binary,
323           std::ostream& _output, Flags _flags) :
324           fromBinary(true), binaryFormat(BinaryFormat::GALLIUM),
325           galliumInput(nullptr), output(_output), flags(_flags), sectionCount(0)
326{
327    isaDisassembler.reset(new GCNDisassembler(*this));
328    galliumInput = getGalliumDisasmInputFromBinary(deviceType, binary);
329}
330
331Disassembler::Disassembler(const GalliumDisasmInput* disasmInput, std::ostream& _output,
332             Flags _flags) : fromBinary(false), binaryFormat(BinaryFormat::GALLIUM),
333            galliumInput(disasmInput), output(_output), flags(_flags), sectionCount(0)
334{
335    isaDisassembler.reset(new GCNDisassembler(*this));
336}
337
338Disassembler::Disassembler(GPUDeviceType deviceType, size_t rawCodeSize,
339           const cxbyte* rawCode, std::ostream& _output, Flags _flags)
340       : fromBinary(true), binaryFormat(BinaryFormat::RAWCODE),
341         output(_output), flags(_flags), sectionCount(0)
342{
343    isaDisassembler.reset(new GCNDisassembler(*this));
344    rawInput = new RawCodeInput{ deviceType, rawCodeSize, rawCode };
345}
346
347Disassembler::~Disassembler()
348{
349    if (fromBinary)
350    {
351        switch(binaryFormat)
352        {
353            case BinaryFormat::AMD:
354                delete amdInput;
355                break;
356            case BinaryFormat::GALLIUM:
357                delete galliumInput;
358                break;
359            case BinaryFormat::ROCM:
360                delete rocmInput;
361                break;
362            case BinaryFormat::AMDCL2:
363                delete amdCL2Input;
364                break;
365            default:
366                delete rawInput;
367        }
368    }
369}
370
371GPUDeviceType Disassembler::getDeviceType() const
372{
373    switch(binaryFormat)
374    {
375        case BinaryFormat::AMD:
376            return amdInput->deviceType;
377        case BinaryFormat::AMDCL2:
378            return amdCL2Input->deviceType;
379        case BinaryFormat::ROCM:
380            return rocmInput->deviceType;
381        case BinaryFormat::GALLIUM:
382            return galliumInput->deviceType;
383        default:
384            return rawInput->deviceType;
385    }
386}
387
388extern void CLRX::printDisasmData(size_t size, const cxbyte* data, std::ostream& output,
389                bool secondAlign)
390{
391    char buf[68];
392    /// const strings for .byte and fill pseudo-ops
393    const char* linePrefix = "    .byte ";
394    const char* fillPrefix = "    .fill ";
395    size_t prefixSize = 10;
396    if (secondAlign)
397    {   // const string for double alignment
398        linePrefix = "        .byte ";
399        fillPrefix = "        .fill ";
400        prefixSize += 4;
401    }
402    ::memcpy(buf, linePrefix, prefixSize);
403    for (size_t p = 0; p < size;)
404    {
405        size_t fillEnd;
406        // find max repetition of this element
407        for (fillEnd = p+1; fillEnd < size && data[fillEnd]==data[p]; fillEnd++);
408        if (fillEnd >= p+8)
409        {   // if element repeated for least 1 line
410            // print .fill pseudo-op
411            ::memcpy(buf, fillPrefix, prefixSize);
412            const size_t oldP = p;
413            p = (fillEnd != size) ? fillEnd&~size_t(7) : fillEnd;
414            size_t bufPos = prefixSize;
415            bufPos += itocstrCStyle(p-oldP, buf+bufPos, 22, 10);
416            memcpy(buf+bufPos, ", 1, ", 5);
417            bufPos += 5;
418            bufPos += itocstrCStyle(data[oldP], buf+bufPos, 6, 16, 2);
419            buf[bufPos++] = '\n';
420            output.write(buf, bufPos);
421            ::memcpy(buf, linePrefix, prefixSize);
422            continue;
423        }
424       
425        const size_t lineEnd = std::min(p+8, size);
426        size_t bufPos = prefixSize;
427        // print 8 or less (if end of data) bytes
428        for (; p < lineEnd; p++)
429        {
430            buf[bufPos++] = '0';
431            buf[bufPos++] = 'x';
432            {   // inline byte in hexadecimal
433                cxuint digit = data[p]>>4;
434                if (digit < 10)
435                    buf[bufPos++] = '0'+digit;
436                else
437                    buf[bufPos++] = 'a'+digit-10;
438                digit = data[p]&0xf;
439                if (digit < 10)
440                    buf[bufPos++] = '0'+digit;
441                else
442                    buf[bufPos++] = 'a'+digit-10;
443            }
444            if (p+1 < lineEnd)
445            {
446                buf[bufPos++] = ',';
447                buf[bufPos++] = ' ';
448            }
449        }
450        buf[bufPos++] = '\n';
451        output.write(buf, bufPos);
452    }
453}
454
455void CLRX::printDisasmDataU32(size_t size, const uint32_t* data, std::ostream& output,
456                bool secondAlign)
457{
458    char buf[68];
459    /// const strings for .byte and fill pseudo-ops
460    const char* linePrefix = "    .int ";
461    const char* fillPrefix = "    .fill ";
462    size_t fillPrefixSize = 10;
463    if (secondAlign)
464    {   // const string for double alignment
465        linePrefix = "        .int ";
466        fillPrefix = "        .fill ";
467        fillPrefixSize += 4;
468    }
469    const size_t intPrefixSize = fillPrefixSize-1;
470    ::memcpy(buf, linePrefix, intPrefixSize);
471    for (size_t p = 0; p < size;)
472    {
473        size_t fillEnd;
474        // find max repetition of this char
475        for (fillEnd = p+1; fillEnd < size && ULEV(data[fillEnd])==ULEV(data[p]);
476             fillEnd++);
477        if (fillEnd >= p+4)
478        {   // if element repeated for least 1 line
479            // print .fill pseudo-op
480            ::memcpy(buf, fillPrefix, fillPrefixSize);
481            const size_t oldP = p;
482            p = (fillEnd != size) ? fillEnd&~size_t(3) : fillEnd;
483            size_t bufPos = fillPrefixSize;
484            bufPos += itocstrCStyle(p-oldP, buf+bufPos, 22, 10);
485            memcpy(buf+bufPos, ", 4, ", 5);
486            bufPos += 5;
487            bufPos += itocstrCStyle(ULEV(data[oldP]), buf+bufPos, 12, 16, 8);
488            buf[bufPos++] = '\n';
489            output.write(buf, bufPos);
490            ::memcpy(buf, linePrefix, fillPrefixSize);
491            continue;
492        }
493       
494        const size_t lineEnd = std::min(p+4, size);
495        size_t bufPos = intPrefixSize;
496        // print four or less (if end of data) dwords
497        for (; p < lineEnd; p++)
498        {
499            bufPos += itocstrCStyle(ULEV(data[p]), buf+bufPos, 12, 16, 8);
500            if (p+1 < lineEnd)
501            {
502                buf[bufPos++] = ',';
503                buf[bufPos++] = ' ';
504            }
505        }
506        buf[bufPos++] = '\n';
507        output.write(buf, bufPos);
508    }
509}
510
511void CLRX::printDisasmLongString(size_t size, const char* data, std::ostream& output,
512            bool secondAlign)
513{
514   
515    const char* linePrefix = "    .ascii \"";
516    size_t prefixSize = 12;
517    if (secondAlign)
518    {
519        linePrefix = "        .ascii \"";
520        prefixSize += 4;
521    }
522    char buffer[96];
523    ::memcpy(buffer, linePrefix, prefixSize);
524   
525    for (size_t pos = 0; pos < size; )
526    {
527        const size_t end = std::min(pos+72, size);
528        const size_t oldPos = pos;
529        while (pos < end && data[pos] != '\n') pos++;
530        if (pos < end && data[pos] == '\n') pos++; // embrace newline
531        size_t escapeSize;
532        pos = oldPos + escapeStringCStyle(pos-oldPos, data+oldPos, 76,
533                      buffer+prefixSize, escapeSize);
534        buffer[prefixSize+escapeSize] = '\"';
535        buffer[prefixSize+escapeSize+1] = '\n';
536        output.write(buffer, prefixSize+escapeSize+2);
537    }
538}
539
540static void disassembleRawCode(std::ostream& output, const RawCodeInput* rawInput,
541       ISADisassembler* isaDisassembler, size_t& sectionCount, Flags flags)
542{
543    if ((flags & DISASM_DUMPCODE) != 0)
544    {
545        output.write(".text\n", 6);
546        isaDisassembler->setInput(rawInput->codeSize, rawInput->code);
547        isaDisassembler->beforeDisassemble();
548        isaDisassembler->disassemble();
549    }
550}
551
552void Disassembler::disassemble()
553{
554    const std::ios::iostate oldExceptions = output.exceptions();
555    output.exceptions(std::ios::failbit | std::ios::badbit);
556    try
557    {
558    switch(binaryFormat)
559    {
560        case BinaryFormat::AMD:
561            output.write(".amd\n", 5);
562            break;
563        case BinaryFormat::AMDCL2:
564            output.write(".amdcl2\n", 8);
565            break;
566        case BinaryFormat::ROCM:
567            output.write(".rocm\n", 6);
568            break;
569        case BinaryFormat::GALLIUM: // Gallium
570            output.write(".gallium\n", 9);
571            break;
572        default:
573            output.write(".rawcode\n", 9);
574    }
575   
576    const GPUDeviceType deviceType = getDeviceType();
577    output.write(".gpu ", 5);
578    const char* gpuName = getGPUDeviceTypeName(deviceType);
579    output.write(gpuName, ::strlen(gpuName));
580    output.put('\n');
581   
582    switch(binaryFormat)
583    {
584        case BinaryFormat::AMD:
585            disassembleAmd(output, amdInput, isaDisassembler.get(), sectionCount, flags);
586            break;
587        case BinaryFormat::AMDCL2:
588            disassembleAmdCL2(output, amdCL2Input, isaDisassembler.get(),
589                              sectionCount, flags);
590            break;
591        case BinaryFormat::ROCM:
592            disassembleROCm(output, rocmInput, isaDisassembler.get(),
593                              sectionCount, flags);
594            break;
595        case BinaryFormat::GALLIUM: // Gallium
596            disassembleGallium(output, galliumInput, isaDisassembler.get(),
597                           sectionCount, flags);
598            break;
599        default:
600            disassembleRawCode(output, rawInput, isaDisassembler.get(),
601                           sectionCount, flags);
602    }
603    output.flush();
604    } /* try catch */
605    catch(...)
606    {
607        output.exceptions(oldExceptions);
608        throw;
609    }
610    output.exceptions(oldExceptions);
611}
Note: See TracBrowser for help on using the repository browser.