source: CLRX/CLRadeonExtender/trunk/amdasm/AsmPseudoOps.cpp @ 4102

Last change on this file since 4102 was 4102, checked in by matszpk, 12 months ago

CLRadeonExtender: Asm: Add enums (pseudo-ops '.enum').

File size: 115.5 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 <string>
22#include <cstring>
23#include <cassert>
24#include <fstream>
25#include <vector>
26#include <utility>
27#include <algorithm>
28#include <CLRX/utils/Utilities.h>
29#include <CLRX/amdbin/AmdBinaries.h>
30#include <CLRX/amdbin/GalliumBinaries.h>
31#include <CLRX/utils/MemAccess.h>
32#include <CLRX/utils/GPUId.h>
33#include <CLRX/utils/InputOutput.h>
34#include <CLRX/amdasm/Assembler.h>
35#include "AsmInternals.h"
36#include "AsmAmdInternals.h"
37#include "AsmAmdCL2Internals.h"
38#include "AsmGalliumInternals.h"
39#include "AsmROCmInternals.h"
40
41using namespace CLRX;
42
43// pseudo-ops used while skipping clauses
44static const char* offlinePseudoOpNamesTbl[] =
45{
46    "else", "elseif", "elseif32", "elseif64", "elseifarch",
47    "elseifb", "elseifc", "elseifdef",
48    "elseifeq", "elseifeqs", "elseiffmt",
49    "elseifge", "elseifgpu", "elseifgt",
50    "elseifle", "elseiflt", "elseifnarch", "elseifnb", "elseifnc",
51    "elseifndef", "elseifne", "elseifnes",
52    "elseifnfmt", "elseifngpu", "elseifnotdef",
53    "endif", "endm", "endmacro", "endr", "endrept", "for",
54    "if", "if32", "if64", "ifarch", "ifb", "ifc", "ifdef", "ifeq",
55    "ifeqs", "iffmt", "ifge", "ifgpu", "ifgt", "ifle",
56    "iflt", "ifnarch", "ifnb", "ifnc", "ifndef",
57    "ifne", "ifnes", "ifnfmt", "ifngpu", "ifnotdef",
58    "irp", "irpc", "macro", "rept", "while"
59};
60
61/// pseudo-ops not ignored while putting macro content
62static const char* macroRepeatPseudoOpNamesTbl[] =
63{
64    "endm", "endmacro", "endr", "endrept", "for", "irp", "irpc", "macro", "rept", "while"
65};
66
67// pseudo-ops used while skipping clauses
68enum
69{
70    ASMCOP_ELSE = 0, ASMCOP_ELSEIF, ASMCOP_ELSEIF32, ASMCOP_ELSEIF64, ASMCOP_ELSEIFARCH,
71    ASMCOP_ELSEIFB, ASMCOP_ELSEIFC, ASMCOP_ELSEIFDEF,
72    ASMCOP_ELSEIFEQ, ASMCOP_ELSEIFEQS, ASMCOP_ELSEIFFMT,
73    ASMCOP_ELSEIFGE, ASMCOP_ELSEIFGPU, ASMCOP_ELSEIFGT,
74    ASMCOP_ELSEIFLE, ASMCOP_ELSEIFLT, ASMCOP_ELSEIFNARCH, ASMCOP_ELSEIFNB, ASMCOP_ELSEIFNC,
75    ASMCOP_ELSEIFNDEF, ASMCOP_ELSEIFNE, ASMCOP_ELSEIFNES,
76    ASMCOP_ELSEIFNFMT, ASMCOP_ELSEIFNGPU, ASMCOP_ELSEIFNOTDEF,
77    ASMCOP_ENDIF, ASMCOP_ENDM, ASMCOP_ENDMACRO, ASMCOP_ENDR, ASMCOP_ENDREPT,
78    ASMCOP_FOR, ASMCOP_IF, ASMCOP_IF32, ASMCOP_IF64, ASMCOP_IFARCH, ASMCOP_IFB,
79    ASMCOP_IFC, ASMCOP_IFDEF, ASMCOP_IFEQ,
80    ASMCOP_IFEQS, ASMCOP_IFFMT, ASMCOP_IFGE, ASMCOP_IFGPU, ASMCOP_IFGT, ASMCOP_IFLE,
81    ASMCOP_IFLT, ASMCOP_IFNARCH, ASMCOP_IFNB, ASMCOP_IFNC, ASMCOP_IFNDEF,
82    ASMCOP_IFNE, ASMCOP_IFNES, ASMCOP_IFNFMT, ASMCOP_IFNGPU, ASMCOP_IFNOTDEF,
83    ASMCOP_IRP, ASMCOP_IRPC, ASMCOP_MACRO, ASMCOP_REPT, ASMCOP_WHILE
84};
85
86/// pseudo-ops not ignored while putting macro content
87enum
88{ ASMMROP_ENDM = 0, ASMMROP_ENDMACRO, ASMMROP_ENDR, ASMMROP_ENDREPT,
89    ASMMROP_FOR, ASMMROP_IRP, ASMMROP_IRPC, ASMMROP_MACRO, ASMMROP_REPT,
90    ASMMROP_WHILE };
91
92/// all main pseudo-ops (sorted by name)
93static const char* pseudoOpNamesTbl[] =
94{
95    "32bit", "64bit", "abort", "align", "altmacro",
96    "amd", "amdcl2", "arch", "ascii", "asciz",
97    "balign", "balignl", "balignw", "buggyfplit", "byte",
98    "cf_call", "cf_cjump", "cf_end",
99    "cf_jump", "cf_ret", "cf_start",
100    "data", "double", "else",
101    "elseif", "elseif32", "elseif64",
102    "elseifarch", "elseifb", "elseifc", "elseifdef",
103    "elseifeq", "elseifeqs", "elseiffmt",
104    "elseifge", "elseifgpu", "elseifgt",
105    "elseifle", "elseiflt", "elseifnarch", "elseifnb",
106    "elseifnc", "elseifndef", "elseifne", "elseifnes",
107    "elseifnfmt", "elseifngpu", "elseifnotdef",
108    "end", "endif", "endm", "endmacro",
109    "endr", "endrept", "ends", "endscope",
110    "enum", "equ", "equiv", "eqv",
111    "err", "error", "exitm", "extern",
112    "fail", "file", "fill", "fillq",
113    "float", "for", "format", "gallium", "get_64bit", "get_arch",
114    "get_format", "get_gpu", "get_version", "global",
115    "globl", "gpu", "half", "hword", "if", "if32", "if64",
116    "ifarch", "ifb", "ifc", "ifdef", "ifeq",
117    "ifeqs", "iffmt", "ifge", "ifgpu", "ifgt", "ifle",
118    "iflt", "ifnarch", "ifnb", "ifnc", "ifndef",
119    "ifne", "ifnes", "ifnfmt", "ifngpu", "ifnotdef", "incbin",
120    "include", "int", "irp", "irpc", "kernel", "lflags",
121    "line", "ln", "local", "long",
122    "macro", "macrocase", "main", "noaltmacro",
123    "nobuggyfplit", "nomacrocase", "nooldmodparam", "octa",
124    "offset", "oldmodparam", "org",
125    "p2align", "print", "purgem", "quad",
126    "rawcode", "regvar", "rept", "rocm", "rodata",
127    "sbttl", "scope", "section", "set",
128    "short", "single", "size", "skip",
129    "space", "string", "string16", "string32",
130    "string64", "struct", "text", "title",
131    "undef", "unusing", "usereg", "using", "version",
132    "warning", "weak", "while", "word"
133};
134
135// enum for all pseudo-ops
136enum
137{
138    ASMOP_32BIT = 0, ASMOP_64BIT, ASMOP_ABORT, ASMOP_ALIGN, ASMOP_ALTMACRO,
139    ASMOP_AMD, ASMOP_AMDCL2, ASMOP_ARCH, ASMOP_ASCII, ASMOP_ASCIZ,
140    ASMOP_BALIGN, ASMOP_BALIGNL, ASMOP_BALIGNW, ASMOP_BUGGYFPLIT, ASMOP_BYTE,
141    ASMOP_CF_CALL, ASMOP_CF_CJUMP, ASMOP_CF_END,
142    ASMOP_CF_JUMP, ASMOP_CF_RET, ASMOP_CF_START,
143    ASMOP_DATA, ASMOP_DOUBLE, ASMOP_ELSE,
144    ASMOP_ELSEIF, ASMOP_ELSEIF32, ASMOP_ELSEIF64,
145    ASMOP_ELSEIFARCH, ASMOP_ELSEIFB, ASMOP_ELSEIFC, ASMOP_ELSEIFDEF,
146    ASMOP_ELSEIFEQ, ASMOP_ELSEIFEQS, ASMOP_ELSEIFFMT,
147    ASMOP_ELSEIFGE, ASMOP_ELSEIFGPU, ASMOP_ELSEIFGT,
148    ASMOP_ELSEIFLE, ASMOP_ELSEIFLT, ASMOP_ELSEIFNARCH, ASMOP_ELSEIFNB,
149    ASMOP_ELSEIFNC, ASMOP_ELSEIFNDEF, ASMOP_ELSEIFNE, ASMOP_ELSEIFNES,
150    ASMOP_ELSEIFNFMT, ASMOP_ELSEIFNGPU, ASMOP_ELSEIFNOTDEF,
151    ASMOP_END, ASMOP_ENDIF, ASMOP_ENDM, ASMOP_ENDMACRO,
152    ASMOP_ENDR, ASMOP_ENDREPT, ASMOP_ENDS, ASMOP_ENDSCOPE,
153    ASMOP_ENUM, ASMOP_EQU, ASMOP_EQUIV, ASMOP_EQV,
154    ASMOP_ERR, ASMOP_ERROR, ASMOP_EXITM, ASMOP_EXTERN,
155    ASMOP_FAIL, ASMOP_FILE, ASMOP_FILL, ASMOP_FILLQ,
156    ASMOP_FLOAT, ASMOP_FOR, ASMOP_FORMAT, ASMOP_GALLIUM, ASMOP_GET_64BIT, ASMOP_GET_ARCH,
157    ASMOP_GET_FORMAT, ASMOP_GET_GPU, ASMOP_GET_VERSION, ASMOP_GLOBAL,
158    ASMOP_GLOBL, ASMOP_GPU, ASMOP_HALF, ASMOP_HWORD, ASMOP_IF, ASMOP_IF32, ASMOP_IF64,
159    ASMOP_IFARCH, ASMOP_IFB, ASMOP_IFC, ASMOP_IFDEF, ASMOP_IFEQ,
160    ASMOP_IFEQS, ASMOP_IFFMT, ASMOP_IFGE, ASMOP_IFGPU, ASMOP_IFGT, ASMOP_IFLE,
161    ASMOP_IFLT, ASMOP_IFNARCH, ASMOP_IFNB, ASMOP_IFNC, ASMOP_IFNDEF,
162    ASMOP_IFNE, ASMOP_IFNES, ASMOP_IFNFMT, ASMOP_IFNGPU, ASMOP_IFNOTDEF, ASMOP_INCBIN,
163    ASMOP_INCLUDE, ASMOP_INT, ASMOP_IRP, ASMOP_IRPC, ASMOP_KERNEL, ASMOP_LFLAGS,
164    ASMOP_LINE, ASMOP_LN, ASMOP_LOCAL, ASMOP_LONG,
165    ASMOP_MACRO, ASMOP_MACROCASE, ASMOP_MAIN, ASMOP_NOALTMACRO,
166    ASMOP_NOBUGGYFPLIT, ASMOP_NOMACROCASE, ASMOP_NOOLDMODPARAM, ASMOP_OCTA,
167    ASMOP_OFFSET, ASMOP_OLDMODPARAM, ASMOP_ORG,
168    ASMOP_P2ALIGN, ASMOP_PRINT, ASMOP_PURGEM, ASMOP_QUAD,
169    ASMOP_RAWCODE, ASMOP_REGVAR, ASMOP_REPT, ASMOP_ROCM, ASMOP_RODATA,
170    ASMOP_SBTTL, ASMOP_SCOPE, ASMOP_SECTION, ASMOP_SET,
171    ASMOP_SHORT, ASMOP_SINGLE, ASMOP_SIZE, ASMOP_SKIP,
172    ASMOP_SPACE, ASMOP_STRING, ASMOP_STRING16, ASMOP_STRING32,
173    ASMOP_STRING64, ASMOP_STRUCT, ASMOP_TEXT, ASMOP_TITLE,
174    ASMOP_UNDEF, ASMOP_UNUSING, ASMOP_USEREG, ASMOP_USING, ASMOP_VERSION,
175    ASMOP_WARNING, ASMOP_WEAK, ASMOP_WHILE, ASMOP_WORD
176};
177
178namespace CLRX
179{
180
181void AsmPseudoOps::setBitness(Assembler& asmr, const char* linePtr, bool _64Bit)
182{
183    if (!checkGarbagesAtEnd(asmr, linePtr))
184        return;
185    if (asmr.formatHandler != nullptr)
186        asmr.printError(linePtr, "Bitness is already defined");
187    else if (asmr.format == BinaryFormat::ROCM)
188    {
189        // ROCm is always 64-bit, print warning about it
190        if (!_64Bit)
191            asmr.printWarning(linePtr, "For ROCm bitness is always 64bit");
192    }
193    else if (asmr.format != BinaryFormat::AMD && asmr.format != BinaryFormat::GALLIUM &&
194        asmr.format != BinaryFormat::AMDCL2)
195        // print warning (for raw format) that bitness is ignored
196        asmr.printWarning(linePtr, "Bitness ignored for other formats than "
197                "AMD Catalyst, ROCm and GalliumCompute");
198    else
199        asmr._64bit = (_64Bit);
200}
201
202bool AsmPseudoOps::parseFormat(Assembler& asmr, const char*& linePtr, BinaryFormat& format)
203{
204    const char* end = asmr.line + asmr.lineSize;
205    skipSpacesToEnd(linePtr, end);
206    const char* formatPlace = linePtr;
207    char formatName[10];
208    if (!getNameArg(asmr, 10, formatName, linePtr, "output format type"))
209        return false;
210   
211    toLowerString(formatName);
212    // choose correct binary format
213    if (::strcmp(formatName, "catalyst")==0 || ::strcmp(formatName, "amd")==0)
214        format = BinaryFormat::AMD;
215    else if (::strcmp(formatName, "amdcl2")==0)
216        format = BinaryFormat::AMDCL2;
217    else if (::strcmp(formatName, "gallium")==0)
218        format = BinaryFormat::GALLIUM;
219    else if (::strcmp(formatName, "rocm")==0)
220        format = BinaryFormat::ROCM;
221    else if (::strcmp(formatName, "raw")==0)
222        format = BinaryFormat::RAWCODE;
223    else
224        ASM_FAIL_BY_ERROR(formatPlace, "Unknown output format type")
225    return true;
226}
227
228// .format pseudo-op
229void AsmPseudoOps::setOutFormat(Assembler& asmr, const char* linePtr)
230{
231    const char* end = asmr.line + asmr.lineSize;
232    BinaryFormat format;
233    skipSpacesToEnd(linePtr, end);
234    const char* formatPlace = linePtr;
235    if (!parseFormat(asmr, linePtr, format))
236        return;
237   
238    if (checkGarbagesAtEnd(asmr, linePtr))
239    {
240        // set if no garbages at end
241        if (asmr.formatHandler!=nullptr)
242            ASM_RETURN_BY_ERROR(formatPlace, "Output format type is already defined")
243        asmr.format = format;
244    }
245}
246
247void AsmPseudoOps::setGPUDevice(Assembler& asmr, const char* linePtr)
248{
249    const char* end = asmr.line + asmr.lineSize;
250    skipSpacesToEnd(linePtr, end);
251    char deviceName[64];
252    const char* deviceNamePlace = linePtr;
253    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU device name"))
254        return;
255    try
256    {
257        GPUDeviceType deviceType = getGPUDeviceTypeFromName(deviceName);
258        if (checkGarbagesAtEnd(asmr, linePtr))
259            // set if no garbages at end
260            asmr.deviceType = deviceType;
261    }
262    // if exception - print error
263    catch(const Exception& ex)
264    { asmr.printError(deviceNamePlace, ex.what()); }
265}
266
267void AsmPseudoOps::setGPUArchitecture(Assembler& asmr, const char* linePtr)
268{
269    const char* end = asmr.line + asmr.lineSize;
270    skipSpacesToEnd(linePtr, end);
271    char deviceName[64];
272    const char* archNamePlace = linePtr;
273    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU architecture name"))
274        return;
275    try
276    {
277        GPUArchitecture arch = getGPUArchitectureFromName(deviceName);
278        GPUDeviceType deviceType = getLowestGPUDeviceTypeFromArchitecture(arch);
279        if (checkGarbagesAtEnd(asmr, linePtr))
280            // set if no garbages at end
281            asmr.deviceType = deviceType;
282    }
283    // if exception - print error
284    catch(const Exception& ex)
285    { asmr.printError(archNamePlace, ex.what()); }
286}
287
288void AsmPseudoOps::goToKernel(Assembler& asmr, const char* pseudoOpPlace,
289                  const char* linePtr)
290{
291    asmr.initializeOutputFormat();
292    const char* end = asmr.line + asmr.lineSize;
293    skipSpacesToEnd(linePtr, end);
294    CString kernelName;
295    if (!getNameArg(asmr, kernelName, linePtr, "kernel name"))
296        return;
297    if (!checkGarbagesAtEnd(asmr, linePtr))
298        return;
299   
300    asmr.goToKernel(pseudoOpPlace, kernelName.c_str());
301}
302
303/// isPseudoOp - if true then name is pseudo-operation (we must convert to lower-case)
304/// if pseudo-op we just do not try to parse section flags
305void AsmPseudoOps::goToSection(Assembler& asmr, const char* pseudoOpPlace,
306                   const char* linePtr, bool isPseudoOp)
307{
308    asmr.initializeOutputFormat();
309    const char* end = asmr.line + asmr.lineSize;
310    skipSpacesToEnd(linePtr, end);
311    CString sectionName;
312    if (!getNameArg(asmr, sectionName, linePtr, "section name"))
313        return;
314    if (isPseudoOp)
315        toLowerString(sectionName);
316    bool haveFlags = false;
317    uint32_t sectFlags = 0;
318    AsmSectionType sectType = AsmSectionType::EXTRA_SECTION;
319    uint64_t sectionAlign = 0;
320    if (!isPseudoOp)
321    {
322        skipSpacesToEnd(linePtr, end);
323        if (linePtr!=end && *linePtr==',')
324        {
325            haveFlags = true;
326            linePtr++;
327        }
328    }
329    bool good = true;
330    if (haveFlags)
331    {
332        std::string flagsStr;
333        skipSpacesToEnd(linePtr, end);
334        const char* flagsStrPlace = linePtr;
335        if (asmr.parseString(flagsStr, linePtr))
336        {
337            // parse section flags (a,x,w)
338            bool flagsStrIsGood = true;
339            for (const char c: flagsStr)
340                if (c=='a')
341                    sectFlags |= ASMELFSECT_ALLOCATABLE;
342                else if (c=='x')
343                    sectFlags |= ASMELFSECT_EXECUTABLE;
344                else if (c=='w')
345                    sectFlags |= ASMELFSECT_WRITEABLE;
346                else if (flagsStrIsGood)
347                    ASM_NOTGOOD_BY_ERROR1(flagsStrIsGood = good, flagsStrPlace,
348                            "Only 'a', 'w', 'x' is accepted in flags string")
349        }
350        else
351            good = false;
352       
353        bool haveComma;
354        if (!skipComma(asmr, haveComma, linePtr))
355            return;
356        if (haveComma)
357        {
358            // section type
359            char typeBuf[20];
360            skipSpacesToEnd(linePtr, end);
361            const char* typePlace = linePtr;
362            if (linePtr+1<end && *linePtr=='@' && isAlpha(linePtr[1]))
363            {
364                // parse section type (progbits, note, nobits)
365                linePtr++;
366                if (getNameArg(asmr, 20, typeBuf, linePtr, "section type"))
367                {
368                    toLowerString(typeBuf);
369                    if (::strcmp(typeBuf, "progbits")==0)
370                        sectType = AsmSectionType::EXTRA_PROGBITS;
371                    else if (::strcmp(typeBuf, "note")==0)
372                        sectType = AsmSectionType::EXTRA_NOTE;
373                    else if (::strcmp(typeBuf, "nobits")==0)
374                        sectType = AsmSectionType::EXTRA_NOBITS;
375                    else
376                        ASM_NOTGOOD_BY_ERROR(typePlace, "Unknown section type")
377                }
378                else
379                    good = false;
380            }
381            else
382                ASM_NOTGOOD_BY_ERROR(typePlace, "Section type was not preceded by '@'")
383        }
384    }
385    // parse alignment
386    skipSpacesToEnd(linePtr, end);
387    if (linePtr+6<end && ::strncasecmp(linePtr, "align", 5)==0 && !isAlpha(linePtr[5]))
388    {
389        // if alignment
390        linePtr+=5;
391        skipSpacesToEnd(linePtr, end);
392        if (linePtr!=end && *linePtr=='=')
393        {
394            skipCharAndSpacesToEnd(linePtr, end);
395            const char* valuePtr = linePtr;
396            if (getAbsoluteValueArg(asmr, sectionAlign, linePtr, true))
397            {
398                if (sectionAlign!=0 && (1ULL<<(63-CLZ64(sectionAlign))) != sectionAlign)
399                    ASM_NOTGOOD_BY_ERROR(valuePtr, "Alignment must be power of two or zero")
400            }
401            else
402                good = false;
403        }
404        else
405            ASM_NOTGOOD_BY_ERROR(linePtr, "Expected '=' after 'align'")
406    }
407   
408    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
409        return;
410   
411    if (!haveFlags)
412        // if section flags and section type not supplied
413        asmr.goToSection(pseudoOpPlace, sectionName.c_str(), sectionAlign);
414    else
415        asmr.goToSection(pseudoOpPlace, sectionName.c_str(), sectType, sectFlags,
416                 sectionAlign);
417}
418
419void AsmPseudoOps::goToMain(Assembler& asmr, const char* pseudoOpPlace,
420                   const char* linePtr)
421{
422    asmr.initializeOutputFormat();
423    const char* end = asmr.line + asmr.lineSize;
424    skipSpacesToEnd(linePtr, end);
425    if (!checkGarbagesAtEnd(asmr, linePtr))
426        return;
427   
428    asmr.goToMain(pseudoOpPlace);
429}
430
431void AsmPseudoOps::includeFile(Assembler& asmr, const char* pseudoOpPlace,
432                   const char* linePtr)
433{
434    const char* end = asmr.line + asmr.lineSize;
435    skipSpacesToEnd(linePtr, end);
436    std::string filename, sysfilename;
437    const char* namePlace = linePtr;
438    if (asmr.parseString(filename, linePtr))
439    {
440        if (!checkGarbagesAtEnd(asmr, linePtr))
441            return;
442        sysfilename = filename;
443        bool failedOpen = false;
444        // convert path to system path (with system dir separators)
445        filesystemPath(sysfilename);
446        try
447        {
448            asmr.includeFile(pseudoOpPlace, sysfilename);
449            return;
450        }
451        catch(const Exception& ex)
452        { failedOpen = true; }
453       
454        // find in include paths
455        for (const CString& incDir: asmr.includeDirs)
456        {
457            failedOpen = false;
458            std::string incDirPath(incDir.c_str());
459            // convert path to system path (with system dir separators)
460            filesystemPath(incDirPath);
461            try
462            {
463                asmr.includeFile(pseudoOpPlace, joinPaths(
464                            std::string(incDirPath.c_str()), sysfilename));
465                break;
466            }
467            catch(const Exception& ex)
468            { failedOpen = true; }
469        }
470        // if not found
471        if (failedOpen)
472            asmr.printError(namePlace, (std::string("Include file '") + filename +
473                    "' not found or unavailable in any directory").c_str());
474    }
475}
476
477void AsmPseudoOps::includeBinFile(Assembler& asmr, const char* pseudoOpPlace,
478                          const char* linePtr)
479{
480    asmr.initializeOutputFormat();
481    const char* end = asmr.line + asmr.lineSize;
482   
483    if (!asmr.isWriteableSection())
484        PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
485   
486    skipSpacesToEnd(linePtr, end);
487    std::string filename, sysfilename;
488    const char* namePlace = linePtr;
489    const char* offsetPlace = linePtr;
490    const char* countPlace = linePtr;
491    uint64_t offset = 0, count = INT64_MAX;
492   
493    bool good = asmr.parseString(filename, linePtr);
494    bool haveComma;
495   
496    if (!skipComma(asmr, haveComma, linePtr))
497        return;
498    if (haveComma)
499    {
500        skipSpacesToEnd(linePtr, end);
501        // parse offset argument
502        offsetPlace = linePtr;
503        if (getAbsoluteValueArg(asmr, offset, linePtr))
504        {
505            // offset must not be negative
506            if (int64_t(offset) < 0)
507                ASM_NOTGOOD_BY_ERROR(offsetPlace, "Offset is negative!")
508        }
509        else
510            good = false;
511       
512        if (!skipComma(asmr, haveComma, linePtr))
513            return;
514        if (haveComma)
515        {
516            skipSpacesToEnd(linePtr, end);
517            countPlace = linePtr;
518            // parse count argument
519            good &= getAbsoluteValueArg(asmr, count, linePtr);
520            if (int64_t(count) < 0)
521                ASM_NOTGOOD_BY_ERROR(countPlace, "Count bytes is negative!")
522        }
523    }
524   
525    if (!good || !checkGarbagesAtEnd(asmr, linePtr)) // failed parsing
526        return;
527   
528    if (count == 0)
529    {
530        asmr.printWarning(namePlace, "Number of bytes is zero, ignoring .incbin");
531        return;
532    }
533   
534    std::ifstream ifs;
535    sysfilename = filename;
536    filesystemPath(sysfilename);
537    // try in this directory
538    ifs.open(sysfilename.c_str(), std::ios::binary);
539    if (!ifs)
540    {
541        // find in include paths
542        for (const CString& incDir: asmr.includeDirs)
543        {
544            std::string incDirPath(incDir.c_str());
545            filesystemPath(incDirPath);
546            ifs.open(joinPaths(incDirPath.c_str(), sysfilename).c_str(), std::ios::binary);
547            if (ifs)
548                break;
549        }
550    }
551    if (!ifs)
552        ASM_RETURN_BY_ERROR(namePlace, (std::string("Binary file '") + filename +
553                    "' not found or unavailable in any directory").c_str())
554    // exception for checking file seeking
555    bool seekingIsWorking = true;
556    ifs.exceptions(std::ios::badbit | std::ios::failbit); // exceptions
557    try
558    { ifs.seekg(0, std::ios::end); /* to end of file */ }
559    catch(const std::exception& ex)
560    {
561        /* oh, no! this is not regular file */
562        seekingIsWorking = false;
563        ifs.clear();
564    }
565    ifs.exceptions(std::ios::badbit);  // exceptions for reading
566    if (seekingIsWorking)
567    {
568        /* for regular files */
569        const uint64_t size = ifs.tellg();
570        if (size < offset)
571            return; // do nothing
572        // skip offset bytes
573        ifs.seekg(offset, std::ios::beg);
574        const uint64_t toRead = std::min(size-offset, count);
575        char* output = reinterpret_cast<char*>(asmr.reserveData(toRead));
576        // and just read directly to output
577        ifs.read(output, toRead);
578        if (ifs.gcount() != std::streamsize(toRead))
579            ASM_RETURN_BY_ERROR(namePlace, "Can't read whole needed file content")
580    }
581    else
582    {
583        /* for sequential files, likes fifo */
584        char tempBuf[256];
585        /// first we skipping bytes given in offset
586        for (uint64_t pos = 0; pos < offset; )
587        {
588            const size_t toRead = std::min(offset-pos, uint64_t(256));
589            ifs.read(tempBuf, toRead);
590            const uint64_t readed = ifs.gcount();
591            pos += readed;
592            if (readed < toRead)
593                break;
594        }
595        // read data from binary file
596        for (uint64_t bytes = 0; bytes < count; )
597        {
598            const size_t toRead = std::min(uint64_t(256), count-bytes);
599            ifs.read(tempBuf, toRead);
600            const uint64_t readed = ifs.gcount();
601            asmr.putData(readed, (cxbyte*)tempBuf);
602            bytes += readed;
603            if (readed < toRead)
604                break;
605        }
606    }
607}
608
609void AsmPseudoOps::doFail(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
610{
611    const char* end = asmr.line + asmr.lineSize;
612    skipSpacesToEnd(linePtr, end);
613    uint64_t value = 0;
614    if (!getAbsoluteValueArg(asmr, value, linePtr, true))
615        return;
616    if (!checkGarbagesAtEnd(asmr, linePtr))
617        return;
618   
619    char buf[50];
620    ::memcpy(buf, ".fail ", 6);
621    const size_t pos = 6+itocstrCStyle(int64_t(value), buf+6, 50-6);
622    ::memcpy(buf+pos, " encountered", 13);
623    if (int64_t(value) >= 500)
624        // value >=500 treat as error
625        asmr.printWarning(pseudoOpPlace, buf);
626    else
627        asmr.printError(pseudoOpPlace, buf);
628}
629
630void AsmPseudoOps::doError(Assembler& asmr, const char* pseudoOpPlace,
631                      const char* linePtr)
632{
633    const char* end = asmr.line + asmr.lineSize;
634    skipSpacesToEnd(linePtr, end);
635    if (linePtr != end)
636    {
637        std::string outStr;
638        if (!asmr.parseString(outStr, linePtr))
639            return; // error
640        if (!checkGarbagesAtEnd(asmr, linePtr))
641            return;
642        asmr.printError(pseudoOpPlace, outStr.c_str());
643    }
644    else
645        // if without string
646        asmr.printError(pseudoOpPlace, ".error encountered");
647}
648
649void AsmPseudoOps::doWarning(Assembler& asmr, const char* pseudoOpPlace,
650                        const char* linePtr)
651{
652    const char* end = asmr.line + asmr.lineSize;
653    skipSpacesToEnd(linePtr, end);
654    if (linePtr != end)
655    {
656        std::string outStr;
657        if (!asmr.parseString(outStr, linePtr))
658            return; // error
659        if (!checkGarbagesAtEnd(asmr, linePtr))
660            return;
661        asmr.printWarning(pseudoOpPlace, outStr.c_str());
662    }
663    else
664        // if without string
665        asmr.printWarning(pseudoOpPlace, ".warning encountered");
666}
667
668template<typename T>
669void AsmPseudoOps::putIntegers(Assembler& asmr, const char* pseudoOpPlace,
670                   const char* linePtr)
671{
672    const char* end = asmr.line + asmr.lineSize;
673    asmr.initializeOutputFormat();
674    if (!asmr.isWriteableSection())
675        PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
676    skipSpacesToEnd(linePtr, end);
677    if (linePtr == end)
678        return;
679    do {
680        const char* exprPlace = linePtr;
681        // try parse expression for this integer
682        uint64_t value;
683        if (AsmExpression::fastExprEvaluate(asmr, linePtr, value))
684        {   // fast path (expression)
685            if (sizeof(T) < 8)
686                asmr.printWarningForRange(sizeof(T)<<3, value,
687                                asmr.getSourcePos(exprPlace));
688            T out;
689            SLEV(out, value); // store in little-endian
690            asmr.putData(sizeof(T), reinterpret_cast<const cxbyte*>(&out));
691            continue;
692        }
693        std::unique_ptr<AsmExpression> expr(AsmExpression::parse(asmr, linePtr));
694        if (expr)
695        {
696            if (expr->isEmpty()) // empty expression print warning
697                asmr.printWarning(linePtr, "No expression, zero has been put");
698           
699            if (expr->getSymOccursNum()==0)
700            {
701                // put directly to section
702                cxuint sectionId;
703                AsmTryStatus  evalStatus = expr->tryEvaluate(asmr, value, sectionId,
704                                        asmr.withSectionDiffs());
705                if (evalStatus == AsmTryStatus::SUCCESS)
706                {
707                    if (sectionId == ASMSECT_ABS)
708                    {
709                        if (sizeof(T) < 8)
710                            asmr.printWarningForRange(sizeof(T)<<3, value,
711                                         asmr.getSourcePos(exprPlace));
712                        T out;
713                        SLEV(out, value); // store in little-endian
714                        asmr.putData(sizeof(T), reinterpret_cast<const cxbyte*>(&out));
715                    }
716                    else
717                        asmr.printError(exprPlace, "Expression must be absolute!");
718                }
719                else if (evalStatus == AsmTryStatus::TRY_LATER)
720                {
721                    // if section diffs to resolve later
722                    expr->setTarget(AsmExprTarget::dataTarget<T>(
723                                    asmr.currentSection, asmr.currentOutPos));
724                    asmr.unevalExpressions.push_back(expr.release());
725                    asmr.reserveData(sizeof(T));
726                }
727            }
728            else // expression, we set target of expression (just data)
729            {
730                /// will be resolved later
731                expr->setTarget(AsmExprTarget::dataTarget<T>(
732                                asmr.currentSection, asmr.currentOutPos));
733                expr.release();
734                asmr.reserveData(sizeof(T));
735            }
736        }
737    } while(skipCommaForMultipleArgs(asmr, linePtr));
738    checkGarbagesAtEnd(asmr, linePtr);
739}
740
741// helper for floating point parsing (with storing in little-endian)
742template<typename T> inline
743T asmcstrtofCStyleLEV(const char* str, const char* inend, const char*& outend);
744
745template<> inline
746uint16_t asmcstrtofCStyleLEV<uint16_t>(const char* str, const char* inend,
747                   const char*& outend)
748{ return LEV(cstrtohCStyle(str, inend, outend)); }
749
750template<> inline
751uint32_t asmcstrtofCStyleLEV<uint32_t>(const char* str, const char* inend,
752                   const char*& outend)
753{
754    union {
755        float f;
756        uint32_t u;
757    } value;
758    value.f = cstrtovCStyle<float>(str, inend, outend);
759    return LEV(value.u);
760}
761
762template<> inline
763uint64_t asmcstrtofCStyleLEV<uint64_t>(const char* str, const char* inend,
764                   const char*& outend)
765{
766    union {
767        double f;
768        uint64_t u;
769    } value;
770    value.f = cstrtovCStyle<double>(str, inend, outend);
771    return LEV(value.u);
772}
773
774template<typename UIntType>
775void AsmPseudoOps::putFloats(Assembler& asmr, const char* pseudoOpPlace,
776                     const char* linePtr)
777{
778    const char* end = asmr.line + asmr.lineSize;
779    asmr.initializeOutputFormat();
780    if (!asmr.isWriteableSection())
781        PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
782    skipSpacesToEnd(linePtr, end);
783    if (linePtr == end)
784        return;
785    do {
786        UIntType out = 0;
787        const char* literalPlace = linePtr;
788        if (linePtr != end && *linePtr != ',')
789        {
790            // try parse floating point (returns as little-endian value)
791            try
792            { out = asmcstrtofCStyleLEV<UIntType>(linePtr, end, linePtr); }
793            catch(const ParseException& ex)
794            { asmr.printError(literalPlace, ex.what()); }
795        }
796        else // warning
797            asmr.printWarning(literalPlace,
798                      "No floating point literal, zero has been put");
799        asmr.putData(sizeof(UIntType), reinterpret_cast<const cxbyte*>(&out));
800       
801    } while (skipCommaForMultipleArgs(asmr, linePtr));
802    checkGarbagesAtEnd(asmr, linePtr);
803}
804
805void AsmPseudoOps::putUInt128s(Assembler& asmr, const char* pseudoOpPlace,
806                   const char* linePtr)
807{
808    const char* end = asmr.line + asmr.lineSize;
809    asmr.initializeOutputFormat();
810    if (!asmr.isWriteableSection())
811        PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
812    skipSpacesToEnd(linePtr, end);
813    if (linePtr == end)
814        return;
815    do {
816        UInt128 value = { 0, 0 };
817        if (linePtr != end && *linePtr != ',')
818        {
819            const char* literalPlace = linePtr;
820            bool negative = false;
821            // handle '+' and '-' before number
822            if (*linePtr == '+')
823                linePtr++;
824            else if (*linePtr == '-')
825            {
826                negative = true;
827                linePtr++;
828            }
829            try
830            { value = cstrtou128CStyle(linePtr, end, linePtr); }
831            catch(const ParseException& ex)
832            { asmr.printError(literalPlace, ex.what()); }
833            if (negative)
834            {
835                // negate value
836                value.hi = ~value.hi + (value.lo==0);
837                value.lo = -value.lo;
838            }
839        }
840        else // warning
841            asmr.printWarning(linePtr, "No 128-bit literal, zero has been put");
842        UInt128 out;
843        // and store value in little-endian
844        SLEV(out.lo, value.lo);
845        SLEV(out.hi, value.hi);
846        asmr.putData(16, reinterpret_cast<const cxbyte*>(&out));
847    } while (skipCommaForMultipleArgs(asmr, linePtr));
848    checkGarbagesAtEnd(asmr, linePtr);
849}
850
851void AsmPseudoOps::putStrings(Assembler& asmr, const char* pseudoOpPlace,
852                      const char* linePtr, bool addZero)
853{
854    const char* end = asmr.line + asmr.lineSize;
855    asmr.initializeOutputFormat();
856    if (!asmr.isWriteableSection())
857        PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
858    skipSpacesToEnd(linePtr, end);
859    if (linePtr == end)
860        return;
861    do {
862        std::string outStr;
863        if (*linePtr != ',')
864        {
865            if (asmr.parseString(outStr, linePtr))
866                asmr.putData(outStr.size()+(addZero), (const cxbyte*)outStr.c_str());
867        }
868    } while (skipCommaForMultipleArgs(asmr, linePtr));
869    checkGarbagesAtEnd(asmr, linePtr);
870}
871
872// for .string16, .string32 and .string64 pseudo-ops
873// store characters as 16-,32-,64-bit values
874template<typename T>
875void AsmPseudoOps::putStringsToInts(Assembler& asmr, const char* pseudoOpPlace,
876                    const char* linePtr)
877{
878    const char* end = asmr.line + asmr.lineSize;
879    if (!asmr.isWriteableSection())
880        PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
881    asmr.initializeOutputFormat();
882    skipSpacesToEnd(linePtr, end);
883    if (linePtr == end)
884        return;
885    do {
886        std::string outStr;
887        if (*linePtr != ',')
888        {
889            if (asmr.parseString(outStr, linePtr))
890            {
891                const size_t strSize = outStr.size()+1;
892                T* outData = reinterpret_cast<T*>(
893                        asmr.reserveData(sizeof(T)*(strSize)));
894                /// put as integer including nul-terminated string
895                for (size_t i = 0; i < strSize; i++)
896                    SULEV(outData[i], T(outStr[i])&T(0xff));
897            }
898        }
899       
900    } while (skipCommaForMultipleArgs(asmr, linePtr));
901    checkGarbagesAtEnd(asmr, linePtr);
902}
903
904void AsmPseudoOps::setSymbol(Assembler& asmr, const char* linePtr, bool reassign,
905                 bool baseExpr)
906{
907    const char* end = asmr.line + asmr.lineSize;
908    skipSpacesToEnd(linePtr, end);
909    const char* strAtSymName = linePtr;
910    CString symName = extractScopedSymName(linePtr, end, false);
911    bool good = true;
912    if (symName.empty())
913        ASM_NOTGOOD_BY_ERROR(linePtr, "Expected symbol")
914    if (!skipRequiredComma(asmr, linePtr))
915        return;
916    if (good) // is good
917        asmr.assignSymbol(symName, strAtSymName, linePtr, reassign, baseExpr);
918}
919
920void AsmPseudoOps::setSymbolBind(Assembler& asmr, const char* linePtr, cxbyte bind)
921{
922    const char* end = asmr.line + asmr.lineSize;
923    skipSpacesToEnd(linePtr, end);
924    do {
925        const char* symNamePlace = linePtr;
926        AsmSymbolEntry* symEntry;
927        Assembler::ParseState state = asmr.parseSymbol(linePtr, symEntry, false);
928        bool good = (state != Assembler::ParseState::FAILED);
929        // handle errors
930        if (symEntry == nullptr)
931            ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol name")
932        else if (symEntry->second.regRange)
933            ASM_NOTGOOD_BY_ERROR(symNamePlace, "Symbol must not be register symbol")
934        else if (symEntry->second.base)
935            ASM_NOTGOOD_BY_ERROR(symNamePlace,
936                "Symbol must not be set by .eqv pseudo-op or must be constant")
937       
938        if (good)
939        {
940            // set binding to symbol (except symbol '.')
941            if (symEntry->first != ".")
942                symEntry->second.info = ELF32_ST_INFO(bind,
943                      ELF32_ST_TYPE(symEntry->second.info));
944            else
945                asmr.printWarning(symNamePlace, "Symbol '.' is ignored");
946        }
947       
948    } while(skipCommaForMultipleArgs(asmr, linePtr));
949    checkGarbagesAtEnd(asmr, linePtr);
950}
951
952void AsmPseudoOps::setSymbolSize(Assembler& asmr, const char* linePtr)
953{
954    const char* end = asmr.line + asmr.lineSize;
955    skipSpacesToEnd(linePtr, end);
956    const char* symNamePlace = linePtr;
957    AsmSymbolEntry* symEntry;
958    Assembler::ParseState state = asmr.parseSymbol(linePtr, symEntry, false);
959    bool good = (state != Assembler::ParseState::FAILED);
960    if (symEntry == nullptr)
961        ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol name")
962    if (!skipRequiredComma(asmr, linePtr))
963        return;
964    // parse size
965    uint64_t size;
966    good &= getAbsoluteValueArg(asmr, size, linePtr, true);
967    bool ignore = false;
968    if (symEntry != nullptr)
969    {
970        if (symEntry->second.base)
971            ASM_NOTGOOD_BY_ERROR(symNamePlace,
972                    "Symbol must not be set by .eqv pseudo-op or must be constant")
973        else if (symEntry->second.regRange)
974            ASM_NOTGOOD_BY_ERROR(symNamePlace, "Symbol must not be register symbol")
975        else if (symEntry->first == ".")
976        {
977            // do not set size for '.' symbol
978            asmr.printWarning(symNamePlace, "Symbol '.' is ignored");
979            ignore = true;
980        }
981    }
982   
983    if (good && checkGarbagesAtEnd(asmr, linePtr))
984        if (!ignore) // ignore if '.'
985            symEntry->second.size = size;
986}
987
988void AsmPseudoOps::ignoreExtern(Assembler& asmr, const char* linePtr)
989{
990    const char* end = asmr.line + asmr.lineSize;
991    skipSpacesToEnd(linePtr, end);
992    if (linePtr == end)
993        return;
994    do {
995        asmr.skipSymbol(linePtr);
996    } while (skipCommaForMultipleArgs(asmr, linePtr));
997    checkGarbagesAtEnd(asmr, linePtr);
998}
999
1000void AsmPseudoOps::doFill(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1001          bool _64bit)
1002{
1003    asmr.initializeOutputFormat();
1004    const char* end = asmr.line + asmr.lineSize;
1005   
1006    if (!asmr.isWriteableSection())
1007        PSEUDOOP_RETURN_BY_ERROR("Writing data into non-writeable section is illegal")
1008   
1009    skipSpacesToEnd(linePtr, end);
1010    uint64_t repeat = 0, size = 1, value = 0;
1011   
1012    const char* reptStr = linePtr;
1013    // parse repeat argument
1014    bool good = getAbsoluteValueArg(asmr, repeat, linePtr, true);
1015   
1016    if (int64_t(repeat) < 0)
1017        asmr.printWarning(reptStr, "Negative repeat has no effect");
1018   
1019    bool haveComma = false;
1020    if (!skipComma(asmr, haveComma, linePtr))
1021        return;
1022    const char* sizePlace = linePtr;
1023    const char* fillValuePlace = linePtr;
1024    if (haveComma)
1025    {
1026        skipSpacesToEnd(linePtr, end);
1027        sizePlace = linePtr; //
1028        // parse size argument
1029        if (getAbsoluteValueArg(asmr, size, linePtr))
1030        {
1031            if (int64_t(size) < 0)
1032                asmr.printWarning(sizePlace, "Negative size has no effect");
1033        }
1034        else
1035            good = false;
1036       
1037        if (!skipComma(asmr, haveComma, linePtr))
1038            return;
1039        if (haveComma)
1040        {
1041            skipSpacesToEnd(linePtr, end);
1042            fillValuePlace = linePtr;
1043            // parse value argument
1044            good &= getAbsoluteValueArg(asmr, value, linePtr);
1045        }
1046    }
1047    if (int64_t(size) > 0 && int64_t(repeat) > 0 && SSIZE_MAX/size < repeat)
1048        ASM_NOTGOOD_BY_ERROR(pseudoOpPlace, "Product of repeat and size is too big")
1049   
1050    cxuint truncBits = std::min(uint64_t(8), size)<<3;
1051    /* honors old behaviour from original GNU as (just cut to 32-bit values)
1052     * do not that for .fillq (_64bit=true) */
1053    if (!_64bit)
1054        truncBits = std::min(cxuint(32), truncBits);
1055    if (truncBits != 0 && truncBits < 64) // if print
1056        asmr.printWarningForRange(truncBits, value, asmr.getSourcePos(fillValuePlace));
1057   
1058    if (!good || !checkGarbagesAtEnd(asmr, linePtr)) // if parsing failed
1059        return;
1060   
1061    if (int64_t(repeat) <= 0 || int64_t(size) <= 0)
1062        return;
1063   
1064    if (!_64bit)
1065        value &= 0xffffffffUL;
1066   
1067    /* do fill */
1068    cxbyte* content = asmr.reserveData(size*repeat);
1069    const size_t valueSize = std::min(uint64_t(8), size);
1070    uint64_t outValue;
1071    SLEV(outValue, value);
1072    // main filling route (slow)
1073    for (uint64_t r = 0; r < repeat; r++)
1074    {
1075        ::memcpy(content, &outValue, valueSize);
1076        ::memset(content+valueSize, 0, size-valueSize);
1077        content += size;
1078    }
1079}
1080
1081void AsmPseudoOps::doSkip(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1082{
1083    asmr.initializeOutputFormat();
1084    const char* end = asmr.line + asmr.lineSize;
1085   
1086    if (!asmr.isAddressableSection())
1087        PSEUDOOP_RETURN_BY_ERROR("Change output counter inside non-addressable "
1088                    "section is illegal")
1089   
1090    skipSpacesToEnd(linePtr, end);
1091    uint64_t size = 1, value = 0;
1092   
1093    const char* sizePlace = linePtr;
1094    // parse size argument
1095    bool good = getAbsoluteValueArg(asmr, size, linePtr);
1096    if (int64_t(size) < 0)
1097        asmr.printWarning(sizePlace, "Negative size has no effect");
1098   
1099    bool haveComma = false;
1100    if (!skipComma(asmr, haveComma, linePtr))
1101        return;
1102    const char* fillValuePlace = linePtr;
1103    if (haveComma)
1104    {
1105        skipSpacesToEnd(linePtr, end);
1106        fillValuePlace = linePtr;
1107        // parse value argument (optional)
1108        if (getAbsoluteValueArg(asmr, value, linePtr))
1109            asmr.printWarningForRange(8, value, asmr.getSourcePos(fillValuePlace));
1110        else
1111            good = false;
1112    }
1113    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1114        return;
1115   
1116    if (int64_t(size) < 0)
1117        return;
1118   
1119    if (asmr.currentSection==ASMSECT_ABS && value != 0)
1120        asmr.printWarning(fillValuePlace, "Fill value is ignored inside absolute section");
1121    asmr.reserveData(size, value&0xff);
1122}
1123
1124void AsmPseudoOps::doAlign(Assembler& asmr, const char* pseudoOpPlace,
1125                           const char* linePtr, bool powerOf2)
1126{
1127    asmr.initializeOutputFormat();
1128    const char* end = asmr.line + asmr.lineSize;
1129   
1130    if (!asmr.isAddressableSection())
1131        PSEUDOOP_RETURN_BY_ERROR("Change output counter inside non-addressable"
1132                    " section is illegal")
1133   
1134    skipSpacesToEnd(linePtr, end);
1135    uint64_t alignment, value = 0, maxAlign = 0;
1136    const char* alignPlace = linePtr;
1137    bool good = getAbsoluteValueArg(asmr, alignment, linePtr, true);
1138   
1139    if (good)
1140    {
1141        // checking alignment value
1142        if (powerOf2)
1143        {
1144            // if alignment is power of 2, then must be lesser than 64
1145            if (alignment > 63)
1146                ASM_NOTGOOD_BY_ERROR(alignPlace, "Power of 2 of alignment is "
1147                            "greater than 63")
1148            else
1149                alignment = (1ULL<<alignment);
1150        }
1151        // checking whether alignment is power of 2
1152        else if (alignment == 0 || (1ULL<<(63-CLZ64(alignment))) != alignment)
1153            ASM_NOTGOOD_BY_ERROR(alignPlace, "Alignment is not power of 2")
1154    }
1155   
1156    bool haveValue = false;
1157    if (!skipComma(asmr, haveValue, linePtr))
1158        return;
1159    const char* valuePlace = linePtr;
1160    if (haveValue)
1161    {
1162        skipSpacesToEnd(linePtr, end);
1163        valuePlace = linePtr;
1164        // parse value argument
1165        if (getAbsoluteValueArg(asmr, value, linePtr))
1166            asmr.printWarningForRange(8, value, asmr.getSourcePos(valuePlace));
1167        else
1168            good = false;
1169       
1170        bool haveComma = false;
1171        if (!skipComma(asmr, haveComma, linePtr))
1172            return;
1173        if (haveComma)
1174        {
1175            skipSpacesToEnd(linePtr, end);
1176            // maxalign argument
1177            good &= getAbsoluteValueArg(asmr, maxAlign, linePtr);
1178        }
1179    }
1180    if (!good || !checkGarbagesAtEnd(asmr, linePtr)) //if parsing failed
1181        return;
1182   
1183    uint64_t outPos = asmr.currentOutPos;
1184    // calculate bytes to fill (to next alignment bytes)
1185    const uint64_t bytesToFill = ((outPos&(alignment-1))!=0) ?
1186            alignment - (outPos&(alignment-1)) : 0;
1187    if (maxAlign!=0 && bytesToFill > maxAlign)
1188        return; // do not make alignment
1189   
1190    if (asmr.currentSection==ASMSECT_ABS && value != 0)
1191        asmr.printWarning(valuePlace, "Fill value is ignored inside absolute section");
1192   
1193    if (haveValue || asmr.sections[asmr.currentSection].type != AsmSectionType::CODE)
1194        asmr.reserveData(bytesToFill, value&0xff);
1195    else /* only if no value and is code section */
1196    {
1197        // call routine to filling alignment from ISA assembler (to fill code by nops)
1198        cxbyte* output = asmr.reserveData(bytesToFill, 0);
1199        asmr.isaAssembler->fillAlignment(bytesToFill, output);
1200    }
1201}
1202
1203template<typename Word>
1204void AsmPseudoOps::doAlignWord(Assembler& asmr, const char* pseudoOpPlace,
1205                       const char* linePtr)
1206{
1207    asmr.initializeOutputFormat();
1208    const char* end = asmr.line + asmr.lineSize;
1209   
1210    if (!asmr.isAddressableSection())
1211        PSEUDOOP_RETURN_BY_ERROR("Change output counter inside non-addressable "
1212                    "section is illegal")
1213   
1214    skipSpacesToEnd(linePtr, end);
1215    uint64_t alignment, value = 0, maxAlign = 0;
1216    const char* alignPlace = linePtr;
1217    bool good = getAbsoluteValueArg(asmr, alignment, linePtr, true);
1218    if (good && alignment != 0 && (1ULL<<(63-CLZ64(alignment))) != alignment)
1219        ASM_NOTGOOD_BY_ERROR(alignPlace, "Alignment is not power of 2")
1220   
1221    bool haveValue = false;
1222    if (!skipComma(asmr, haveValue, linePtr))
1223        return;
1224    const char* valuePlace = linePtr;
1225    if (haveValue)
1226    {
1227        skipSpacesToEnd(linePtr, end);
1228        valuePlace = linePtr;
1229        if (getAbsoluteValueArg(asmr, value, linePtr))
1230            asmr.printWarningForRange(sizeof(Word)<<3, value,
1231                          asmr.getSourcePos(valuePlace));
1232        else
1233            good = false;
1234       
1235        bool haveComma = false;
1236        if (!skipComma(asmr, haveComma, linePtr))
1237            return;
1238        if (haveComma)
1239        {
1240            skipSpacesToEnd(linePtr, end);
1241            // maxalign argument
1242            good &= getAbsoluteValueArg(asmr, maxAlign, linePtr);
1243        }
1244    }
1245    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1246        return;
1247   
1248    if (alignment == 0)
1249        return; // do nothing
1250   
1251    uint64_t outPos = asmr.currentOutPos;
1252    if (outPos&(sizeof(Word)-1))
1253        PSEUDOOP_RETURN_BY_ERROR("Offset is not aligned to word")
1254   
1255    // calculate bytes to fill (to next alignment bytes)
1256    const uint64_t bytesToFill = ((outPos&(alignment-1))!=0) ?
1257            alignment - (outPos&(alignment-1)) : 0;
1258   
1259    if (maxAlign!=0 && bytesToFill > maxAlign)
1260        return; // do not make alignment
1261   
1262    if (asmr.currentSection==ASMSECT_ABS && value != 0)
1263    {
1264        asmr.printWarning(valuePlace, "Fill value is ignored inside absolute section");
1265        asmr.reserveData(bytesToFill);
1266        return;
1267    }
1268    cxbyte* content = asmr.reserveData(bytesToFill);
1269    if (haveValue)
1270    {
1271        Word word;
1272        SLEV(word, value);
1273        std::fill(reinterpret_cast<Word*>(content),
1274                  reinterpret_cast<Word*>(content + bytesToFill), word);
1275    }
1276    else if (asmr.sections[asmr.currentSection].type == AsmSectionType::CODE)
1277        // call routine to filling alignment from ISA assembler (to fill code by nops)
1278        asmr.isaAssembler->fillAlignment(bytesToFill, content);
1279}
1280
1281void AsmPseudoOps::doOrganize(Assembler& asmr, const char* linePtr)
1282{
1283    asmr.initializeOutputFormat();
1284    const char* end = asmr.line + asmr.lineSize;
1285    skipSpacesToEnd(linePtr, end);
1286    uint64_t value;
1287    cxuint sectionId = ASMSECT_ABS;
1288    const char* valuePlace = linePtr;
1289    bool good = getAnyValueArg(asmr, value, sectionId, linePtr);
1290   
1291    uint64_t fillValue = 0;
1292    bool haveComma;
1293    if (!skipComma(asmr, haveComma, linePtr))
1294        return;
1295    const char* fillValuePlace = linePtr;
1296    if (haveComma)
1297    {
1298        // optional fill argument
1299        skipSpacesToEnd(linePtr, end);
1300        fillValuePlace = linePtr;
1301        good = getAbsoluteValueArg(asmr, fillValue, linePtr, true);
1302    }
1303    asmr.printWarningForRange(8, fillValue, asmr.getSourcePos(fillValuePlace));
1304   
1305    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1306        return;
1307   
1308    asmr.assignOutputCounter(valuePlace, value, sectionId, fillValue);
1309}
1310
1311void AsmPseudoOps::doPrint(Assembler& asmr, const char* linePtr)
1312{
1313    std::string outStr;
1314    if (!asmr.parseString(outStr, linePtr))
1315        return;
1316    if (!AsmPseudoOps::checkGarbagesAtEnd(asmr, linePtr))
1317        return;
1318    asmr.printStream.write(outStr.c_str(), outStr.size());
1319    asmr.printStream.put('\n');
1320}
1321
1322/// perform .if for integer comparisons '.iflt', '.ifle', '.ifne'
1323void AsmPseudoOps::doIfInt(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1324               IfIntComp compType, bool elseIfClause)
1325{
1326    const char* end = asmr.line + asmr.lineSize;
1327    skipSpacesToEnd(linePtr, end);
1328    uint64_t value;
1329    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
1330    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1331        return;
1332   
1333    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1334            AsmClauseType::IF;
1335    bool satisfied;
1336    switch(compType)
1337    {
1338        case IfIntComp::EQUAL:
1339            satisfied = (value == 0);
1340            break;
1341        case IfIntComp::NOT_EQUAL:
1342            satisfied = (value != 0);
1343            break;
1344        case IfIntComp::LESS:
1345            satisfied = (int64_t(value) < 0);
1346            break;
1347        case IfIntComp::LESS_EQUAL:
1348            satisfied = (int64_t(value) <= 0);
1349            break;
1350        case IfIntComp::GREATER:
1351            satisfied = (int64_t(value) > 0);
1352            break;
1353        case IfIntComp::GREATER_EQUAL:
1354            satisfied = (int64_t(value) >= 0);
1355            break;
1356        default:
1357            satisfied = false;
1358            break;
1359    }
1360    bool included;
1361    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1362    {   //
1363        if (!included) // skip clauses (do not perform statements)
1364            asmr.skipClauses();
1365    }
1366}
1367
1368// .ifdef (or .ifndef if negation is true)
1369void AsmPseudoOps::doIfDef(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1370               bool negation, bool elseIfClause)
1371{
1372    const char* end = asmr.line + asmr.lineSize;
1373    skipSpacesToEnd(linePtr, end);
1374    const char* symNamePlace = linePtr;
1375    AsmSymbolEntry* entry;
1376    bool good = true;
1377    // parse symbol
1378    Assembler::ParseState state = asmr.parseSymbol(linePtr, entry, false, true);
1379    if (state == Assembler::ParseState::FAILED)
1380        return;
1381    if (state == Assembler::ParseState::MISSING)
1382        ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol")
1383    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1384        return;
1385   
1386    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1387            AsmClauseType::IF;
1388    bool included;
1389    const bool symDefined = (entry!=nullptr && entry->second.isDefined());
1390    bool satisfied = (!negation) ?  symDefined : !symDefined;
1391    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1392    {   //
1393        if (!included) // skip clauses (do not perform statements)
1394            asmr.skipClauses();
1395    }
1396}
1397
1398// .ifb (or .ifnb if negation is true)
1399void AsmPseudoOps::doIfBlank(Assembler& asmr, const char* pseudoOpPlace,
1400             const char* linePtr, bool negation, bool elseIfClause)
1401{
1402    const char* end = asmr.line + asmr.lineSize;
1403    skipSpacesToEnd(linePtr, end);
1404   
1405    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1406            AsmClauseType::IF;
1407    bool included;
1408    bool satisfied = (!negation) ? linePtr==end : linePtr!=end;
1409    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1410    {   //
1411        if (!included) // skip clauses (do not perform statements)
1412            asmr.skipClauses();
1413    }
1414}
1415
1416// this routine get string to compare in rules given GNU as
1417static std::string getStringToCompare(const char* strStart, const char* strEnd)
1418{
1419    std::string firstStr;
1420    bool blank = true;
1421    bool singleQuote = false;
1422    bool dblQuote = false;
1423    cxbyte prevTok = 0;
1424    for (const char* s = strStart; s != strEnd; ++s)
1425        if (isSpace(*s))
1426        {
1427            if (!blank || dblQuote || singleQuote)
1428                firstStr.push_back(*s);
1429            blank = true;
1430        }
1431        else
1432        {
1433            blank = false;
1434            if (*s == '"' && !singleQuote)
1435                dblQuote = !dblQuote;
1436            else if (*s == '\'' && !dblQuote)
1437                singleQuote = !singleQuote;
1438           
1439            /* original GNU as tokenize line before processing, this code 'emulates'
1440             * this operation */
1441            cxbyte thisTok = (cxbyte(*s) >= 0x20 && cxbyte(*s) <= 0x80) ?
1442                    tokenCharTable[*s-0x20] : 0;
1443            if (!singleQuote && !dblQuote && !firstStr.empty() &&
1444                isSpace(firstStr.back()) &&
1445                ((prevTok != thisTok) || ((prevTok == thisTok) && (prevTok & 0x80)==0)))
1446                firstStr.pop_back();// delete space between different tokens
1447           
1448            firstStr.push_back(*s);
1449            prevTok = thisTok;
1450        }
1451    if (!firstStr.empty() && isSpace(firstStr.back()))
1452        firstStr.pop_back(); // remove last space
1453    return firstStr;
1454}
1455
1456void AsmPseudoOps::doIfCmpStr(Assembler& asmr, const char* pseudoOpPlace,
1457               const char* linePtr, bool negation, bool elseIfClause)
1458{
1459    const char* end = asmr.line + asmr.lineSize;
1460    skipSpacesToEnd(linePtr, end);
1461    const char* firstStrStart = linePtr;
1462    bool good = true;
1463    while (linePtr != end && *linePtr != ',') linePtr++;
1464    if (linePtr == end)
1465        ASM_RETURN_BY_ERROR(linePtr, "Missing second string")
1466    const char* firstStrEnd = linePtr;
1467    if (good) linePtr++; // comma
1468    else return;
1469   
1470    std::string firstStr = getStringToCompare(firstStrStart, firstStrEnd);
1471    std::string secondStr = getStringToCompare(linePtr, end);
1472   
1473    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1474            AsmClauseType::IF;
1475    bool included;
1476    bool satisfied = (!negation) ? firstStr==secondStr : firstStr!=secondStr;
1477    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1478    {   //
1479        if (!included) // skip clauses (do not perform statements)
1480            asmr.skipClauses();
1481    }
1482}
1483
1484void AsmPseudoOps::doIfStrEqual(Assembler& asmr, const char* pseudoOpPlace,
1485                const char* linePtr, bool negation, bool elseIfClause)
1486{
1487    const char* end = asmr.line + asmr.lineSize;
1488    skipSpacesToEnd(linePtr, end);
1489    std::string firstStr, secondStr;
1490    bool good = asmr.parseString(firstStr, linePtr);
1491    if (!skipRequiredComma(asmr, linePtr))
1492        return;
1493    skipSpacesToEnd(linePtr, end);
1494    good &= asmr.parseString(secondStr, linePtr);
1495    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1496        return;
1497   
1498    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1499            AsmClauseType::IF;
1500    bool included;
1501    bool satisfied = (!negation) ? firstStr==secondStr : firstStr!=secondStr;
1502    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1503    {   //
1504        if (!included) // skip clauses (do not perform statements)
1505            asmr.skipClauses();
1506    }
1507}
1508
1509void AsmPseudoOps::doIf64Bit(Assembler& asmr, const char* pseudoOpPlace,
1510                const char* linePtr, bool negation, bool elseIfClause)
1511{
1512    if (!checkGarbagesAtEnd(asmr, linePtr))
1513        return;
1514   
1515    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1516            AsmClauseType::IF;
1517    bool included;
1518    bool satisfied = (!negation) ? asmr._64bit : !asmr._64bit;
1519    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1520    {   //
1521        if (!included) // skip clauses (do not perform statements)
1522            asmr.skipClauses();
1523    }
1524}
1525
1526void AsmPseudoOps::doIfArch(Assembler& asmr, const char* pseudoOpPlace,
1527            const char* linePtr, bool negation, bool elseIfClause)
1528{
1529    const char* end = asmr.line + asmr.lineSize;
1530    skipSpacesToEnd(linePtr, end);
1531    char deviceName[64];
1532    const char* archNamePlace = linePtr;
1533    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU architecture name"))
1534        return;
1535    GPUArchitecture arch;
1536    try
1537    {
1538        arch = getGPUArchitectureFromName(deviceName);
1539        if (!checkGarbagesAtEnd(asmr, linePtr))
1540            return;
1541    }
1542    catch(const Exception& ex)
1543    {
1544        // if architecture not found (unknown architecture)
1545        asmr.printError(archNamePlace, ex.what());
1546        return;
1547    }
1548   
1549    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1550            AsmClauseType::IF;
1551    bool included;
1552    GPUArchitecture curArch = getGPUArchitectureFromDeviceType(asmr.getDeviceType());
1553    bool satisfied = (!negation) ? arch==curArch : arch!=curArch;
1554    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1555    {   //
1556        if (!included) // skip clauses (do not perform statements)
1557            asmr.skipClauses();
1558    }
1559}
1560
1561void AsmPseudoOps::doIfGpu(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1562            bool negation, bool elseIfClause)
1563{
1564    const char* end = asmr.line + asmr.lineSize;
1565    skipSpacesToEnd(linePtr, end);
1566    char deviceName[64];
1567    const char* deviceNamePlace = linePtr;
1568    if (!getNameArg(asmr, 64, deviceName, linePtr, "GPU device name"))
1569        return;
1570    GPUDeviceType deviceType;
1571    try
1572    {
1573        deviceType = getGPUDeviceTypeFromName(deviceName);
1574        if (!checkGarbagesAtEnd(asmr, linePtr))
1575            return;
1576    }
1577    catch(const Exception& ex)
1578    {
1579        // if GPU device name is unknown, print error
1580        asmr.printError(deviceNamePlace, ex.what());
1581        return;
1582    }
1583   
1584    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1585            AsmClauseType::IF;
1586    bool included;
1587    bool satisfied = (!negation) ? deviceType==asmr.deviceType :
1588                deviceType!=asmr.deviceType;
1589    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1590    {   //
1591        if (!included) // skip clauses (do not perform statements)
1592            asmr.skipClauses();
1593    }
1594}
1595
1596void AsmPseudoOps::doIfFmt(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1597            bool negation, bool elseIfClause)
1598{
1599    const char* end = asmr.line + asmr.lineSize;
1600    skipSpacesToEnd(linePtr, end);
1601    BinaryFormat format;
1602    // parse binary format name
1603    if (!parseFormat(asmr, linePtr, format))
1604        return;
1605   
1606    const AsmClauseType clauseType = elseIfClause ? AsmClauseType::ELSEIF :
1607            AsmClauseType::IF;
1608    bool included;
1609    bool satisfied = (!negation) ? format==asmr.format: format!=asmr.format;
1610    if (asmr.pushClause(pseudoOpPlace, clauseType, satisfied, included))
1611    {   //
1612        if (!included) // skip clauses (do not perform statements)
1613            asmr.skipClauses();
1614    }
1615}
1616
1617void AsmPseudoOps::doElse(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1618{
1619    if (!checkGarbagesAtEnd(asmr, linePtr))
1620        return;
1621    bool included;
1622    if (asmr.pushClause(pseudoOpPlace, AsmClauseType::ELSE, true, included))
1623    {
1624        if (!included) // skip clauses (do not perform statements)
1625            asmr.skipClauses();
1626    }
1627}
1628
1629void AsmPseudoOps::endIf(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1630{
1631    if (!checkGarbagesAtEnd(asmr, linePtr))
1632        return;
1633    asmr.popClause(pseudoOpPlace, AsmClauseType::IF);
1634}
1635
1636void AsmPseudoOps::doRepeat(Assembler& asmr, const char* pseudoOpPlace,
1637                    const char* linePtr)
1638{
1639    const char* end = asmr.line + asmr.lineSize;
1640    skipSpacesToEnd(linePtr, end);
1641    uint64_t repeatsNum;
1642    bool good = getAbsoluteValueArg(asmr, repeatsNum, linePtr, true);
1643    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1644        return;
1645   
1646    if (asmr.repetitionLevel == 1000)
1647        PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
1648    asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
1649    if (repeatsNum == 0)
1650    {
1651        /* skip it */
1652        asmr.skipClauses();
1653        return;
1654    }
1655    /* create repetition (even if only 1 - for correct source position included
1656     * to messages from repetition) */
1657    std::unique_ptr<AsmRepeat> repeat(new AsmRepeat(
1658                asmr.getSourcePos(pseudoOpPlace), repeatsNum));
1659    if (asmr.putRepetitionContent(*repeat))
1660    {
1661        // and input stream filter
1662        std::unique_ptr<AsmInputFilter> newInputFilter(
1663                    new AsmRepeatInputFilter(repeat.release()));
1664        asmr.asmInputFilters.push(newInputFilter.release());
1665        asmr.currentInputFilter = asmr.asmInputFilters.top();
1666        asmr.repetitionLevel++;
1667    }
1668}
1669
1670void AsmPseudoOps::endRepeat(Assembler& asmr, const char* pseudoOpPlace,
1671                   const char* linePtr)
1672{
1673    if (!checkGarbagesAtEnd(asmr, linePtr))
1674        return;
1675    asmr.popClause(pseudoOpPlace, AsmClauseType::REPEAT);
1676}
1677
1678void AsmPseudoOps::doMacro(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1679{
1680    const char* end = asmr.line + asmr.lineSize;
1681    skipSpacesToEnd(linePtr, end);
1682    const char* macroNamePlace = linePtr;
1683    CString macroName = extractSymName(linePtr, end, false);
1684    if (macroName.empty())
1685        ASM_RETURN_BY_ERROR(macroNamePlace, "Expected macro name")
1686    // convert to lower (name is case-insensitive)
1687    if (asmr.macroCase)
1688        toLowerString(macroName);
1689    /* parse args */
1690    std::vector<AsmMacroArg> args;
1691   
1692    bool good = true;
1693    bool haveVarArg = false;
1694   
1695    if (asmr.macroMap.find(macroName) != asmr.macroMap.end())
1696        ASM_NOTGOOD_BY_ERROR(macroNamePlace, (std::string("Macro '") + macroName.c_str() +
1697                "' is already defined").c_str())
1698   
1699    {
1700    std::unordered_set<CString> macroArgSet;
1701    while(linePtr != end)
1702    {
1703        skipSpacesToEnd(linePtr, end);
1704        if (linePtr != end && *linePtr == ',')
1705            skipCharAndSpacesToEnd(linePtr, end);
1706        const char* argPlace = linePtr;
1707        CString argName = extractSymName(linePtr, end, false);
1708        if (argName.empty())
1709            ASM_RETURN_BY_ERROR(argPlace, "Expected macro argument name")
1710        bool argRequired = false;
1711        bool argVarArgs = false;
1712        bool argGood = true;
1713        std::string defaultArgValue;
1714       
1715        if (!macroArgSet.insert(argName).second)
1716            // duplicate!
1717            ASM_NOTGOOD_BY_ERROR1(argGood, argPlace, (std::string(
1718                    "Duplicated macro argument '")+ argName.c_str()+'\'').c_str())
1719       
1720        skipSpacesToEnd(linePtr, end);
1721        if (linePtr != end && *linePtr == ':')
1722        {
1723            // parse argument's qualifier
1724            skipCharAndSpacesToEnd(linePtr, end);
1725            //extr
1726            if (linePtr+3 <= end && linePtr[0] == 'r' && linePtr[1] == 'e' &&
1727                    linePtr[2] == 'q') // reqd (if argument required)
1728            {
1729                argRequired = true;
1730                linePtr += 3;
1731            }
1732            else if (linePtr+6 <= end && ::memcmp(linePtr, "vararg", 6)==0) // required
1733            {
1734                argVarArgs = true;
1735                linePtr += 6;
1736            }
1737            else // otherwise
1738                ASM_NOTGOOD_BY_ERROR1(argGood, linePtr,
1739                        "Expected qualifier 'req' or 'vararg'")
1740        }
1741        skipSpacesToEnd(linePtr, end);
1742        if (linePtr != end && *linePtr == '=')
1743        {
1744            // parse default value
1745            skipCharAndSpacesToEnd(linePtr, end);
1746            const char* defaultValueStr = linePtr;
1747            if (!asmr.parseMacroArgValue(linePtr, defaultArgValue))
1748            {
1749                good = false;
1750                continue; // error
1751            }
1752            if (argRequired)
1753                asmr.printWarning(defaultValueStr, (std::string(
1754                        "Pointless default value for argument '") +
1755                        argName.c_str()+'\'').c_str());
1756        }
1757       
1758        if (argGood)
1759        {
1760            // push to arguments
1761            if (haveVarArg)
1762                ASM_NOTGOOD_BY_ERROR(argPlace, "Variadic argument must be last")
1763            else
1764                haveVarArg = argVarArgs;
1765        }
1766        else // not good
1767            good = false;
1768       
1769        if (argGood) // push argument
1770            args.push_back({argName, defaultArgValue, argVarArgs, argRequired});
1771    }
1772    }
1773    if (good)
1774    {   
1775        if (checkPseudoOpName(macroName))
1776        {
1777            // ignore if name of macro is name of pseudo op name
1778            asmr.printWarning(pseudoOpPlace, (std::string(
1779                        "Attempt to redefine pseudo-op '")+macroName.c_str()+
1780                        "' as macro. Ignoring it...").c_str());
1781            asmr.pushClause(pseudoOpPlace, AsmClauseType::MACRO);
1782            asmr.skipClauses();
1783            return;
1784        }
1785        // create a macro and put macro map
1786        RefPtr<const AsmMacro> macro(new AsmMacro(asmr.getSourcePos(pseudoOpPlace),
1787                        Array<AsmMacroArg>(args.begin(), args.end())));
1788        asmr.pushClause(pseudoOpPlace, AsmClauseType::MACRO);
1789        if (!asmr.putMacroContent(macro.constCast<AsmMacro>()))
1790            return;
1791        asmr.macroMap.insert(std::make_pair(std::move(macroName), std::move(macro)));
1792    }
1793}
1794
1795void AsmPseudoOps::endMacro(Assembler& asmr, const char* pseudoOpPlace,
1796                    const char* linePtr)
1797{
1798    if (!checkGarbagesAtEnd(asmr, linePtr))
1799        return;
1800    asmr.popClause(pseudoOpPlace, AsmClauseType::MACRO);
1801}
1802
1803void AsmPseudoOps::exitMacro(Assembler& asmr, const char* pseudoOpPlace,
1804                   const char* linePtr)
1805{
1806    if (!checkGarbagesAtEnd(asmr, linePtr))
1807        return;
1808   
1809    const AsmInputFilterType type = asmr.currentInputFilter->getType();
1810    if (type == AsmInputFilterType::STREAM)
1811        asmr.printWarning(pseudoOpPlace, "'.exitm' is ignored outside macro content");
1812    else
1813    {
1814        if (type == AsmInputFilterType::REPEAT)
1815            asmr.printWarning(pseudoOpPlace, "Behavior of '.exitm' inside repeat is "
1816                    "undefined. Exiting from repeat...");
1817        // skipping clauses to current macro
1818        asmr.skipClauses(true);
1819    }
1820}
1821
1822void AsmPseudoOps::doIRP(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr,
1823              bool perChar)
1824{
1825    const char* end = asmr.line + asmr.lineSize;
1826    skipSpacesToEnd(linePtr, end);
1827    const char* symNamePlace = linePtr;
1828    CString symName = extractSymName(linePtr, end, false);
1829    if (symName.empty())
1830        ASM_RETURN_BY_ERROR(symNamePlace, "Expected argument name")
1831    /* parse args */
1832    std::vector<CString> symValues;
1833    std::string symValString;
1834   
1835    bool good = true;
1836    skipSpacesToEnd(linePtr, end);
1837    if (linePtr != end && *linePtr == ',')
1838        skipCharAndSpacesToEnd(linePtr, end);
1839   
1840    // parse list of symvalues for repetitions
1841    while(linePtr != end)
1842    {
1843        if (linePtr != end && *linePtr == ',')
1844        {
1845            if (perChar)
1846                // because if value stores as character we add ','
1847                symValString.push_back(',');
1848            skipCharAndSpacesToEnd(linePtr, end);
1849        }
1850        std::string symValue;
1851        if (!asmr.parseMacroArgValue(linePtr, symValue))
1852        {
1853            good = false;
1854            continue; // error
1855        }
1856        skipSpacesToEnd(linePtr, end);
1857        if (!perChar)
1858            // push single sym value
1859            symValues.push_back(symValue);
1860        else
1861            // otherwise this sym value as string of values
1862            symValString += symValue;
1863    }
1864   
1865    // check depth of repetitions
1866    if (asmr.repetitionLevel == 1000)
1867        PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
1868   
1869    if (symValues.empty())
1870        symValues.push_back("");
1871    if (good)
1872    {
1873        // create IRP repetition
1874        asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
1875        std::unique_ptr<AsmIRP> repeat;
1876        if (!perChar)
1877            repeat.reset(new AsmIRP(asmr.getSourcePos(pseudoOpPlace),
1878                      symName, Array<CString>(symValues.begin(), symValues.end())));
1879        else // per char
1880            repeat.reset(new AsmIRP(asmr.getSourcePos(pseudoOpPlace),
1881                      symName, symValString));
1882       
1883        if (asmr.putRepetitionContent(*repeat))
1884        {
1885            // and input stream filter
1886            std::unique_ptr<AsmInputFilter> newInputFilter(
1887                        new AsmIRPInputFilter(repeat.release()));
1888            asmr.asmInputFilters.push(newInputFilter.release());
1889            asmr.currentInputFilter = asmr.asmInputFilters.top();
1890            asmr.repetitionLevel++;
1891        }
1892    }
1893}
1894
1895void AsmPseudoOps::doFor(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1896{
1897    const char* end = asmr.line+asmr.lineSize;
1898    skipSpacesToEnd(linePtr, end);
1899    const char* symNamePlace = linePtr;
1900    AsmSymbolEntry* iterSymbol = nullptr;
1901    const CString symName = extractScopedSymName(linePtr, end, false);
1902    if (symName.empty())
1903        ASM_RETURN_BY_ERROR(symNamePlace, "Illegal symbol name")
1904    size_t symNameLength = symName.size();
1905    // special case for '.' symbol (check whether is in global scope)
1906    if (symNameLength >= 3 && symName.compare(symNameLength-3, 3, "::.")==0)
1907        ASM_RETURN_BY_ERROR(symNamePlace, "Symbol '.' can be only in global scope")
1908   
1909    bool good = true;
1910    skipSpacesToEnd(linePtr, end);
1911    if (linePtr==end || *linePtr!='=')
1912        ASM_NOTGOOD_BY_ERROR(linePtr, "Expected '='")
1913    skipCharAndSpacesToEnd(linePtr, end);
1914    uint64_t value = 0;
1915    cxuint sectionId = ASMSECT_ABS;
1916    good &= AsmParseUtils::getAnyValueArg(asmr, value, sectionId, linePtr);
1917    if (good)
1918    {
1919        std::pair<AsmSymbolEntry*, bool> res = asmr.insertSymbolInScope(symName,
1920                    AsmSymbol(sectionId, value));
1921        if (!res.second)
1922        {
1923            // if symbol found
1924            if (res.first->second.onceDefined && res.first->second.isDefined()) // if label
1925            {
1926                asmr.printError(symNamePlace, (std::string("Symbol '")+symName.c_str()+
1927                            "' is already defined").c_str());
1928                good = false;
1929            }
1930            else // set value of symbol
1931                asmr.setSymbol(*res.first, value, sectionId);
1932        }
1933        else // set hasValue (by isResolvableSection
1934            res.first->second.hasValue = asmr.isResolvableSection(sectionId);
1935        iterSymbol = res.first;
1936    }
1937   
1938    if (!skipRequiredComma(asmr, linePtr))
1939        return;
1940    std::unique_ptr<AsmExpression> condExpr(AsmExpression::parse(asmr, linePtr, true));
1941    if (!skipRequiredComma(asmr, linePtr))
1942        return;
1943    std::unique_ptr<AsmExpression> nextExpr(AsmExpression::parse(asmr, linePtr, true));
1944   
1945    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
1946        return;
1947   
1948    if (condExpr==nullptr || nextExpr==nullptr)
1949        return; // if no expressions
1950   
1951    // check depth of repetitions
1952    if (asmr.repetitionLevel == 1000)
1953        PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
1954   
1955    // create AsmFor
1956    asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
1957    std::unique_ptr<AsmFor> repeat(new AsmFor(
1958                asmr.getSourcePos(pseudoOpPlace), iterSymbol, condExpr.get(),
1959                nextExpr.get()));
1960    condExpr.release();
1961    nextExpr.release();
1962    if (asmr.putRepetitionContent(*repeat))
1963    {
1964        // and input stream filter
1965        std::unique_ptr<AsmInputFilter> newInputFilter(
1966                    new AsmForInputFilter(repeat.release()));
1967        asmr.asmInputFilters.push(newInputFilter.release());
1968        asmr.currentInputFilter = asmr.asmInputFilters.top();
1969        asmr.repetitionLevel++;
1970    }
1971}
1972
1973void AsmPseudoOps::doWhile(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
1974{
1975    std::unique_ptr<AsmExpression> condExpr(AsmExpression::parse(asmr, linePtr, true));
1976    if (!checkGarbagesAtEnd(asmr, linePtr))
1977        return;
1978   
1979    if (condExpr==nullptr)
1980        return; // if no expressions
1981   
1982    // check depth of repetitions
1983    if (asmr.repetitionLevel == 1000)
1984        PSEUDOOP_RETURN_BY_ERROR("Repetition level is greater than 1000")
1985   
1986    // create AsmFor
1987    asmr.pushClause(pseudoOpPlace, AsmClauseType::REPEAT);
1988    std::unique_ptr<AsmFor> repeat(new AsmFor(
1989                asmr.getSourcePos(pseudoOpPlace), nullptr, condExpr.get(), nullptr));
1990    condExpr.release();
1991    if (asmr.putRepetitionContent(*repeat))
1992    {
1993        // and input stream filter
1994        std::unique_ptr<AsmInputFilter> newInputFilter(
1995                    new AsmForInputFilter(repeat.release()));
1996        asmr.asmInputFilters.push(newInputFilter.release());
1997        asmr.currentInputFilter = asmr.asmInputFilters.top();
1998        asmr.repetitionLevel++;
1999    }
2000}
2001
2002void AsmPseudoOps::purgeMacro(Assembler& asmr, const char* linePtr)
2003{
2004    const char* end = asmr.line+asmr.lineSize;
2005    skipSpacesToEnd(linePtr, end);
2006    const char* macroNamePlace = linePtr;
2007    CString macroName = extractSymName(linePtr, end, false);
2008    bool good = true;
2009    if (macroName.empty())
2010        ASM_NOTGOOD_BY_ERROR(macroNamePlace, "Expected macro name")
2011    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2012        return;
2013    // convert to lower (name is case-insensitive)
2014    if (asmr.macroCase)
2015        toLowerString(macroName); // macro name is lowered
2016   
2017    if (!asmr.macroMap.erase(macroName))
2018        asmr.printWarning(macroNamePlace, (std::string("Macro '")+macroName.c_str()+
2019                "' already doesn't exist").c_str());
2020}
2021
2022void AsmPseudoOps::openScope(Assembler& asmr, const char* pseudoOpPlace,
2023                     const char* linePtr)
2024{
2025    const char* end = asmr.line+asmr.lineSize;
2026    skipSpacesToEnd(linePtr, end);
2027    CString scopeName = extractSymName(linePtr, end, false);
2028    bool good = true;
2029    // check depth of scopes
2030    if (asmr.scopeStack.size() == 1000)
2031        ASM_NOTGOOD_BY_ERROR(pseudoOpPlace, "Scope level is greater than 1000")
2032    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2033        return;
2034   
2035    asmr.pushScope(scopeName);
2036}
2037
2038void AsmPseudoOps::closeScope(Assembler& asmr, const char* pseudoOpPlace,
2039                      const char* linePtr)
2040{
2041    const char* end = asmr.line+asmr.lineSize;
2042    skipSpacesToEnd(linePtr, end);
2043    bool good = true;
2044    if (asmr.scopeStack.empty())
2045        ASM_NOTGOOD_BY_ERROR(pseudoOpPlace, "Closing global scope is illegal")
2046    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2047        return;
2048    asmr.popScope();
2049}
2050
2051void AsmPseudoOps::startUsing(Assembler& asmr, const char* linePtr)
2052{
2053    const char* end = asmr.line+asmr.lineSize;
2054    skipSpacesToEnd(linePtr, end);
2055    const char* scopePathPlace = linePtr;
2056    CString scopePath = extractScopedSymName(linePtr, end);
2057    bool good = true;
2058    if (scopePath.empty() || scopePath == "::")
2059        ASM_NOTGOOD_BY_ERROR(scopePathPlace, "Expected scope path")
2060    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2061        return;
2062    AsmScope* scope = asmr.getRecurScope(scopePath);
2063    // do add this
2064    asmr.currentScope->startUsingScope(scope);
2065}
2066
2067void AsmPseudoOps::doUseReg(Assembler& asmr, const char* linePtr)
2068{
2069    const char* end = asmr.line+asmr.lineSize;
2070    asmr.initializeOutputFormat();
2071   
2072    do {
2073        skipSpacesToEnd(linePtr, end);
2074        bool good = true;
2075        cxuint regStart, regEnd;
2076        const AsmRegVar* regVar;
2077        good = asmr.isaAssembler->parseRegisterRange(linePtr, regStart, regEnd, regVar);
2078        skipSpacesToEnd(linePtr, end);
2079        if (linePtr==end || *linePtr!=':')
2080        {
2081            asmr.printError(linePtr, "Expected colon after register");
2082            continue;
2083        }
2084        skipCharAndSpacesToEnd(linePtr, end);
2085       
2086        cxbyte rwFlags = 0;
2087        // parse read/write flags (r,w,rw)
2088        for (; linePtr != end; linePtr++)
2089        {
2090            char c = toLower(*linePtr);
2091            if (c!='r' && c!='w')
2092                break;
2093            rwFlags |= (c=='r') ? ASMRVU_READ : ASMRVU_WRITE;
2094        }
2095        if (rwFlags==0) // not parsed
2096        {
2097            asmr.printError(linePtr, "Expected access mask");
2098            continue;
2099        }
2100       
2101        if (good) // if good
2102        {
2103            // create usageHandler if needed
2104            if (asmr.sections[asmr.currentSection].usageHandler == nullptr)
2105                    asmr.sections[asmr.currentSection].usageHandler.reset(
2106                            asmr.isaAssembler->createUsageHandler(
2107                                    asmr.sections[asmr.currentSection].content));
2108            // put regVar usage
2109            asmr.sections[asmr.currentSection].usageHandler->pushUseRegUsage(
2110                AsmRegVarUsage{ size_t(asmr.currentOutPos), regVar,
2111                    uint16_t(regStart), uint16_t(regEnd), ASMFIELD_NONE, rwFlags, 0 });
2112        }
2113       
2114    } while(skipCommaForMultipleArgs(asmr, linePtr));
2115   
2116    checkGarbagesAtEnd(asmr, linePtr);
2117}
2118
2119void AsmPseudoOps::stopUsing(Assembler& asmr, const char* linePtr)
2120{
2121    const char* end = asmr.line+asmr.lineSize;
2122    skipSpacesToEnd(linePtr, end);
2123    const char* scopePathPlace = linePtr;
2124    CString scopePath = extractScopedSymName(linePtr, end);
2125    bool good = true;
2126    if (scopePath == "::")
2127        ASM_NOTGOOD_BY_ERROR(scopePathPlace, "Expected scope path")
2128    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2129        return;
2130    AsmScope* scope = asmr.getRecurScope(scopePath);
2131    if (!scopePath.empty())
2132        asmr.currentScope->stopUsingScope(scope);
2133    else // stop using all scopes
2134        asmr.currentScope->stopUsingScopes();
2135}
2136
2137void AsmPseudoOps::undefSymbol(Assembler& asmr, const char* linePtr)
2138{
2139    const char* end = asmr.line+asmr.lineSize;
2140    skipSpacesToEnd(linePtr, end);
2141    const char* symNamePlace = linePtr;
2142    CString symName = extractScopedSymName(linePtr, end, false);
2143    bool good = true;
2144    if (symName.empty())
2145        ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol name")
2146    // symbol '.' can not be undefined
2147    else if (symName == ".")
2148        ASM_NOTGOOD_BY_ERROR(symNamePlace, "Symbol '.' can not be undefined")
2149    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2150        return;
2151   
2152    CString sameSymName;
2153    AsmScope* outScope;
2154    AsmSymbolEntry* it = asmr.findSymbolInScope(symName, outScope, sameSymName);
2155    if (it == nullptr || !it->second.isDefined())
2156        asmr.printWarning(symNamePlace, (std::string("Symbol '") + symName.c_str() +
2157                "' already doesn't exist").c_str());
2158    else // always undefine (do not remove, due to .eqv evaluation)
2159        asmr.undefineSymbol(*it);
2160}
2161
2162void AsmPseudoOps::setAbsoluteOffset(Assembler& asmr, const char* linePtr)
2163{
2164    const char* end = asmr.line+asmr.lineSize;
2165    asmr.initializeOutputFormat();
2166    skipSpacesToEnd(linePtr, end);
2167    uint64_t value = 0;
2168    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
2169    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2170        return;
2171    asmr.currentSection = ASMSECT_ABS;
2172    asmr.currentOutPos = value;
2173}
2174
2175void AsmPseudoOps::defRegVar(Assembler& asmr, const char* linePtr)
2176{
2177    const char* end = asmr.line+asmr.lineSize;
2178    asmr.initializeOutputFormat();
2179   
2180    do {
2181        skipSpacesToEnd(linePtr, end);
2182        const char* regNamePlace = linePtr;
2183        CString name = extractScopedSymName(linePtr, end, false);
2184        bool good = true;
2185        if (name.empty())
2186            ASM_NOTGOOD_BY_ERROR(regNamePlace, "Expected reg-var name")
2187        skipSpacesToEnd(linePtr, end);
2188        if (linePtr==end || *linePtr!=':')
2189        {
2190            asmr.printError(linePtr, "Expected colon after reg-var");
2191            continue;
2192        }
2193        skipCharAndSpacesToEnd(linePtr, end);
2194        AsmRegVar var = { 0, 1 };
2195        if (!asmr.isaAssembler->parseRegisterType(linePtr, end, var.type))
2196            ASM_NOTGOOD_BY_ERROR(linePtr, "Expected name of register type")
2197        skipSpacesToEnd(linePtr, end);
2198       
2199        if (linePtr!=end && *linePtr!=',')
2200        {
2201            if (*linePtr!=':')
2202            {
2203                asmr.printError(linePtr, "Expected colon after reg-var");
2204                continue;
2205            }
2206            linePtr++;
2207            skipSpacesToEnd(linePtr, end);
2208            uint64_t regSize;
2209            if (!getAbsoluteValueArg(asmr, regSize, linePtr, true))
2210                continue;
2211            if (regSize==0)
2212                ASM_NOTGOOD_BY_ERROR(linePtr, "Size of reg-var is zero")
2213            if (regSize>UINT16_MAX)
2214                ASM_NOTGOOD_BY_ERROR(linePtr, "Size of reg-var out of range")
2215            var.size = regSize;
2216        }
2217       
2218        if (!good)
2219            continue;
2220       
2221        if (!asmr.addRegVar(name, var))
2222            asmr.printError(regNamePlace, (std::string("Reg-var '")+name.c_str()+
2223                        "' was already defined").c_str());
2224       
2225    } while(skipCommaForMultipleArgs(asmr, linePtr));
2226   
2227    checkGarbagesAtEnd(asmr, linePtr);
2228}
2229
2230void AsmPseudoOps::addCodeFlowEntries(Assembler& asmr, const char* pseudoOpPlace,
2231                     const char* linePtr, AsmCodeFlowType type)
2232{
2233    const bool acceptArgs = (type==AsmCodeFlowType::JUMP || type==AsmCodeFlowType::CJUMP ||
2234            type==AsmCodeFlowType::CALL);
2235    asmr.initializeOutputFormat();
2236   
2237    if (asmr.currentSection==ASMSECT_ABS ||
2238        asmr.sections[asmr.currentSection].type != AsmSectionType::CODE)
2239        PSEUDOOP_RETURN_BY_ERROR("Defining codeflow in non-code section is illegal")
2240   
2241    const char* end = asmr.line+asmr.lineSize;
2242    if (acceptArgs)
2243    {
2244        // multiple entries
2245        do {
2246            bool good = true;
2247            skipSpacesToEnd(linePtr, end);
2248            if (!good)
2249                continue;
2250            std::unique_ptr<AsmExpression> expr;
2251            uint64_t target;
2252            if (!getJumpValueArg(asmr, target, expr, linePtr))
2253                continue;
2254            asmr.sections[asmr.currentSection].addCodeFlowEntry({ 
2255                    size_t(asmr.currentOutPos), size_t(target), type });
2256            if (expr)
2257                expr->setTarget(AsmExprTarget::codeFlowTarget(asmr.currentSection,
2258                        asmr.sections[asmr.currentSection].codeFlow.size()-1));
2259            expr.release();
2260        } while (skipCommaForMultipleArgs(asmr, linePtr));
2261    }
2262    else // single entry without target
2263        asmr.sections[asmr.currentSection].addCodeFlowEntry({ 
2264                    size_t(asmr.currentOutPos), 0, type });
2265   
2266    checkGarbagesAtEnd(asmr, linePtr);
2267}
2268
2269// get predefine value ('.get_64bit', '.get_arch', '.get_format')
2270void AsmPseudoOps::getPredefinedValue(Assembler& asmr, const char* linePtr,
2271                            AsmPredefined predefined)
2272{
2273    cxuint predefValue = 0;
2274    // we must initialize output format before getting any arch, gpu or format
2275    // must be set before
2276    asmr.initializeOutputFormat();
2277    switch (predefined)
2278    {
2279        case AsmPredefined::ARCH:
2280            predefValue = cxuint(getGPUArchitectureFromDeviceType(asmr.deviceType));
2281            break;
2282        case AsmPredefined::BIT64:
2283            predefValue = asmr._64bit;
2284            break;
2285        case AsmPredefined::GPU:
2286            predefValue = cxuint(asmr.deviceType);
2287            break;
2288        case AsmPredefined::FORMAT:
2289            predefValue = cxuint(asmr.format);
2290            break;
2291        case AsmPredefined::VERSION:
2292            predefValue = CLRX_MAJOR_VERSION*10000U + CLRX_MINOR_VERSION*100U +
2293                    CLRX_MICRO_VERSION;
2294            break;
2295        default:
2296            break;
2297    }
2298    AsmParseUtils::setSymbolValue(asmr, linePtr, predefValue, ASMSECT_ABS);
2299}
2300
2301void AsmPseudoOps::doEnum(Assembler& asmr, const char* pseudoOpPlace, const char* linePtr)
2302{
2303    const char* end = asmr.line + asmr.lineSize;
2304    skipSpacesToEnd(linePtr, end);
2305    uint64_t& enumCount = asmr.currentScope->enumCount;
2306    if (linePtr!=end && *linePtr=='>')
2307    {
2308        // parse enum start
2309        linePtr++;
2310        uint64_t enumStart = 0;
2311        if (!getAbsoluteValueArg(asmr, enumStart, linePtr, false))
2312            return;
2313       
2314        enumCount = enumStart;
2315        if (!skipRequiredComma(asmr, linePtr))
2316            return;
2317    }
2318    skipSpacesToEnd(linePtr, end);
2319    do {
2320        const char* strAtSymName = linePtr;
2321        CString symbolName = extractScopedSymName(linePtr, end, false);
2322        if (!symbolName.empty())
2323        {
2324            std::pair<AsmSymbolEntry*, bool> res =
2325                    asmr.insertSymbolInScope(symbolName, AsmSymbol());
2326            if (!res.second && res.first->second.isDefined())
2327                // found and can be only once defined
2328                asmr.printError(strAtSymName, (std::string("Symbol '") +
2329                        symbolName.c_str() + "' is already defined").c_str());
2330            else
2331            {
2332                asmr.setSymbol(*res.first, enumCount++, ASMSECT_ABS);
2333                res.first->second.onceDefined = true;
2334            }
2335        }
2336        else
2337            asmr.printError(linePtr, "Expected symbol name");
2338       
2339    } while(skipCommaForMultipleArgs(asmr, linePtr));
2340    checkGarbagesAtEnd(asmr, linePtr);
2341}
2342
2343void AsmPseudoOps::ignoreString(Assembler& asmr, const char* linePtr)
2344{
2345    const char* end = asmr.line+asmr.lineSize;
2346    skipSpacesToEnd(linePtr, end);
2347    std::string out;
2348    if (asmr.parseString(out, linePtr))
2349        checkGarbagesAtEnd(asmr, linePtr);
2350}
2351
2352// checking whether name is pseudo-op name
2353// (checking any extra pseudo-op provided by format handler)
2354bool AsmPseudoOps::checkPseudoOpName(const CString& string)
2355{
2356    if (string.empty() || string[0] != '.')
2357        return false;
2358    const size_t pseudoOp = binaryFind(pseudoOpNamesTbl, pseudoOpNamesTbl +
2359                    sizeof(pseudoOpNamesTbl)/sizeof(char*), string.c_str()+1,
2360                   CStringLess()) - pseudoOpNamesTbl;
2361    if (pseudoOp < sizeof(pseudoOpNamesTbl)/sizeof(char*))
2362        return true;
2363    if (AsmGalliumPseudoOps::checkPseudoOpName(string))
2364        return true;
2365    if (AsmAmdPseudoOps::checkPseudoOpName(string))
2366        return true;
2367    if (AsmAmdCL2PseudoOps::checkPseudoOpName(string))
2368        return true;
2369    if (AsmROCmPseudoOps::checkPseudoOpName(string))
2370        return true;
2371    return false;
2372}
2373
2374};
2375
2376void Assembler::parsePseudoOps(const CString& firstName,
2377       const char* stmtPlace, const char* linePtr)
2378{
2379    const size_t pseudoOp = binaryFind(pseudoOpNamesTbl, pseudoOpNamesTbl +
2380                    sizeof(pseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
2381                   CStringLess()) - pseudoOpNamesTbl;
2382   
2383    switch(pseudoOp)
2384    {
2385        case ASMOP_32BIT:
2386        case ASMOP_64BIT:
2387            AsmPseudoOps::setBitness(*this, linePtr, pseudoOp == ASMOP_64BIT);
2388            break;
2389        case ASMOP_ABORT:
2390            printError(stmtPlace, "Aborted!");
2391            endOfAssembly = true;
2392            break;
2393        case ASMOP_ALIGN:
2394        case ASMOP_BALIGN:
2395            AsmPseudoOps::doAlign(*this, stmtPlace, linePtr);
2396            break;
2397        case ASMOP_ALTMACRO:
2398            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2399                alternateMacro = true;
2400            break;
2401        case ASMOP_ARCH:
2402            AsmPseudoOps::setGPUArchitecture(*this, linePtr);
2403            break;
2404        case ASMOP_ASCII:
2405            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr);
2406            break;
2407        case ASMOP_ASCIZ:
2408            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr, true);
2409            break;
2410        case ASMOP_BALIGNL:
2411            AsmPseudoOps::doAlignWord<uint32_t>(*this, stmtPlace, linePtr);
2412            break;
2413        case ASMOP_BALIGNW:
2414            AsmPseudoOps::doAlignWord<uint16_t>(*this, stmtPlace, linePtr);
2415            break;
2416        case ASMOP_BUGGYFPLIT:
2417            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2418                buggyFPLit = true;
2419            break;
2420        case ASMOP_BYTE:
2421            AsmPseudoOps::putIntegers<cxbyte>(*this, stmtPlace, linePtr);
2422            break;
2423        case ASMOP_AMD:
2424        case ASMOP_AMDCL2:
2425        case ASMOP_RAWCODE:
2426        case ASMOP_GALLIUM:
2427        case ASMOP_ROCM:
2428            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2429            {
2430                if (formatHandler!=nullptr)
2431                    printError(linePtr, "Output format type is already defined");
2432                else
2433                    format = (pseudoOp == ASMOP_GALLIUM) ? BinaryFormat::GALLIUM :
2434                        (pseudoOp == ASMOP_AMD) ? BinaryFormat::AMD :
2435                        (pseudoOp == ASMOP_AMDCL2) ? BinaryFormat::AMDCL2 :
2436                        (pseudoOp == ASMOP_ROCM) ? BinaryFormat::ROCM :
2437                        BinaryFormat::RAWCODE;
2438            }
2439            break;
2440        case ASMOP_CF_CALL:
2441            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2442                                  AsmCodeFlowType::CALL);
2443            break;
2444        case ASMOP_CF_CJUMP:
2445            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2446                                  AsmCodeFlowType::CJUMP);
2447            break;
2448        case ASMOP_CF_END:
2449            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2450                                  AsmCodeFlowType::END);
2451            break;
2452        case ASMOP_CF_JUMP:
2453            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2454                                  AsmCodeFlowType::JUMP);
2455            break;
2456        case ASMOP_CF_RET:
2457            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2458                                  AsmCodeFlowType::RETURN);
2459            break;
2460        case ASMOP_CF_START:
2461            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2462                                  AsmCodeFlowType::START);
2463            break;
2464        case ASMOP_DATA:
2465            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2466            break;
2467        case ASMOP_DOUBLE:
2468            AsmPseudoOps::putFloats<uint64_t>(*this, stmtPlace, linePtr);
2469            break;
2470        case ASMOP_ELSE:
2471            AsmPseudoOps::doElse(*this, stmtPlace, linePtr);
2472            break;
2473        case ASMOP_ELSEIF:
2474            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2475                      IfIntComp::NOT_EQUAL, true);
2476            break;
2477        case ASMOP_ELSEIF32:
2478            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, true, true);
2479            break;
2480        case ASMOP_ELSEIF64:
2481            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, false, true);
2482            break;
2483        case ASMOP_ELSEIFARCH:
2484            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, false, true);
2485            break;
2486        case ASMOP_ELSEIFB:
2487            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, false, true);
2488            break;
2489        case ASMOP_ELSEIFC:
2490            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, false, true);
2491            break;
2492        case ASMOP_ELSEIFDEF:
2493            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, false, true);
2494            break;
2495        case ASMOP_ELSEIFEQ:
2496            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2497                      IfIntComp::EQUAL, true);
2498            break;
2499        case ASMOP_ELSEIFEQS:
2500            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, false, true);
2501            break;
2502        case ASMOP_ELSEIFFMT:
2503            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, false, true);
2504            break;
2505        case ASMOP_ELSEIFGE:
2506            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2507                      IfIntComp::GREATER_EQUAL, true);
2508            break;
2509        case ASMOP_ELSEIFGPU:
2510            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, false, true);
2511            break;
2512        case ASMOP_ELSEIFGT:
2513            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2514                      IfIntComp::GREATER, true);
2515            break;
2516        case ASMOP_ELSEIFLE:
2517            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2518                      IfIntComp::LESS_EQUAL, true);
2519            break;
2520        case ASMOP_ELSEIFLT:
2521            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2522                      IfIntComp::LESS, true);
2523            break;
2524        case ASMOP_ELSEIFNARCH:
2525            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, true, true);
2526            break;
2527        case ASMOP_ELSEIFNB:
2528            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, true, true);
2529            break;
2530        case ASMOP_ELSEIFNC:
2531            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, true, true);
2532            break;
2533        case ASMOP_ELSEIFNOTDEF:
2534        case ASMOP_ELSEIFNDEF:
2535            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, true, true);
2536            break;
2537        case ASMOP_ELSEIFNE:
2538            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2539                      IfIntComp::NOT_EQUAL, true);
2540            break;
2541        case ASMOP_ELSEIFNES:
2542            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, true, true);
2543            break;
2544        case ASMOP_ELSEIFNFMT:
2545            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, true, true);
2546            break;
2547        case ASMOP_ELSEIFNGPU:
2548            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, true, true);
2549            break;
2550        case ASMOP_END:
2551            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2552                endOfAssembly = true;
2553            break;
2554        case ASMOP_ENDIF:
2555            AsmPseudoOps::endIf(*this, stmtPlace, linePtr);
2556            break;
2557        case ASMOP_ENDM:
2558        case ASMOP_ENDMACRO:
2559            AsmPseudoOps::endMacro(*this, stmtPlace, linePtr);
2560            break;
2561        case ASMOP_ENDR:
2562        case ASMOP_ENDREPT:
2563            AsmPseudoOps::endRepeat(*this, stmtPlace, linePtr);
2564            break;
2565        case ASMOP_ENDS:
2566        case ASMOP_ENDSCOPE:
2567            AsmPseudoOps::closeScope(*this, stmtPlace, linePtr);
2568            break;
2569        case ASMOP_ENUM:
2570            AsmPseudoOps::doEnum(*this, stmtPlace, linePtr);
2571            break;
2572        case ASMOP_EQU:
2573        case ASMOP_SET:
2574            AsmPseudoOps::setSymbol(*this, linePtr);
2575            break;
2576        case ASMOP_EQUIV:
2577            AsmPseudoOps::setSymbol(*this, linePtr, false);
2578            break;
2579        case ASMOP_EQV:
2580            AsmPseudoOps::setSymbol(*this, linePtr, false, true);
2581            break;
2582        case ASMOP_ERR:
2583            printError(stmtPlace, ".err encountered");
2584            break;
2585        case ASMOP_ERROR:
2586            AsmPseudoOps::doError(*this, stmtPlace, linePtr);
2587            break;
2588        case ASMOP_EXITM:
2589            AsmPseudoOps::exitMacro(*this, stmtPlace, linePtr);
2590            break;
2591        case ASMOP_EXTERN:
2592            AsmPseudoOps::ignoreExtern(*this, linePtr);
2593            break;
2594        case ASMOP_FAIL:
2595            AsmPseudoOps::doFail(*this, stmtPlace, linePtr);
2596            break;
2597        case ASMOP_FILE:
2598            printWarning(stmtPlace, "'.file' is ignored by this assembler.");
2599            break;
2600        case ASMOP_FILL:
2601            AsmPseudoOps::doFill(*this, stmtPlace, linePtr, false);
2602            break;
2603        case ASMOP_FILLQ:
2604            AsmPseudoOps::doFill(*this, stmtPlace, linePtr, true);
2605            break;
2606        case ASMOP_FLOAT:
2607            AsmPseudoOps::putFloats<uint32_t>(*this, stmtPlace, linePtr);
2608            break;
2609        case ASMOP_FOR:
2610            AsmPseudoOps::doFor(*this, stmtPlace, linePtr);
2611            break;
2612        case ASMOP_FORMAT:
2613            AsmPseudoOps::setOutFormat(*this, linePtr);
2614            break;
2615        case ASMOP_GET_64BIT:
2616            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::BIT64);
2617            break;
2618        case ASMOP_GET_ARCH:
2619            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::ARCH);
2620            break;
2621        case ASMOP_GET_FORMAT:
2622            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::FORMAT);
2623            break;
2624        case ASMOP_GET_GPU:
2625            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::GPU);
2626            break;
2627        case ASMOP_GET_VERSION:
2628            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::VERSION);
2629            break;
2630        case ASMOP_GLOBAL:
2631        case ASMOP_GLOBL:
2632            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_GLOBAL);
2633            break;
2634        case ASMOP_GPU:
2635            AsmPseudoOps::setGPUDevice(*this, linePtr);
2636            break;
2637        case ASMOP_HALF:
2638            AsmPseudoOps::putFloats<uint16_t>(*this, stmtPlace, linePtr);
2639            break;
2640        case ASMOP_HWORD:
2641            AsmPseudoOps::putIntegers<uint16_t>(*this, stmtPlace, linePtr);
2642            break;
2643        case ASMOP_IF:
2644            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2645                      IfIntComp::NOT_EQUAL, false);
2646            break;
2647        case ASMOP_IF32:
2648            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, true, false);
2649            break;
2650        case ASMOP_IF64:
2651            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, false, false);
2652            break;
2653        case ASMOP_IFARCH:
2654            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, false, false);
2655            break;
2656        case ASMOP_IFB:
2657            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, false, false);
2658            break;
2659        case ASMOP_IFC:
2660            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, false, false);
2661            break;
2662        case ASMOP_IFDEF:
2663            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, false, false);
2664            break;
2665        case ASMOP_IFEQ:
2666            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2667                      IfIntComp::EQUAL, false);
2668            break;
2669        case ASMOP_IFEQS:
2670            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, false, false);
2671            break;
2672        case ASMOP_IFFMT:
2673            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, false, false);
2674            break;
2675        case ASMOP_IFGE:
2676            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2677                      IfIntComp::GREATER_EQUAL, false);
2678            break;
2679        case ASMOP_IFGPU:
2680            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, false, false);
2681            break;
2682        case ASMOP_IFGT:
2683            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2684                      IfIntComp::GREATER, false);
2685            break;
2686        case ASMOP_IFLE:
2687            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2688                      IfIntComp::LESS_EQUAL, false);
2689            break;
2690        case ASMOP_IFLT:
2691            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2692                      IfIntComp::LESS, false);
2693            break;
2694        case ASMOP_IFNARCH:
2695            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, true, false);
2696            break;
2697        case ASMOP_IFNB:
2698            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, true, false);
2699            break;
2700        case ASMOP_IFNC:
2701            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, true, false);
2702            break;
2703        case ASMOP_IFNDEF:
2704        case ASMOP_IFNOTDEF:
2705            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, true, false);
2706            break;
2707        case ASMOP_IFNE:
2708            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2709                      IfIntComp::NOT_EQUAL, false);
2710            break;
2711        case ASMOP_IFNES:
2712            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, true, false);
2713            break;
2714        case ASMOP_IFNFMT:
2715            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, true, false);
2716            break;
2717        case ASMOP_IFNGPU:
2718            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, true, false);
2719            break;
2720        case ASMOP_INCBIN:
2721            AsmPseudoOps::includeBinFile(*this, stmtPlace, linePtr);
2722            break;
2723        case ASMOP_INCLUDE:
2724            AsmPseudoOps::includeFile(*this, stmtPlace, linePtr);
2725            break;
2726        case ASMOP_IRP:
2727            AsmPseudoOps::doIRP(*this, stmtPlace, linePtr, false);
2728            break;
2729        case ASMOP_IRPC:
2730            AsmPseudoOps::doIRP(*this, stmtPlace, linePtr, true);
2731            break;
2732        case ASMOP_INT:
2733        case ASMOP_LONG:
2734            AsmPseudoOps::putIntegers<uint32_t>(*this, stmtPlace, linePtr);
2735            break;
2736        case ASMOP_KERNEL:
2737            AsmPseudoOps::goToKernel(*this, stmtPlace, linePtr);
2738            break;
2739        case ASMOP_LFLAGS:
2740            printWarning(stmtPlace, "'.lflags' is ignored by this assembler.");
2741            break;
2742        case ASMOP_LINE:
2743        case ASMOP_LN:
2744            printWarning(stmtPlace, "'.line' is ignored by this assembler.");
2745            break;
2746        case ASMOP_LOCAL:
2747            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_LOCAL);
2748            break;
2749        case ASMOP_MACRO:
2750            AsmPseudoOps::doMacro(*this, stmtPlace, linePtr);
2751            break;
2752        case ASMOP_MACROCASE:
2753            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2754                macroCase = true;
2755            break;
2756        case ASMOP_MAIN:
2757            AsmPseudoOps::goToMain(*this, stmtPlace, linePtr);
2758            break;
2759        case ASMOP_NOALTMACRO:
2760            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2761                alternateMacro = false;
2762            break;
2763        case ASMOP_NOBUGGYFPLIT:
2764            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2765                buggyFPLit = false;
2766            break;
2767        case ASMOP_NOMACROCASE:
2768            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2769                macroCase = false;
2770            break;
2771        case ASMOP_NOOLDMODPARAM:
2772            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2773                oldModParam = false;
2774            break;
2775        case ASMOP_OCTA:
2776            AsmPseudoOps::putUInt128s(*this, stmtPlace, linePtr);
2777            break;
2778        case ASMOP_OFFSET:
2779            AsmPseudoOps::setAbsoluteOffset(*this, linePtr);
2780            break;
2781        case ASMOP_OLDMODPARAM:
2782            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2783                oldModParam = true;
2784            break;
2785        case ASMOP_ORG:
2786            AsmPseudoOps::doOrganize(*this, linePtr);
2787            break;
2788        case ASMOP_P2ALIGN:
2789            AsmPseudoOps::doAlign(*this, stmtPlace, linePtr, true);
2790            break;
2791        case ASMOP_PRINT:
2792            AsmPseudoOps::doPrint(*this, linePtr);
2793            break;
2794        case ASMOP_PURGEM:
2795            AsmPseudoOps::purgeMacro(*this, linePtr);
2796            break;
2797        case ASMOP_QUAD:
2798            AsmPseudoOps::putIntegers<uint64_t>(*this, stmtPlace, linePtr);
2799            break;
2800        case ASMOP_REGVAR:
2801            AsmPseudoOps::defRegVar(*this, linePtr);
2802            break;
2803        case ASMOP_REPT:
2804            AsmPseudoOps::doRepeat(*this, stmtPlace, linePtr);
2805            break;
2806        case ASMOP_RODATA:
2807            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2808            break;
2809        case ASMOP_SCOPE:
2810            AsmPseudoOps::openScope(*this, stmtPlace, linePtr);
2811            break;
2812        case ASMOP_SECTION:
2813            AsmPseudoOps::goToSection(*this, stmtPlace, linePtr);
2814            break;
2815        case ASMOP_SHORT:
2816            AsmPseudoOps::putIntegers<uint16_t>(*this, stmtPlace, linePtr);
2817            break;
2818        case ASMOP_SINGLE:
2819            AsmPseudoOps::putFloats<uint32_t>(*this, stmtPlace, linePtr);
2820            break;
2821        case ASMOP_SIZE:
2822            AsmPseudoOps::setSymbolSize(*this, linePtr);
2823            break;
2824        case ASMOP_SKIP:
2825        case ASMOP_SPACE:
2826            AsmPseudoOps::doSkip(*this, stmtPlace, linePtr);
2827            break;
2828        case ASMOP_STRING:
2829            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr, true);
2830            break;
2831        case ASMOP_STRING16:
2832            AsmPseudoOps::putStringsToInts<uint16_t>(*this, stmtPlace, linePtr);
2833            break;
2834        case ASMOP_STRING32:
2835            AsmPseudoOps::putStringsToInts<uint32_t>(*this, stmtPlace, linePtr);
2836            break;
2837        case ASMOP_STRING64:
2838            AsmPseudoOps::putStringsToInts<uint64_t>(*this, stmtPlace, linePtr);
2839            break;
2840        case ASMOP_STRUCT:
2841            AsmPseudoOps::setAbsoluteOffset(*this, linePtr);
2842            break;
2843        case ASMOP_TEXT:
2844            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2845            break;
2846        case ASMOP_SBTTL:
2847        case ASMOP_TITLE:
2848        case ASMOP_VERSION:
2849            AsmPseudoOps::ignoreString(*this, linePtr);
2850            break;
2851        case ASMOP_UNDEF:
2852            AsmPseudoOps::undefSymbol(*this, linePtr);
2853            break;
2854        case ASMOP_UNUSING:
2855            AsmPseudoOps::stopUsing(*this, linePtr);
2856            break;
2857        case ASMOP_USEREG:
2858            AsmPseudoOps::doUseReg(*this, linePtr);
2859            break;
2860        case ASMOP_USING:
2861            AsmPseudoOps::startUsing(*this, linePtr);
2862            break;
2863        case ASMOP_WARNING:
2864            AsmPseudoOps::doWarning(*this, stmtPlace, linePtr);
2865            break;
2866        case ASMOP_WEAK:
2867            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_WEAK);
2868            break;
2869        case ASMOP_WHILE:
2870            AsmPseudoOps::doWhile(*this, stmtPlace, linePtr);
2871            break;
2872        case ASMOP_WORD:
2873            AsmPseudoOps::putIntegers<uint32_t>(*this, stmtPlace, linePtr);
2874            break;
2875        default:
2876        {
2877            bool isGalliumPseudoOp = AsmGalliumPseudoOps::checkPseudoOpName(firstName);
2878            bool isAmdPseudoOp = AsmAmdPseudoOps::checkPseudoOpName(firstName);
2879            bool isAmdCL2PseudoOp = AsmAmdCL2PseudoOps::checkPseudoOpName(firstName);
2880            bool isROCmPseudoOp = AsmROCmPseudoOps::checkPseudoOpName(firstName);
2881            if (isGalliumPseudoOp || isAmdPseudoOp || isAmdCL2PseudoOp || isROCmPseudoOp)
2882            {
2883                // initialize only if gallium pseudo-op or AMD pseudo-op
2884                initializeOutputFormat();
2885                /// try to parse
2886                if (!formatHandler->parsePseudoOp(firstName, stmtPlace, linePtr))
2887                {
2888                    // check other
2889                    if (format != BinaryFormat::GALLIUM)
2890                    {
2891                        // check gallium pseudo-op
2892                        if (isGalliumPseudoOp)
2893                        {
2894                            printError(stmtPlace, "Gallium pseudo-op can be defined "
2895                                    "only in Gallium format code");
2896                            break;
2897                        }
2898                    }
2899                    if (format != BinaryFormat::AMD)
2900                    {
2901                        // check amd pseudo-op
2902                        if (isAmdPseudoOp)
2903                        {
2904                            printError(stmtPlace, "AMD pseudo-op can be defined only in "
2905                                    "AMD format code");
2906                            break;
2907                        }
2908                    }
2909                    if (format != BinaryFormat::AMDCL2)
2910                    {
2911                        // check amd pseudo-op
2912                        if (isAmdCL2PseudoOp)
2913                        {
2914                            printError(stmtPlace, "AMDCL2 pseudo-op can be defined only in "
2915                                    "AMDCL2 format code");
2916                            break;
2917                        }
2918                    }
2919                    if (format != BinaryFormat::ROCM)
2920                    {
2921                        // check rocm pseudo-op
2922                        if (isROCmPseudoOp)
2923                        {
2924                            printError(stmtPlace, "ROCm pseudo-op can be defined "
2925                                    "only in ROCm format code");
2926                            break;
2927                        }
2928                    }
2929                }
2930            }
2931            else if (makeMacroSubstitution(stmtPlace) == ParseState::MISSING)
2932                printError(stmtPlace, "This is neither pseudo-op and nor macro");
2933            break;
2934        }
2935    }
2936}
2937
2938/* skipping clauses */
2939bool Assembler::skipClauses(bool exitm)
2940{
2941    const cxuint clauseLevel = clauses.size();
2942    AsmClauseType topClause = (!clauses.empty()) ? clauses.top().type :
2943            AsmClauseType::IF;
2944    const bool isTopIfClause = (topClause == AsmClauseType::IF ||
2945            topClause == AsmClauseType::ELSEIF || topClause == AsmClauseType::ELSE);
2946    bool good = true;
2947    const size_t inputFilterTop = asmInputFilters.size();
2948    while (exitm || clauses.size() >= clauseLevel)
2949    {
2950        if (!readLine())
2951            break;
2952        // if exit from macro mode, exit when macro filter exits
2953        if (exitm && inputFilterTop > asmInputFilters.size())
2954        {
2955            // set lineAlreadyRead - next line after skipped region read will be read
2956            lineAlreadyRead  = true;
2957            break; // end of macro,
2958        }
2959       
2960        const char* linePtr = line;
2961        const char* end = line+lineSize;
2962        skipSpacesAndLabels(linePtr, end);
2963        const char* stmtPlace = linePtr;
2964        if (linePtr == end || *linePtr != '.')
2965            continue;
2966       
2967        CString pseudoOpName = extractSymName(linePtr, end, false);
2968        toLowerString(pseudoOpName);
2969       
2970        const size_t pseudoOp = binaryFind(offlinePseudoOpNamesTbl,
2971               offlinePseudoOpNamesTbl + sizeof(offlinePseudoOpNamesTbl)/sizeof(char*),
2972               pseudoOpName.c_str()+1, CStringLess()) - offlinePseudoOpNamesTbl;
2973       
2974        // any conditional inside macro or repeat will be ignored
2975        bool insideMacroOrRepeat = !clauses.empty() && 
2976            (clauses.top().type == AsmClauseType::MACRO ||
2977                    clauses.top().type == AsmClauseType::REPEAT);
2978        switch(pseudoOp)
2979        {
2980            case ASMCOP_ENDIF:
2981                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2982                    good = false;   // if endif have garbages
2983                else if (!insideMacroOrRepeat)
2984                    if (!popClause(stmtPlace, AsmClauseType::IF))
2985                        good = false;
2986                break;
2987            case ASMCOP_ENDM:
2988            case ASMCOP_ENDMACRO:
2989                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2990                    good = false;   // if .endm have garbages
2991                else if (!popClause(stmtPlace, AsmClauseType::MACRO))
2992                    good = false;
2993                break;
2994            case ASMCOP_ENDR:
2995            case ASMCOP_ENDREPT:
2996                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2997                    good = false;   // if .endr have garbages
2998                else if (!popClause(stmtPlace, AsmClauseType::REPEAT))
2999                    good = false;
3000                break;
3001            case ASMCOP_ELSE:
3002            case ASMCOP_ELSEIFARCH:
3003            case ASMCOP_ELSEIF:
3004            case ASMCOP_ELSEIF32:
3005            case ASMCOP_ELSEIF64:
3006            case ASMCOP_ELSEIFB:
3007            case ASMCOP_ELSEIFC:
3008            case ASMCOP_ELSEIFDEF:
3009            case ASMCOP_ELSEIFEQ:
3010            case ASMCOP_ELSEIFEQS:
3011            case ASMCOP_ELSEIFFMT:
3012            case ASMCOP_ELSEIFGE:
3013            case ASMCOP_ELSEIFGPU:
3014            case ASMCOP_ELSEIFGT:
3015            case ASMCOP_ELSEIFLE:
3016            case ASMCOP_ELSEIFLT:
3017            case ASMCOP_ELSEIFNARCH:
3018            case ASMCOP_ELSEIFNB:
3019            case ASMCOP_ELSEIFNC:
3020            case ASMCOP_ELSEIFNDEF:
3021            case ASMCOP_ELSEIFNE:
3022            case ASMCOP_ELSEIFNES:
3023            case ASMCOP_ELSEIFNFMT:
3024            case ASMCOP_ELSEIFNGPU:
3025            case ASMCOP_ELSEIFNOTDEF:
3026                if (pseudoOp == ASMCOP_ELSE &&
3027                            !AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
3028                    good = false; // if .else have garbages
3029                else if (!insideMacroOrRepeat)
3030                {
3031                    if (!exitm && clauseLevel == clauses.size() && isTopIfClause)
3032                    {
3033                        /* set lineAlreadyRead - next line after skipped region read
3034                         * will be read */
3035                        lineAlreadyRead = true; // read
3036                        return good; // do exit
3037                    }
3038                    if (!pushClause(stmtPlace, (pseudoOp==ASMCOP_ELSE ?
3039                                AsmClauseType::ELSE : AsmClauseType::ELSEIF)))
3040                        good = false;
3041                }
3042                break;
3043            case ASMCOP_IF:
3044            case ASMCOP_IFARCH:
3045            case ASMCOP_IF32:
3046            case ASMCOP_IF64:
3047            case ASMCOP_IFB:
3048            case ASMCOP_IFC:
3049            case ASMCOP_IFDEF:
3050            case ASMCOP_IFEQ:
3051            case ASMCOP_IFEQS:
3052            case ASMCOP_IFFMT:
3053            case ASMCOP_IFGE:
3054            case ASMCOP_IFGPU:
3055            case ASMCOP_IFGT:
3056            case ASMCOP_IFLE:
3057            case ASMCOP_IFLT:
3058            case ASMCOP_IFNARCH:
3059            case ASMCOP_IFNB:
3060            case ASMCOP_IFNC:
3061            case ASMCOP_IFNDEF:
3062            case ASMCOP_IFNE:
3063            case ASMCOP_IFNES:
3064            case ASMCOP_IFNFMT:
3065            case ASMCOP_IFNGPU:
3066            case ASMCOP_IFNOTDEF:
3067                if (!insideMacroOrRepeat)
3068                {
3069                    if (!pushClause(stmtPlace, AsmClauseType::IF))
3070                        good = false;
3071                }
3072                break;
3073            case ASMCOP_MACRO:
3074                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
3075                    good = false;
3076                break;
3077            case ASMCOP_IRP:
3078            case ASMCOP_IRPC:
3079            case ASMCOP_REPT:
3080            case ASMCOP_FOR:
3081            case ASMCOP_WHILE:
3082                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
3083                    good = false;
3084                break;
3085            default:
3086                break;
3087        }
3088    }
3089    return good;
3090}
3091
3092bool Assembler::putMacroContent(RefPtr<AsmMacro> macro)
3093{
3094    const cxuint clauseLevel = clauses.size();
3095    bool good = true;
3096    while (clauses.size() >= clauseLevel)
3097    {
3098        if (!readLine())
3099        {
3100            // error, must be finished in by .endm or .endmacro
3101            good = false;
3102            break;
3103        }
3104       
3105        const char* linePtr = line;
3106        const char* end = line+lineSize;
3107        skipSpacesAndLabels(linePtr, end);
3108        const char* stmtPlace = linePtr;
3109        // if not pseudo-op
3110        if (linePtr == end || *linePtr != '.')
3111        {
3112            macro->addLine(currentInputFilter->getMacroSubst(),
3113                  currentInputFilter->getSource(),
3114                  currentInputFilter->getColTranslations(), lineSize, line);
3115            continue;
3116        }
3117       
3118        CString pseudoOpName = extractSymName(linePtr, end, false);
3119        toLowerString(pseudoOpName);
3120       
3121        const size_t pseudoOp = binaryFind(macroRepeatPseudoOpNamesTbl,
3122               macroRepeatPseudoOpNamesTbl + sizeof(macroRepeatPseudoOpNamesTbl) /
3123               sizeof(char*), pseudoOpName.c_str()+1, CStringLess()) -
3124               macroRepeatPseudoOpNamesTbl;
3125        // handle pseudo-op in macro content
3126        switch(pseudoOp)
3127        {
3128            case ASMMROP_ENDM:
3129            case ASMMROP_ENDMACRO:
3130                if (!popClause(stmtPlace, AsmClauseType::MACRO))
3131                    good = false;
3132                break;
3133            case ASMMROP_ENDR:
3134            case ASMMROP_ENDREPT:
3135                if (!popClause(stmtPlace, AsmClauseType::REPEAT))
3136                    good = false;
3137                break;
3138            case ASMMROP_MACRO:
3139                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
3140                    good = false;
3141                break;
3142            case ASMMROP_IRP:
3143            case ASMMROP_IRPC:
3144            case ASMMROP_REPT:
3145            case ASMMROP_FOR:
3146            case ASMMROP_WHILE:
3147                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
3148                    good = false;
3149                break;
3150            default:
3151                break;
3152        }
3153        if (pseudoOp != ASMMROP_ENDM || clauses.size() >= clauseLevel)
3154            // add line if is still in macro
3155            macro->addLine(currentInputFilter->getMacroSubst(),
3156                  currentInputFilter->getSource(),
3157                  currentInputFilter->getColTranslations(), lineSize, line);
3158    }
3159    return good;
3160}
3161
3162bool Assembler::putRepetitionContent(AsmRepeat& repeat)
3163{
3164    const cxuint clauseLevel = clauses.size();
3165    bool good = true;
3166    while (clauses.size() >= clauseLevel)
3167    {
3168        if (!readLine())
3169        {
3170            // error, must be finished in by .endm or .endmacro
3171            good = false;
3172            break;
3173        }
3174       
3175        const char* linePtr = line;
3176        const char* end = line+lineSize;
3177        skipSpacesAndLabels(linePtr, end);
3178        const char* stmtPlace = linePtr;
3179        // if not pseudo-op
3180        if (linePtr == end || *linePtr != '.')
3181        {
3182            repeat.addLine(currentInputFilter->getMacroSubst(),
3183               currentInputFilter->getSource(), currentInputFilter->getColTranslations(),
3184               lineSize, line);
3185            continue;
3186        }
3187       
3188        CString pseudoOpName = extractSymName(linePtr, end, false);
3189        toLowerString(pseudoOpName);
3190        const size_t pseudoOp = binaryFind(macroRepeatPseudoOpNamesTbl,
3191               macroRepeatPseudoOpNamesTbl + sizeof(macroRepeatPseudoOpNamesTbl) /
3192               sizeof(char*), pseudoOpName.c_str()+1, CStringLess()) -
3193               macroRepeatPseudoOpNamesTbl;
3194        // handle pseudo-op in macro content
3195        switch(pseudoOp)
3196        {
3197            case ASMMROP_ENDM:
3198                if (!popClause(stmtPlace, AsmClauseType::MACRO))
3199                    good = false;
3200                break;
3201            case ASMMROP_ENDR:
3202                if (!popClause(stmtPlace, AsmClauseType::REPEAT))
3203                    good = false;
3204                break;
3205            case ASMMROP_MACRO:
3206                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
3207                    good = false;
3208                break;
3209            case ASMMROP_IRP:
3210            case ASMMROP_IRPC:
3211            case ASMMROP_REPT:
3212            case ASMMROP_FOR:
3213            case ASMMROP_WHILE:
3214                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
3215                    good = false;
3216                break;
3217            default:
3218                break;
3219        }
3220        if (pseudoOp != ASMMROP_ENDR || clauses.size() >= clauseLevel)
3221            // add line if is still in repetition
3222            repeat.addLine(currentInputFilter->getMacroSubst(),
3223                   currentInputFilter->getSource(),
3224                   currentInputFilter->getColTranslations(), lineSize, line);
3225    }
3226    return good;
3227}
Note: See TracBrowser for help on using the repository browser.