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

Last change on this file since 3787 was 3787, checked in by matszpk, 14 months ago

CLRadeonExtender: Asm: Evaluate old expression of symbol if this symbol was undefined.

File size: 114.2 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    "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_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* pseudoOpPlace,
2052                    const char* linePtr)
2053{
2054    const char* end = asmr.line+asmr.lineSize;
2055    skipSpacesToEnd(linePtr, end);
2056    const char* scopePathPlace = linePtr;
2057    CString scopePath = extractScopedSymName(linePtr, end);
2058    bool good = true;
2059    if (scopePath.empty() || scopePath == "::")
2060        ASM_NOTGOOD_BY_ERROR(scopePathPlace, "Expected scope path")
2061    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2062        return;
2063    AsmScope* scope = asmr.getRecurScope(scopePath);
2064    // do add this
2065    asmr.currentScope->startUsingScope(scope);
2066}
2067
2068void AsmPseudoOps::doUseReg(Assembler& asmr, const char* pseudoOpPlace,
2069                    const char* linePtr)
2070{
2071    const char* end = asmr.line+asmr.lineSize;
2072    asmr.initializeOutputFormat();
2073   
2074    do {
2075        skipSpacesToEnd(linePtr, end);
2076        bool good = true;
2077        cxuint regStart, regEnd;
2078        const AsmRegVar* regVar;
2079        good = asmr.isaAssembler->parseRegisterRange(linePtr, regStart, regEnd, regVar);
2080        skipSpacesToEnd(linePtr, end);
2081        if (linePtr==end || *linePtr!=':')
2082        {
2083            asmr.printError(linePtr, "Expected colon after register");
2084            continue;
2085        }
2086        skipCharAndSpacesToEnd(linePtr, end);
2087       
2088        cxbyte rwFlags = 0;
2089        // parse read/write flags (r,w,rw)
2090        for (; linePtr != end; linePtr++)
2091        {
2092            char c = toLower(*linePtr);
2093            if (c!='r' && c!='w')
2094                break;
2095            rwFlags |= (c=='r') ? ASMRVU_READ : ASMRVU_WRITE;
2096        }
2097        if (rwFlags==0) // not parsed
2098        {
2099            asmr.printError(linePtr, "Expected access mask");
2100            continue;
2101        }
2102       
2103        if (good) // if good
2104        {
2105            // create usageHandler if needed
2106            if (asmr.sections[asmr.currentSection].usageHandler == nullptr)
2107                    asmr.sections[asmr.currentSection].usageHandler.reset(
2108                            asmr.isaAssembler->createUsageHandler(
2109                                    asmr.sections[asmr.currentSection].content));
2110            // put regVar usage
2111            asmr.sections[asmr.currentSection].usageHandler->pushUseRegUsage(
2112                AsmRegVarUsage{ size_t(asmr.currentOutPos), regVar,
2113                    uint16_t(regStart), uint16_t(regEnd), ASMFIELD_NONE, rwFlags, 0 });
2114        }
2115       
2116    } while(skipCommaForMultipleArgs(asmr, linePtr));
2117   
2118    checkGarbagesAtEnd(asmr, linePtr);
2119}
2120
2121void AsmPseudoOps::stopUsing(Assembler& asmr, const char* pseudoOpPlace,
2122                    const char* linePtr)
2123{
2124    const char* end = asmr.line+asmr.lineSize;
2125    skipSpacesToEnd(linePtr, end);
2126    const char* scopePathPlace = linePtr;
2127    CString scopePath = extractScopedSymName(linePtr, end);
2128    bool good = true;
2129    if (scopePath == "::")
2130        ASM_NOTGOOD_BY_ERROR(scopePathPlace, "Expected scope path")
2131    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2132        return;
2133    AsmScope* scope = asmr.getRecurScope(scopePath);
2134    if (!scopePath.empty())
2135        asmr.currentScope->stopUsingScope(scope);
2136    else // stop using all scopes
2137        asmr.currentScope->stopUsingScopes();
2138}
2139
2140void AsmPseudoOps::undefSymbol(Assembler& asmr, const char* linePtr)
2141{
2142    const char* end = asmr.line+asmr.lineSize;
2143    skipSpacesToEnd(linePtr, end);
2144    const char* symNamePlace = linePtr;
2145    CString symName = extractScopedSymName(linePtr, end, false);
2146    bool good = true;
2147    if (symName.empty())
2148        ASM_NOTGOOD_BY_ERROR(symNamePlace, "Expected symbol name")
2149    // symbol '.' can not be undefined
2150    else if (symName == ".")
2151        ASM_NOTGOOD_BY_ERROR(symNamePlace, "Symbol '.' can not be undefined")
2152    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2153        return;
2154   
2155    CString sameSymName;
2156    AsmScope* outScope;
2157    AsmSymbolEntry* it = asmr.findSymbolInScope(symName, outScope, sameSymName);
2158    if (it == nullptr || !it->second.isDefined())
2159        asmr.printWarning(symNamePlace, (std::string("Symbol '") + symName.c_str() +
2160                "' already doesn't exist").c_str());
2161    else // always undefine (do not remove, due to .eqv evaluation)
2162        asmr.undefineSymbol(*it);
2163}
2164
2165void AsmPseudoOps::setAbsoluteOffset(Assembler& asmr, const char* linePtr)
2166{
2167    const char* end = asmr.line+asmr.lineSize;
2168    asmr.initializeOutputFormat();
2169    skipSpacesToEnd(linePtr, end);
2170    uint64_t value = 0;
2171    bool good = getAbsoluteValueArg(asmr, value, linePtr, true);
2172    if (!good || !checkGarbagesAtEnd(asmr, linePtr))
2173        return;
2174    asmr.currentSection = ASMSECT_ABS;
2175    asmr.currentOutPos = value;
2176}
2177
2178void AsmPseudoOps::defRegVar(Assembler& asmr, const char* pseudoOpPlace,
2179                       const char* linePtr)
2180{
2181    const char* end = asmr.line+asmr.lineSize;
2182    asmr.initializeOutputFormat();
2183   
2184    do {
2185        skipSpacesToEnd(linePtr, end);
2186        const char* regNamePlace = linePtr;
2187        CString name = extractScopedSymName(linePtr, end, false);
2188        bool good = true;
2189        if (name.empty())
2190            ASM_NOTGOOD_BY_ERROR(regNamePlace, "Expected reg-var name")
2191        skipSpacesToEnd(linePtr, end);
2192        if (linePtr==end || *linePtr!=':')
2193        {
2194            asmr.printError(linePtr, "Expected colon after reg-var");
2195            continue;
2196        }
2197        skipCharAndSpacesToEnd(linePtr, end);
2198        AsmRegVar var = { 0, 1 };
2199        if (!asmr.isaAssembler->parseRegisterType(linePtr, end, var.type))
2200            ASM_NOTGOOD_BY_ERROR(linePtr, "Expected name of register type")
2201        skipSpacesToEnd(linePtr, end);
2202       
2203        if (linePtr!=end && *linePtr!=',')
2204        {
2205            if (*linePtr!=':')
2206            {
2207                asmr.printError(linePtr, "Expected colon after reg-var");
2208                continue;
2209            }
2210            linePtr++;
2211            skipSpacesToEnd(linePtr, end);
2212            uint64_t regSize;
2213            if (!getAbsoluteValueArg(asmr, regSize, linePtr, true))
2214                continue;
2215            if (regSize==0)
2216                ASM_NOTGOOD_BY_ERROR(linePtr, "Size of reg-var is zero")
2217            if (regSize>UINT16_MAX)
2218                ASM_NOTGOOD_BY_ERROR(linePtr, "Size of reg-var out of range")
2219            var.size = regSize;
2220        }
2221       
2222        if (!good)
2223            continue;
2224       
2225        if (!asmr.addRegVar(name, var))
2226            asmr.printError(regNamePlace, (std::string("Reg-var '")+name.c_str()+
2227                        "' was already defined").c_str());
2228       
2229    } while(skipCommaForMultipleArgs(asmr, linePtr));
2230   
2231    checkGarbagesAtEnd(asmr, linePtr);
2232}
2233
2234void AsmPseudoOps::addCodeFlowEntries(Assembler& asmr, const char* pseudoOpPlace,
2235                     const char* linePtr, AsmCodeFlowType type)
2236{
2237    const bool acceptArgs = (type==AsmCodeFlowType::JUMP || type==AsmCodeFlowType::CJUMP ||
2238            type==AsmCodeFlowType::CALL);
2239    asmr.initializeOutputFormat();
2240   
2241    if (asmr.currentSection==ASMSECT_ABS ||
2242        asmr.sections[asmr.currentSection].type != AsmSectionType::CODE)
2243        PSEUDOOP_RETURN_BY_ERROR("Defining codeflow in non-code section is illegal")
2244   
2245    const char* end = asmr.line+asmr.lineSize;
2246    if (acceptArgs)
2247    {
2248        // multiple entries
2249        do {
2250            bool good = true;
2251            skipSpacesToEnd(linePtr, end);
2252            if (!good)
2253                continue;
2254            std::unique_ptr<AsmExpression> expr;
2255            uint64_t target;
2256            if (!getJumpValueArg(asmr, target, expr, linePtr))
2257                continue;
2258            asmr.sections[asmr.currentSection].addCodeFlowEntry({ 
2259                    size_t(asmr.currentOutPos), size_t(target), type });
2260            if (expr)
2261                expr->setTarget(AsmExprTarget::codeFlowTarget(asmr.currentSection,
2262                        asmr.sections[asmr.currentSection].codeFlow.size()-1));
2263            expr.release();
2264        } while (skipCommaForMultipleArgs(asmr, linePtr));
2265    }
2266    else // single entry without target
2267        asmr.sections[asmr.currentSection].addCodeFlowEntry({ 
2268                    size_t(asmr.currentOutPos), 0, type });
2269   
2270    checkGarbagesAtEnd(asmr, linePtr);
2271}
2272
2273// get predefine value ('.get_64bit', '.get_arch', '.get_format')
2274void AsmPseudoOps::getPredefinedValue(Assembler& asmr, const char* linePtr,
2275                            AsmPredefined predefined)
2276{
2277    cxuint predefValue = 0;
2278    // we must initialize output format before getting any arch, gpu or format
2279    // must be set before
2280    asmr.initializeOutputFormat();
2281    switch (predefined)
2282    {
2283        case AsmPredefined::ARCH:
2284            predefValue = cxuint(getGPUArchitectureFromDeviceType(asmr.deviceType));
2285            break;
2286        case AsmPredefined::BIT64:
2287            predefValue = asmr._64bit;
2288            break;
2289        case AsmPredefined::GPU:
2290            predefValue = cxuint(asmr.deviceType);
2291            break;
2292        case AsmPredefined::FORMAT:
2293            predefValue = cxuint(asmr.format);
2294            break;
2295        case AsmPredefined::VERSION:
2296            predefValue = CLRX_MAJOR_VERSION*10000U + CLRX_MINOR_VERSION*100U +
2297                    CLRX_MICRO_VERSION;
2298            break;
2299        default:
2300            break;
2301    }
2302    AsmParseUtils::setSymbolValue(asmr, linePtr, predefValue, ASMSECT_ABS);
2303}
2304
2305void AsmPseudoOps::ignoreString(Assembler& asmr, const char* linePtr)
2306{
2307    const char* end = asmr.line+asmr.lineSize;
2308    skipSpacesToEnd(linePtr, end);
2309    std::string out;
2310    if (asmr.parseString(out, linePtr))
2311        checkGarbagesAtEnd(asmr, linePtr);
2312}
2313
2314// checking whether name is pseudo-op name
2315// (checking any extra pseudo-op provided by format handler)
2316bool AsmPseudoOps::checkPseudoOpName(const CString& string)
2317{
2318    if (string.empty() || string[0] != '.')
2319        return false;
2320    const size_t pseudoOp = binaryFind(pseudoOpNamesTbl, pseudoOpNamesTbl +
2321                    sizeof(pseudoOpNamesTbl)/sizeof(char*), string.c_str()+1,
2322                   CStringLess()) - pseudoOpNamesTbl;
2323    if (pseudoOp < sizeof(pseudoOpNamesTbl)/sizeof(char*))
2324        return true;
2325    if (AsmGalliumPseudoOps::checkPseudoOpName(string))
2326        return true;
2327    if (AsmAmdPseudoOps::checkPseudoOpName(string))
2328        return true;
2329    if (AsmAmdCL2PseudoOps::checkPseudoOpName(string))
2330        return true;
2331    if (AsmROCmPseudoOps::checkPseudoOpName(string))
2332        return true;
2333    return false;
2334}
2335
2336};
2337
2338void Assembler::parsePseudoOps(const CString& firstName,
2339       const char* stmtPlace, const char* linePtr)
2340{
2341    const size_t pseudoOp = binaryFind(pseudoOpNamesTbl, pseudoOpNamesTbl +
2342                    sizeof(pseudoOpNamesTbl)/sizeof(char*), firstName.c_str()+1,
2343                   CStringLess()) - pseudoOpNamesTbl;
2344   
2345    switch(pseudoOp)
2346    {
2347        case ASMOP_32BIT:
2348        case ASMOP_64BIT:
2349            AsmPseudoOps::setBitness(*this, linePtr, pseudoOp == ASMOP_64BIT);
2350            break;
2351        case ASMOP_ABORT:
2352            printError(stmtPlace, "Aborted!");
2353            endOfAssembly = true;
2354            break;
2355        case ASMOP_ALIGN:
2356        case ASMOP_BALIGN:
2357            AsmPseudoOps::doAlign(*this, stmtPlace, linePtr);
2358            break;
2359        case ASMOP_ALTMACRO:
2360            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2361                alternateMacro = true;
2362            break;
2363        case ASMOP_ARCH:
2364            AsmPseudoOps::setGPUArchitecture(*this, linePtr);
2365            break;
2366        case ASMOP_ASCII:
2367            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr);
2368            break;
2369        case ASMOP_ASCIZ:
2370            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr, true);
2371            break;
2372        case ASMOP_BALIGNL:
2373            AsmPseudoOps::doAlignWord<uint32_t>(*this, stmtPlace, linePtr);
2374            break;
2375        case ASMOP_BALIGNW:
2376            AsmPseudoOps::doAlignWord<uint16_t>(*this, stmtPlace, linePtr);
2377            break;
2378        case ASMOP_BUGGYFPLIT:
2379            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2380                buggyFPLit = true;
2381            break;
2382        case ASMOP_BYTE:
2383            AsmPseudoOps::putIntegers<cxbyte>(*this, stmtPlace, linePtr);
2384            break;
2385        case ASMOP_AMD:
2386        case ASMOP_AMDCL2:
2387        case ASMOP_RAWCODE:
2388        case ASMOP_GALLIUM:
2389        case ASMOP_ROCM:
2390            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2391            {
2392                if (formatHandler!=nullptr)
2393                    printError(linePtr, "Output format type is already defined");
2394                else
2395                    format = (pseudoOp == ASMOP_GALLIUM) ? BinaryFormat::GALLIUM :
2396                        (pseudoOp == ASMOP_AMD) ? BinaryFormat::AMD :
2397                        (pseudoOp == ASMOP_AMDCL2) ? BinaryFormat::AMDCL2 :
2398                        (pseudoOp == ASMOP_ROCM) ? BinaryFormat::ROCM :
2399                        BinaryFormat::RAWCODE;
2400            }
2401            break;
2402        case ASMOP_CF_CALL:
2403            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2404                                  AsmCodeFlowType::CALL);
2405            break;
2406        case ASMOP_CF_CJUMP:
2407            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2408                                  AsmCodeFlowType::CJUMP);
2409            break;
2410        case ASMOP_CF_END:
2411            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2412                                  AsmCodeFlowType::END);
2413            break;
2414        case ASMOP_CF_JUMP:
2415            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2416                                  AsmCodeFlowType::JUMP);
2417            break;
2418        case ASMOP_CF_RET:
2419            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2420                                  AsmCodeFlowType::RETURN);
2421            break;
2422        case ASMOP_CF_START:
2423            AsmPseudoOps::addCodeFlowEntries(*this, stmtPlace, linePtr,
2424                                  AsmCodeFlowType::START);
2425            break;
2426        case ASMOP_DATA:
2427            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2428            break;
2429        case ASMOP_DOUBLE:
2430            AsmPseudoOps::putFloats<uint64_t>(*this, stmtPlace, linePtr);
2431            break;
2432        case ASMOP_ELSE:
2433            AsmPseudoOps::doElse(*this, stmtPlace, linePtr);
2434            break;
2435        case ASMOP_ELSEIF:
2436            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2437                      IfIntComp::NOT_EQUAL, true);
2438            break;
2439        case ASMOP_ELSEIF32:
2440            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, true, true);
2441            break;
2442        case ASMOP_ELSEIF64:
2443            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, false, true);
2444            break;
2445        case ASMOP_ELSEIFARCH:
2446            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, false, true);
2447            break;
2448        case ASMOP_ELSEIFB:
2449            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, false, true);
2450            break;
2451        case ASMOP_ELSEIFC:
2452            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, false, true);
2453            break;
2454        case ASMOP_ELSEIFDEF:
2455            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, false, true);
2456            break;
2457        case ASMOP_ELSEIFEQ:
2458            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2459                      IfIntComp::EQUAL, true);
2460            break;
2461        case ASMOP_ELSEIFEQS:
2462            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, false, true);
2463            break;
2464        case ASMOP_ELSEIFFMT:
2465            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, false, true);
2466            break;
2467        case ASMOP_ELSEIFGE:
2468            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2469                      IfIntComp::GREATER_EQUAL, true);
2470            break;
2471        case ASMOP_ELSEIFGPU:
2472            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, false, true);
2473            break;
2474        case ASMOP_ELSEIFGT:
2475            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2476                      IfIntComp::GREATER, true);
2477            break;
2478        case ASMOP_ELSEIFLE:
2479            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2480                      IfIntComp::LESS_EQUAL, true);
2481            break;
2482        case ASMOP_ELSEIFLT:
2483            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2484                      IfIntComp::LESS, true);
2485            break;
2486        case ASMOP_ELSEIFNARCH:
2487            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, true, true);
2488            break;
2489        case ASMOP_ELSEIFNB:
2490            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, true, true);
2491            break;
2492        case ASMOP_ELSEIFNC:
2493            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, true, true);
2494            break;
2495        case ASMOP_ELSEIFNOTDEF:
2496        case ASMOP_ELSEIFNDEF:
2497            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, true, true);
2498            break;
2499        case ASMOP_ELSEIFNE:
2500            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2501                      IfIntComp::NOT_EQUAL, true);
2502            break;
2503        case ASMOP_ELSEIFNES:
2504            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, true, true);
2505            break;
2506        case ASMOP_ELSEIFNFMT:
2507            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, true, true);
2508            break;
2509        case ASMOP_ELSEIFNGPU:
2510            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, true, true);
2511            break;
2512        case ASMOP_END:
2513            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2514                endOfAssembly = true;
2515            break;
2516        case ASMOP_ENDIF:
2517            AsmPseudoOps::endIf(*this, stmtPlace, linePtr);
2518            break;
2519        case ASMOP_ENDM:
2520        case ASMOP_ENDMACRO:
2521            AsmPseudoOps::endMacro(*this, stmtPlace, linePtr);
2522            break;
2523        case ASMOP_ENDR:
2524        case ASMOP_ENDREPT:
2525            AsmPseudoOps::endRepeat(*this, stmtPlace, linePtr);
2526            break;
2527        case ASMOP_ENDS:
2528        case ASMOP_ENDSCOPE:
2529            AsmPseudoOps::closeScope(*this, stmtPlace, linePtr);
2530            break;
2531            break;
2532        case ASMOP_EQU:
2533        case ASMOP_SET:
2534            AsmPseudoOps::setSymbol(*this, linePtr);
2535            break;
2536        case ASMOP_EQUIV:
2537            AsmPseudoOps::setSymbol(*this, linePtr, false);
2538            break;
2539        case ASMOP_EQV:
2540            AsmPseudoOps::setSymbol(*this, linePtr, false, true);
2541            break;
2542        case ASMOP_ERR:
2543            printError(stmtPlace, ".err encountered");
2544            break;
2545        case ASMOP_ERROR:
2546            AsmPseudoOps::doError(*this, stmtPlace, linePtr);
2547            break;
2548        case ASMOP_EXITM:
2549            AsmPseudoOps::exitMacro(*this, stmtPlace, linePtr);
2550            break;
2551        case ASMOP_EXTERN:
2552            AsmPseudoOps::ignoreExtern(*this, linePtr);
2553            break;
2554        case ASMOP_FAIL:
2555            AsmPseudoOps::doFail(*this, stmtPlace, linePtr);
2556            break;
2557        case ASMOP_FILE:
2558            printWarning(stmtPlace, "'.file' is ignored by this assembler.");
2559            break;
2560        case ASMOP_FILL:
2561            AsmPseudoOps::doFill(*this, stmtPlace, linePtr, false);
2562            break;
2563        case ASMOP_FILLQ:
2564            AsmPseudoOps::doFill(*this, stmtPlace, linePtr, true);
2565            break;
2566        case ASMOP_FLOAT:
2567            AsmPseudoOps::putFloats<uint32_t>(*this, stmtPlace, linePtr);
2568            break;
2569        case ASMOP_FOR:
2570            AsmPseudoOps::doFor(*this, stmtPlace, linePtr);
2571            break;
2572        case ASMOP_FORMAT:
2573            AsmPseudoOps::setOutFormat(*this, linePtr);
2574            break;
2575        case ASMOP_GET_64BIT:
2576            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::BIT64);
2577            break;
2578        case ASMOP_GET_ARCH:
2579            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::ARCH);
2580            break;
2581        case ASMOP_GET_FORMAT:
2582            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::FORMAT);
2583            break;
2584        case ASMOP_GET_GPU:
2585            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::GPU);
2586            break;
2587        case ASMOP_GET_VERSION:
2588            AsmPseudoOps::getPredefinedValue(*this, linePtr, AsmPredefined::VERSION);
2589            break;
2590        case ASMOP_GLOBAL:
2591        case ASMOP_GLOBL:
2592            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_GLOBAL);
2593            break;
2594        case ASMOP_GPU:
2595            AsmPseudoOps::setGPUDevice(*this, linePtr);
2596            break;
2597        case ASMOP_HALF:
2598            AsmPseudoOps::putFloats<uint16_t>(*this, stmtPlace, linePtr);
2599            break;
2600        case ASMOP_HWORD:
2601            AsmPseudoOps::putIntegers<uint16_t>(*this, stmtPlace, linePtr);
2602            break;
2603        case ASMOP_IF:
2604            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2605                      IfIntComp::NOT_EQUAL, false);
2606            break;
2607        case ASMOP_IF32:
2608            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, true, false);
2609            break;
2610        case ASMOP_IF64:
2611            AsmPseudoOps::doIf64Bit(*this, stmtPlace, linePtr, false, false);
2612            break;
2613        case ASMOP_IFARCH:
2614            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, false, false);
2615            break;
2616        case ASMOP_IFB:
2617            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, false, false);
2618            break;
2619        case ASMOP_IFC:
2620            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, false, false);
2621            break;
2622        case ASMOP_IFDEF:
2623            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, false, false);
2624            break;
2625        case ASMOP_IFEQ:
2626            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2627                      IfIntComp::EQUAL, false);
2628            break;
2629        case ASMOP_IFEQS:
2630            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, false, false);
2631            break;
2632        case ASMOP_IFFMT:
2633            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, false, false);
2634            break;
2635        case ASMOP_IFGE:
2636            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2637                      IfIntComp::GREATER_EQUAL, false);
2638            break;
2639        case ASMOP_IFGPU:
2640            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, false, false);
2641            break;
2642        case ASMOP_IFGT:
2643            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2644                      IfIntComp::GREATER, false);
2645            break;
2646        case ASMOP_IFLE:
2647            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2648                      IfIntComp::LESS_EQUAL, false);
2649            break;
2650        case ASMOP_IFLT:
2651            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2652                      IfIntComp::LESS, false);
2653            break;
2654        case ASMOP_IFNARCH:
2655            AsmPseudoOps::doIfArch(*this, stmtPlace, linePtr, true, false);
2656            break;
2657        case ASMOP_IFNB:
2658            AsmPseudoOps::doIfBlank(*this, stmtPlace, linePtr, true, false);
2659            break;
2660        case ASMOP_IFNC:
2661            AsmPseudoOps::doIfCmpStr(*this, stmtPlace, linePtr, true, false);
2662            break;
2663        case ASMOP_IFNDEF:
2664        case ASMOP_IFNOTDEF:
2665            AsmPseudoOps::doIfDef(*this, stmtPlace, linePtr, true, false);
2666            break;
2667        case ASMOP_IFNE:
2668            AsmPseudoOps::doIfInt(*this, stmtPlace, linePtr,
2669                      IfIntComp::NOT_EQUAL, false);
2670            break;
2671        case ASMOP_IFNES:
2672            AsmPseudoOps::doIfStrEqual(*this, stmtPlace, linePtr, true, false);
2673            break;
2674        case ASMOP_IFNFMT:
2675            AsmPseudoOps::doIfFmt(*this, stmtPlace, linePtr, true, false);
2676            break;
2677        case ASMOP_IFNGPU:
2678            AsmPseudoOps::doIfGpu(*this, stmtPlace, linePtr, true, false);
2679            break;
2680        case ASMOP_INCBIN:
2681            AsmPseudoOps::includeBinFile(*this, stmtPlace, linePtr);
2682            break;
2683        case ASMOP_INCLUDE:
2684            AsmPseudoOps::includeFile(*this, stmtPlace, linePtr);
2685            break;
2686        case ASMOP_IRP:
2687            AsmPseudoOps::doIRP(*this, stmtPlace, linePtr, false);
2688            break;
2689        case ASMOP_IRPC:
2690            AsmPseudoOps::doIRP(*this, stmtPlace, linePtr, true);
2691            break;
2692        case ASMOP_INT:
2693        case ASMOP_LONG:
2694            AsmPseudoOps::putIntegers<uint32_t>(*this, stmtPlace, linePtr);
2695            break;
2696        case ASMOP_KERNEL:
2697            AsmPseudoOps::goToKernel(*this, stmtPlace, linePtr);
2698            break;
2699        case ASMOP_LFLAGS:
2700            printWarning(stmtPlace, "'.lflags' is ignored by this assembler.");
2701            break;
2702        case ASMOP_LINE:
2703        case ASMOP_LN:
2704            printWarning(stmtPlace, "'.line' is ignored by this assembler.");
2705            break;
2706        case ASMOP_LOCAL:
2707            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_LOCAL);
2708            break;
2709        case ASMOP_MACRO:
2710            AsmPseudoOps::doMacro(*this, stmtPlace, linePtr);
2711            break;
2712        case ASMOP_MACROCASE:
2713            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2714                macroCase = true;
2715            break;
2716        case ASMOP_MAIN:
2717            AsmPseudoOps::goToMain(*this, stmtPlace, linePtr);
2718            break;
2719        case ASMOP_NOALTMACRO:
2720            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2721                alternateMacro = false;
2722            break;
2723        case ASMOP_NOBUGGYFPLIT:
2724            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2725                buggyFPLit = false;
2726            break;
2727        case ASMOP_NOMACROCASE:
2728            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2729                macroCase = false;
2730            break;
2731        case ASMOP_NOOLDMODPARAM:
2732            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2733                oldModParam = false;
2734            break;
2735        case ASMOP_OCTA:
2736            AsmPseudoOps::putUInt128s(*this, stmtPlace, linePtr);
2737            break;
2738        case ASMOP_OFFSET:
2739            AsmPseudoOps::setAbsoluteOffset(*this, linePtr);
2740            break;
2741        case ASMOP_OLDMODPARAM:
2742            if (AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2743                oldModParam = true;
2744            break;
2745        case ASMOP_ORG:
2746            AsmPseudoOps::doOrganize(*this, linePtr);
2747            break;
2748        case ASMOP_P2ALIGN:
2749            AsmPseudoOps::doAlign(*this, stmtPlace, linePtr, true);
2750            break;
2751        case ASMOP_PRINT:
2752            AsmPseudoOps::doPrint(*this, linePtr);
2753            break;
2754        case ASMOP_PURGEM:
2755            AsmPseudoOps::purgeMacro(*this, linePtr);
2756            break;
2757        case ASMOP_QUAD:
2758            AsmPseudoOps::putIntegers<uint64_t>(*this, stmtPlace, linePtr);
2759            break;
2760        case ASMOP_REGVAR:
2761            AsmPseudoOps::defRegVar(*this, stmtPlace, linePtr);
2762            break;
2763        case ASMOP_REPT:
2764            AsmPseudoOps::doRepeat(*this, stmtPlace, linePtr);
2765            break;
2766        case ASMOP_RODATA:
2767            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2768            break;
2769        case ASMOP_SCOPE:
2770            AsmPseudoOps::openScope(*this, stmtPlace, linePtr);
2771            break;
2772        case ASMOP_SECTION:
2773            AsmPseudoOps::goToSection(*this, stmtPlace, linePtr);
2774            break;
2775        case ASMOP_SHORT:
2776            AsmPseudoOps::putIntegers<uint16_t>(*this, stmtPlace, linePtr);
2777            break;
2778        case ASMOP_SINGLE:
2779            AsmPseudoOps::putFloats<uint32_t>(*this, stmtPlace, linePtr);
2780            break;
2781        case ASMOP_SIZE:
2782            AsmPseudoOps::setSymbolSize(*this, linePtr);
2783            break;
2784        case ASMOP_SKIP:
2785        case ASMOP_SPACE:
2786            AsmPseudoOps::doSkip(*this, stmtPlace, linePtr);
2787            break;
2788        case ASMOP_STRING:
2789            AsmPseudoOps::putStrings(*this, stmtPlace, linePtr, true);
2790            break;
2791        case ASMOP_STRING16:
2792            AsmPseudoOps::putStringsToInts<uint16_t>(*this, stmtPlace, linePtr);
2793            break;
2794        case ASMOP_STRING32:
2795            AsmPseudoOps::putStringsToInts<uint32_t>(*this, stmtPlace, linePtr);
2796            break;
2797        case ASMOP_STRING64:
2798            AsmPseudoOps::putStringsToInts<uint64_t>(*this, stmtPlace, linePtr);
2799            break;
2800        case ASMOP_STRUCT:
2801            AsmPseudoOps::setAbsoluteOffset(*this, linePtr);
2802            break;
2803        case ASMOP_TEXT:
2804            AsmPseudoOps::goToSection(*this, stmtPlace, stmtPlace, true);
2805            break;
2806        case ASMOP_SBTTL:
2807        case ASMOP_TITLE:
2808        case ASMOP_VERSION:
2809            AsmPseudoOps::ignoreString(*this, linePtr);
2810            break;
2811        case ASMOP_UNDEF:
2812            AsmPseudoOps::undefSymbol(*this, linePtr);
2813            break;
2814        case ASMOP_UNUSING:
2815            AsmPseudoOps::stopUsing(*this, stmtPlace, linePtr);
2816            break;
2817        case ASMOP_USEREG:
2818            AsmPseudoOps::doUseReg(*this, stmtPlace, linePtr);
2819            break;
2820        case ASMOP_USING:
2821            AsmPseudoOps::startUsing(*this, stmtPlace, linePtr);
2822            break;
2823        case ASMOP_WARNING:
2824            AsmPseudoOps::doWarning(*this, stmtPlace, linePtr);
2825            break;
2826        case ASMOP_WEAK:
2827            AsmPseudoOps::setSymbolBind(*this, linePtr, STB_WEAK);
2828            break;
2829        case ASMOP_WHILE:
2830            AsmPseudoOps::doWhile(*this, stmtPlace, linePtr);
2831            break;
2832        case ASMOP_WORD:
2833            AsmPseudoOps::putIntegers<uint32_t>(*this, stmtPlace, linePtr);
2834            break;
2835        default:
2836        {
2837            bool isGalliumPseudoOp = AsmGalliumPseudoOps::checkPseudoOpName(firstName);
2838            bool isAmdPseudoOp = AsmAmdPseudoOps::checkPseudoOpName(firstName);
2839            bool isAmdCL2PseudoOp = AsmAmdCL2PseudoOps::checkPseudoOpName(firstName);
2840            bool isROCmPseudoOp = AsmROCmPseudoOps::checkPseudoOpName(firstName);
2841            if (isGalliumPseudoOp || isAmdPseudoOp || isAmdCL2PseudoOp || isROCmPseudoOp)
2842            {
2843                // initialize only if gallium pseudo-op or AMD pseudo-op
2844                initializeOutputFormat();
2845                /// try to parse
2846                if (!formatHandler->parsePseudoOp(firstName, stmtPlace, linePtr))
2847                {
2848                    // check other
2849                    if (format != BinaryFormat::GALLIUM)
2850                    {
2851                        // check gallium pseudo-op
2852                        if (isGalliumPseudoOp)
2853                        {
2854                            printError(stmtPlace, "Gallium pseudo-op can be defined "
2855                                    "only in Gallium format code");
2856                            break;
2857                        }
2858                    }
2859                    if (format != BinaryFormat::AMD)
2860                    {
2861                        // check amd pseudo-op
2862                        if (isAmdPseudoOp)
2863                        {
2864                            printError(stmtPlace, "AMD pseudo-op can be defined only in "
2865                                    "AMD format code");
2866                            break;
2867                        }
2868                    }
2869                    if (format != BinaryFormat::AMDCL2)
2870                    {
2871                        // check amd pseudo-op
2872                        if (isAmdCL2PseudoOp)
2873                        {
2874                            printError(stmtPlace, "AMDCL2 pseudo-op can be defined only in "
2875                                    "AMDCL2 format code");
2876                            break;
2877                        }
2878                    }
2879                    if (format != BinaryFormat::ROCM)
2880                    {
2881                        // check rocm pseudo-op
2882                        if (isROCmPseudoOp)
2883                        {
2884                            printError(stmtPlace, "ROCm pseudo-op can be defined "
2885                                    "only in ROCm format code");
2886                            break;
2887                        }
2888                    }
2889                }
2890            }
2891            else if (makeMacroSubstitution(stmtPlace) == ParseState::MISSING)
2892                printError(stmtPlace, "This is neither pseudo-op and nor macro");
2893            break;
2894        }
2895    }
2896}
2897
2898/* skipping clauses */
2899bool Assembler::skipClauses(bool exitm)
2900{
2901    const cxuint clauseLevel = clauses.size();
2902    AsmClauseType topClause = (!clauses.empty()) ? clauses.top().type :
2903            AsmClauseType::IF;
2904    const bool isTopIfClause = (topClause == AsmClauseType::IF ||
2905            topClause == AsmClauseType::ELSEIF || topClause == AsmClauseType::ELSE);
2906    bool good = true;
2907    const size_t inputFilterTop = asmInputFilters.size();
2908    while (exitm || clauses.size() >= clauseLevel)
2909    {
2910        if (!readLine())
2911            break;
2912        // if exit from macro mode, exit when macro filter exits
2913        if (exitm && inputFilterTop > asmInputFilters.size())
2914        {
2915            // set lineAlreadyRead - next line after skipped region read will be read
2916            lineAlreadyRead  = true;
2917            break; // end of macro,
2918        }
2919       
2920        const char* linePtr = line;
2921        const char* end = line+lineSize;
2922        skipSpacesAndLabels(linePtr, end);
2923        const char* stmtPlace = linePtr;
2924        if (linePtr == end || *linePtr != '.')
2925            continue;
2926       
2927        CString pseudoOpName = extractSymName(linePtr, end, false);
2928        toLowerString(pseudoOpName);
2929       
2930        const size_t pseudoOp = binaryFind(offlinePseudoOpNamesTbl,
2931               offlinePseudoOpNamesTbl + sizeof(offlinePseudoOpNamesTbl)/sizeof(char*),
2932               pseudoOpName.c_str()+1, CStringLess()) - offlinePseudoOpNamesTbl;
2933       
2934        // any conditional inside macro or repeat will be ignored
2935        bool insideMacroOrRepeat = !clauses.empty() && 
2936            (clauses.top().type == AsmClauseType::MACRO ||
2937                    clauses.top().type == AsmClauseType::REPEAT);
2938        switch(pseudoOp)
2939        {
2940            case ASMCOP_ENDIF:
2941                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2942                    good = false;   // if endif have garbages
2943                else if (!insideMacroOrRepeat)
2944                    if (!popClause(stmtPlace, AsmClauseType::IF))
2945                        good = false;
2946                break;
2947            case ASMCOP_ENDM:
2948            case ASMCOP_ENDMACRO:
2949                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2950                    good = false;   // if .endm have garbages
2951                else if (!popClause(stmtPlace, AsmClauseType::MACRO))
2952                    good = false;
2953                break;
2954            case ASMCOP_ENDR:
2955            case ASMCOP_ENDREPT:
2956                if (!AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2957                    good = false;   // if .endr have garbages
2958                else if (!popClause(stmtPlace, AsmClauseType::REPEAT))
2959                    good = false;
2960                break;
2961            case ASMCOP_ELSE:
2962            case ASMCOP_ELSEIFARCH:
2963            case ASMCOP_ELSEIF:
2964            case ASMCOP_ELSEIF32:
2965            case ASMCOP_ELSEIF64:
2966            case ASMCOP_ELSEIFB:
2967            case ASMCOP_ELSEIFC:
2968            case ASMCOP_ELSEIFDEF:
2969            case ASMCOP_ELSEIFEQ:
2970            case ASMCOP_ELSEIFEQS:
2971            case ASMCOP_ELSEIFFMT:
2972            case ASMCOP_ELSEIFGE:
2973            case ASMCOP_ELSEIFGPU:
2974            case ASMCOP_ELSEIFGT:
2975            case ASMCOP_ELSEIFLE:
2976            case ASMCOP_ELSEIFLT:
2977            case ASMCOP_ELSEIFNARCH:
2978            case ASMCOP_ELSEIFNB:
2979            case ASMCOP_ELSEIFNC:
2980            case ASMCOP_ELSEIFNDEF:
2981            case ASMCOP_ELSEIFNE:
2982            case ASMCOP_ELSEIFNES:
2983            case ASMCOP_ELSEIFNFMT:
2984            case ASMCOP_ELSEIFNGPU:
2985            case ASMCOP_ELSEIFNOTDEF:
2986                if (pseudoOp == ASMCOP_ELSE &&
2987                            !AsmPseudoOps::checkGarbagesAtEnd(*this, linePtr))
2988                    good = false; // if .else have garbages
2989                else if (!insideMacroOrRepeat)
2990                {
2991                    if (!exitm && clauseLevel == clauses.size() && isTopIfClause)
2992                    {
2993                        /* set lineAlreadyRead - next line after skipped region read
2994                         * will be read */
2995                        lineAlreadyRead = true; // read
2996                        return good; // do exit
2997                    }
2998                    if (!pushClause(stmtPlace, (pseudoOp==ASMCOP_ELSE ?
2999                                AsmClauseType::ELSE : AsmClauseType::ELSEIF)))
3000                        good = false;
3001                }
3002                break;
3003            case ASMCOP_IF:
3004            case ASMCOP_IFARCH:
3005            case ASMCOP_IF32:
3006            case ASMCOP_IF64:
3007            case ASMCOP_IFB:
3008            case ASMCOP_IFC:
3009            case ASMCOP_IFDEF:
3010            case ASMCOP_IFEQ:
3011            case ASMCOP_IFEQS:
3012            case ASMCOP_IFFMT:
3013            case ASMCOP_IFGE:
3014            case ASMCOP_IFGPU:
3015            case ASMCOP_IFGT:
3016            case ASMCOP_IFLE:
3017            case ASMCOP_IFLT:
3018            case ASMCOP_IFNARCH:
3019            case ASMCOP_IFNB:
3020            case ASMCOP_IFNC:
3021            case ASMCOP_IFNDEF:
3022            case ASMCOP_IFNE:
3023            case ASMCOP_IFNES:
3024            case ASMCOP_IFNFMT:
3025            case ASMCOP_IFNGPU:
3026            case ASMCOP_IFNOTDEF:
3027                if (!insideMacroOrRepeat)
3028                {
3029                    if (!pushClause(stmtPlace, AsmClauseType::IF))
3030                        good = false;
3031                }
3032                break;
3033            case ASMCOP_MACRO:
3034                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
3035                    good = false;
3036                break;
3037            case ASMCOP_IRP:
3038            case ASMCOP_IRPC:
3039            case ASMCOP_REPT:
3040            case ASMCOP_FOR:
3041            case ASMCOP_WHILE:
3042                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
3043                    good = false;
3044                break;
3045            default:
3046                break;
3047        }
3048    }
3049    return good;
3050}
3051
3052bool Assembler::putMacroContent(RefPtr<AsmMacro> macro)
3053{
3054    const cxuint clauseLevel = clauses.size();
3055    bool good = true;
3056    while (clauses.size() >= clauseLevel)
3057    {
3058        if (!readLine())
3059        {
3060            // error, must be finished in by .endm or .endmacro
3061            good = false;
3062            break;
3063        }
3064       
3065        const char* linePtr = line;
3066        const char* end = line+lineSize;
3067        skipSpacesAndLabels(linePtr, end);
3068        const char* stmtPlace = linePtr;
3069        // if not pseudo-op
3070        if (linePtr == end || *linePtr != '.')
3071        {
3072            macro->addLine(currentInputFilter->getMacroSubst(),
3073                  currentInputFilter->getSource(),
3074                  currentInputFilter->getColTranslations(), lineSize, line);
3075            continue;
3076        }
3077       
3078        CString pseudoOpName = extractSymName(linePtr, end, false);
3079        toLowerString(pseudoOpName);
3080       
3081        const size_t pseudoOp = binaryFind(macroRepeatPseudoOpNamesTbl,
3082               macroRepeatPseudoOpNamesTbl + sizeof(macroRepeatPseudoOpNamesTbl) /
3083               sizeof(char*), pseudoOpName.c_str()+1, CStringLess()) -
3084               macroRepeatPseudoOpNamesTbl;
3085        // handle pseudo-op in macro content
3086        switch(pseudoOp)
3087        {
3088            case ASMMROP_ENDM:
3089            case ASMMROP_ENDMACRO:
3090                if (!popClause(stmtPlace, AsmClauseType::MACRO))
3091                    good = false;
3092                break;
3093            case ASMMROP_ENDR:
3094            case ASMMROP_ENDREPT:
3095                if (!popClause(stmtPlace, AsmClauseType::REPEAT))
3096                    good = false;
3097                break;
3098            case ASMMROP_MACRO:
3099                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
3100                    good = false;
3101                break;
3102            case ASMMROP_IRP:
3103            case ASMMROP_IRPC:
3104            case ASMMROP_REPT:
3105            case ASMMROP_FOR:
3106            case ASMMROP_WHILE:
3107                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
3108                    good = false;
3109                break;
3110            default:
3111                break;
3112        }
3113        if (pseudoOp != ASMMROP_ENDM || clauses.size() >= clauseLevel)
3114            // add line if is still in macro
3115            macro->addLine(currentInputFilter->getMacroSubst(),
3116                  currentInputFilter->getSource(),
3117                  currentInputFilter->getColTranslations(), lineSize, line);
3118    }
3119    return good;
3120}
3121
3122bool Assembler::putRepetitionContent(AsmRepeat& repeat)
3123{
3124    const cxuint clauseLevel = clauses.size();
3125    bool good = true;
3126    while (clauses.size() >= clauseLevel)
3127    {
3128        if (!readLine())
3129        {
3130            // error, must be finished in by .endm or .endmacro
3131            good = false;
3132            break;
3133        }
3134       
3135        const char* linePtr = line;
3136        const char* end = line+lineSize;
3137        skipSpacesAndLabels(linePtr, end);
3138        const char* stmtPlace = linePtr;
3139        // if not pseudo-op
3140        if (linePtr == end || *linePtr != '.')
3141        {
3142            repeat.addLine(currentInputFilter->getMacroSubst(),
3143               currentInputFilter->getSource(), currentInputFilter->getColTranslations(),
3144               lineSize, line);
3145            continue;
3146        }
3147       
3148        CString pseudoOpName = extractSymName(linePtr, end, false);
3149        toLowerString(pseudoOpName);
3150        const size_t pseudoOp = binaryFind(macroRepeatPseudoOpNamesTbl,
3151               macroRepeatPseudoOpNamesTbl + sizeof(macroRepeatPseudoOpNamesTbl) /
3152               sizeof(char*), pseudoOpName.c_str()+1, CStringLess()) -
3153               macroRepeatPseudoOpNamesTbl;
3154        // handle pseudo-op in macro content
3155        switch(pseudoOp)
3156        {
3157            case ASMMROP_ENDM:
3158                if (!popClause(stmtPlace, AsmClauseType::MACRO))
3159                    good = false;
3160                break;
3161            case ASMMROP_ENDR:
3162                if (!popClause(stmtPlace, AsmClauseType::REPEAT))
3163                    good = false;
3164                break;
3165            case ASMMROP_MACRO:
3166                if (!pushClause(stmtPlace, AsmClauseType::MACRO))
3167                    good = false;
3168                break;
3169            case ASMMROP_IRP:
3170            case ASMMROP_IRPC:
3171            case ASMMROP_REPT:
3172            case ASMMROP_FOR:
3173            case ASMMROP_WHILE:
3174                if (!pushClause(stmtPlace, AsmClauseType::REPEAT))
3175                    good = false;
3176                break;
3177            default:
3178                break;
3179        }
3180        if (pseudoOp != ASMMROP_ENDR || clauses.size() >= clauseLevel)
3181            // add line if is still in repetition
3182            repeat.addLine(currentInputFilter->getMacroSubst(),
3183                   currentInputFilter->getSource(),
3184                   currentInputFilter->getColTranslations(), lineSize, line);
3185    }
3186    return good;
3187}
Note: See TracBrowser for help on using the repository browser.