| /* SPDX-License-Identifier: BSD-2-Clause */ |
| /* Copyright 1996-2025 The NASM Authors - All Rights Reserved */ |
| |
| /* |
| * nasm.h main header file for the Netwide Assembler: inter-module interface |
| */ |
| |
| #ifndef NASM_NASM_H |
| #define NASM_NASM_H |
| |
| #include "compiler.h" |
| |
| #include <time.h> |
| |
| #include "nasmlib.h" |
| #include "nctype.h" |
| #include "strlist.h" |
| #include "preproc.h" |
| #include "macros.h" |
| #include "insnsi.h" /* For enum opcode */ |
| #include "directiv.h" /* For enum directive */ |
| #include "labels.h" /* For enum mangle_index, enum label_type */ |
| #include "opflags.h" |
| #include "regs.h" |
| #include "x86const.h" |
| #include "srcfile.h" |
| #include "error.h" |
| |
| /* Program name for error messages etc. */ |
| extern const char *_progname; |
| |
| /* Time stamp for the official start of compilation */ |
| struct compile_time { |
| time_t t; |
| bool have_local, have_gm, have_posix; |
| int64_t posix; |
| struct tm local; |
| struct tm gm; |
| }; |
| extern struct compile_time official_compile_time; |
| |
| /* POSIX timestamp if and only if we are not a reproducible build */ |
| extern bool reproducible; |
| static inline int64_t posix_timestamp(void) |
| { |
| return reproducible ? 0 : official_compile_time.posix; |
| } |
| |
| #define NO_SEG INT32_C(-1) /* null segment value */ |
| #define SEG_ABS 0x40000000L /* mask for far-absolute segments */ |
| |
| #define IDLEN_MAX 4096 |
| #define DECOLEN_MAX 32 |
| |
| /* |
| * Name pollution problems: <time.h> on Digital UNIX pulls in some |
| * strange hardware header file which sees fit to define R_SP. We |
| * undefine it here so as not to break the enum below. |
| */ |
| #ifdef R_SP |
| #undef R_SP |
| #endif |
| |
| /* |
| * We must declare the existence of this structure type up here, |
| * since we have to reference it before we define it... |
| */ |
| struct ofmt; |
| |
| /* |
| * Values for the `type' parameter to an output function. |
| */ |
| enum out_type { |
| OUT_RAWDATA, /* Plain bytes */ |
| OUT_RESERVE, /* Reserved bytes (RESB et al) */ |
| OUT_ZERODATA, /* Initialized data, but all zero */ |
| OUT_ADDRESS, /* An address (symbol value) */ |
| OUT_RELADDR, /* A relative address */ |
| OUT_SEGMENT, /* A segment number */ |
| |
| /* |
| * These values are used by the legacy backend interface only; see |
| * nasm_ofmt_output() in asm/assemble.c for more information. |
| * These should never be used otherwise. Once all backends have |
| * been fully migrated to the new interface they should be |
| * removed. |
| */ |
| OUT_REL1ADR, |
| OUT_REL2ADR, |
| OUT_REL4ADR, |
| OUT_REL8ADR |
| }; |
| |
| enum out_flags { |
| OUT_WRAP = 0, /* Undefined signedness (wraps) */ |
| OUT_SIGNED = 1, /* Value is signed */ |
| OUT_UNSIGNED = 2, /* Value is unsigned */ |
| OUT_SIGNMASK = 3, /* Mask for signedness bits */ |
| OUT_NOWARN = 4 /* Don't warn on overflow (already done?) */ |
| }; |
| |
| /* |
| * Description of an assembly output location |
| */ |
| struct location { |
| int64_t offset; |
| int32_t segment; |
| bool known; |
| }; |
| extern struct location location; /* Current assembly location */ |
| |
| /* |
| * The data we send down to the backend. |
| * XXX: We still want to push down the base address symbol if |
| * available, and replace the segment numbers with a structure. |
| */ |
| struct out_data { |
| struct location loc; /* seg:offset being written to */ |
| enum out_type type; /* See above */ |
| enum out_flags flags; /* See above */ |
| int inslen; /* Length of instruction */ |
| int insoffs; /* Offset inside instruction */ |
| int bits; /* Bits mode of compilation */ |
| uint64_t size; /* Size of output */ |
| const struct itemplate *itemp; /* Instruction template */ |
| const void *data; /* Data for OUT_RAWDATA */ |
| uint64_t toffset; /* Target address offset for relocation */ |
| int32_t tsegment; /* Target segment for relocation */ |
| int32_t twrt; /* Relocation with respect to */ |
| int64_t relbase; /* Relative base for OUT_RELADDR */ |
| struct src_location where; /* Source file and line */ |
| const char *what; /* Additional description, e.g. "immediate" */ |
| |
| /* |
| * Legacy output data fields; some of these differ in their |
| * definition from the corresponding modern fields. |
| * See nasm_ofmt_output() in asm/assemble.c. |
| */ |
| struct out_data_legacy { |
| const void *data; |
| enum out_type type; |
| uint64_t size; |
| int32_t tsegment; /* Legacy name "segment" */ |
| int32_t twrt; /* Legacy name "wrt" */ |
| } legacy; |
| }; |
| |
| /* |
| * And a label-definition function. The boolean parameter |
| * `is_norm' states whether the label is a `normal' label (which |
| * should affect the local-label system), or something odder like |
| * an EQU or a segment-base symbol, which shouldn't. |
| */ |
| typedef void (*ldfunc)(char *label, int32_t segment, int64_t offset, |
| char *special, bool is_norm); |
| |
| /* |
| * Token types returned by the scanner, in addition to ordinary |
| * ASCII character values, and zero for end-of-string. |
| */ |
| enum token_type { /* token types, other than chars */ |
| |
| /* Token values shared between assembler and preprocessor */ |
| |
| /* Special codes */ |
| TOKEN_INVALID = -1, /* a placeholder value */ |
| TOKEN_BLOCK = -2, /* used for storage management */ |
| TOKEN_FREE = -3, /* free token marker, use to catch leaks */ |
| TOKEN_EOS = 0, /* end of string */ |
| |
| /* |
| * Single-character operators. Enumerated here to keep strict |
| * compilers happy, and for documentation. |
| */ |
| TOKEN_WHITESPACE = ' ', /* Preprocessor use */ |
| TOKEN_BOOL_NOT = '!', |
| TOKEN_AND = '&', |
| TOKEN_OR = '|', |
| TOKEN_XOR = '^', |
| TOKEN_NOT = '~', |
| TOKEN_MULT = '*', |
| TOKEN_DIV = '/', |
| TOKEN_MOD = '%', |
| TOKEN_LPAR = '(', |
| TOKEN_RPAR = ')', |
| TOKEN_PLUS = '+', |
| TOKEN_MINUS = '-', |
| TOKEN_COMMA = ',', |
| TOKEN_LBRACE = '{', |
| TOKEN_RBRACE = '}', |
| TOKEN_LBRACKET = '[', |
| TOKEN_RBRACKET = ']', |
| TOKEN_QMARK = '?', |
| TOKEN_EQ = '=', /* = or == */ |
| TOKEN_GT = '>', |
| TOKEN_LT = '<', |
| TOKEN_COLON = ':', |
| |
| /* Multi-character operators */ |
| TOKEN_SHL = 256, /* << or <<< */ |
| TOKEN_SHR, /* >> */ |
| TOKEN_SAR, /* >>> */ |
| TOKEN_SDIV, /* // */ |
| TOKEN_SMOD, /* %% */ |
| TOKEN_GE, /* >= */ |
| TOKEN_LE, /* <= */ |
| TOKEN_NE, /* <> (!= is same as <>) */ |
| TOKEN_LEG, /* <=> */ |
| TOKEN_DBL_AND, /* && */ |
| TOKEN_DBL_OR, /* || */ |
| TOKEN_DBL_XOR, /* ^^ */ |
| |
| TOKEN_MAX_OPERATOR, |
| |
| TOKEN_NUM, /* numeric constant */ |
| TOKEN_ERRNUM, /* malformed numeric constant */ |
| TOKEN_STR, /* string constant */ |
| TOKEN_ERRSTR, /* unterminated string constant */ |
| TOKEN_ID, /* identifier */ |
| TOKEN_FLOAT, /* floating-point constant */ |
| TOKEN_HERE, /* $, not '$' because it is not an operator */ |
| TOKEN_BASE, /* $$ */ |
| |
| /* Token values only used by the assembler */ |
| TOKEN_START_ASM, |
| |
| TOKEN_SEG, /* SEG */ |
| TOKEN_WRT, /* WRT */ |
| TOKEN_TIMES, /* TIMES */ |
| TOKEN_FLOATIZE, /* __?floatX?__ */ |
| TOKEN_STRFUNC, /* __utf16*__, __utf32*__ */ |
| TOKEN_IFUNC, /* __ilog2*__ */ |
| TOKEN_DECORATOR, /* decorators such as {...} */ |
| TOKEN_MASM_PTR, /* __?masm_ptr?__ for the masm package */ |
| TOKEN_MASM_FLAT, /* __?masm_flat?__ for the masm package */ |
| TOKEN_OPMASK, /* translated token for opmask registers */ |
| TOKEN_SIZE, /* BYTE, WORD, DWORD, QWORD, etc */ |
| TOKEN_SPECIAL, /* REL, FAR, NEAR, STRICT, NOSPLIT, etc */ |
| TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ |
| TOKEN_BRCCONST, /* braced constant expression */ |
| TOKEN_REG, /* register name */ |
| TOKEN_INSN, /* instruction name */ |
| |
| TOKEN_END_ASM, |
| |
| /* Token values only used by the preprocessor */ |
| |
| TOKEN_START_PP = TOKEN_END_ASM, |
| |
| TOKEN_OTHER, /* % sequence without (current) meaning */ |
| TOKEN_PREPROC_ID, /* Preprocessor ID, e.g. %symbol */ |
| TOKEN_MMACRO_PARAM, /* MMacro parameter, e.g. %1 */ |
| TOKEN_LOCAL_SYMBOL, /* Local symbol, e.g. %%symbol */ |
| TOKEN_LOCAL_MACRO, /* Context-local macro, e.g. %$symbol */ |
| TOKEN_ENVIRON, /* %! */ |
| TOKEN_INTERNAL_STR, /* Unquoted string that should remain so */ |
| TOKEN_NAKED_STR, /* Unquoted string that can be re-quoted */ |
| TOKEN_PREPROC_Q, /* %? */ |
| TOKEN_PREPROC_QQ, /* %?? */ |
| TOKEN_PREPROC_SQ, /* %*? */ |
| TOKEN_PREPROC_SQQ, /* %*?? */ |
| TOKEN_PASTE, /* %+ */ |
| TOKEN_COND_COMMA, /* %, */ |
| TOKEN_INDIRECT, /* %[...] */ |
| TOKEN_XDEF_PARAM, /* Used during %xdefine processing */ |
| /* smacro parameters starting here; an arbitrary number. */ |
| TOKEN_SMAC_START_PARAMS, /* MUST BE LAST IN THE LIST!!! */ |
| TOKEN_MAX = INT_MAX /* Keep compiler from reducing the range */ |
| }; |
| |
| /* |
| * Token flags |
| */ |
| enum token_flags { |
| TFLAG_BRC = 1 << 0, /* valid only with braces. {1to8}, {rd-sae}, ...*/ |
| TFLAG_BRC_OPT = 1 << 1, /* may or may not have braces. opmasks {k1} */ |
| TFLAG_BRC_ANY = TFLAG_BRC | TFLAG_BRC_OPT, |
| TFLAG_BRDCAST = 1 << 2, /* broadcasting decorator */ |
| TFLAG_WARN = 1 << 3, /* warning only, treat as ID */ |
| TFLAG_DUP = 1 << 4, /* valid ID but also has context-specific use */ |
| TFLAG_ORBIT = 1 << 5 /* OR in the bit given in t_inttwo */ |
| }; |
| |
| /* Must match the fp_formats[] array in asm/floats.c */ |
| enum floatize { |
| FLOAT_8, |
| FLOAT_16, |
| FLOAT_B16, |
| FLOAT_32, |
| FLOAT_64, |
| FLOAT_80M, |
| FLOAT_80E, |
| FLOAT_128L, |
| FLOAT_128H, |
| FLOAT_ERR /* Invalid format, MUST BE LAST */ |
| }; |
| |
| /* Must match the list in string_transform(), in strfunc.c */ |
| enum strfunc { |
| STRFUNC_UTF16, |
| STRFUNC_UTF16LE, |
| STRFUNC_UTF16BE, |
| STRFUNC_UTF32, |
| STRFUNC_UTF32LE, |
| STRFUNC_UTF32BE |
| }; |
| |
| enum ifunc { |
| IFUNC_ILOG2E, |
| IFUNC_ILOG2W, |
| IFUNC_ILOG2F, |
| IFUNC_ILOG2C |
| }; |
| |
| size_t string_transform(char *, size_t, char **, enum strfunc); |
| |
| /* |
| * The expression evaluator must be passed a scanner function; a |
| * standard scanner is provided as part of nasmlib.c. The |
| * preprocessor will use a different one. Scanners, and the |
| * token-value structures they return, look like this. |
| * |
| * The return value from the scanner is always a copy of the |
| * `t_type' field in the structure. |
| */ |
| struct tokenval { |
| int64_t t_integer; |
| int64_t t_inttwo; |
| char *t_charptr; |
| const char *t_start; /* Pointer to token in input buffer */ |
| int t_len; /* Length of token in input buffer */ |
| enum token_type t_type; |
| enum token_flags t_flag; |
| }; |
| typedef int (*scanner)(void *private_data, struct tokenval *tv); |
| |
| /* |
| * Expression-evaluator datatype. Expressions, within the |
| * evaluator, are stored as an array of these beasts, terminated by |
| * a record with type==0. Mostly, it's a vector type: each type |
| * denotes some kind of a component, and the value denotes the |
| * multiple of that component present in the expression. The |
| * exception is the WRT type, whose `value' field denotes the |
| * segment to which the expression is relative. These segments will |
| * be segment-base types, i.e. either odd segment values or SEG_ABS |
| * types. So it is still valid to assume that anything with a |
| * `value' field of zero is insignificant. |
| */ |
| typedef struct { |
| int32_t type; /* a register, or EXPR_xxx */ |
| int64_t value; /* must be >= 32 bits */ |
| } expr; |
| |
| /* |
| * Library routines to manipulate expression data types. |
| */ |
| enum expr_classes { |
| EC_ZERO = 0, /* All-zero expression */ |
| EC_CONST = 1, /* Additive constant */ |
| EC_SEGABS = 2, /* Absolute segment reference */ |
| EC_SIMPLE = EC_CONST | EC_SEGABS, |
| EC_SELFREL = 4, /* Self-relative expression */ |
| EC_SEG = 8, /* Has a segment base */ |
| EC_WRT = 16, /* Has WRT */ |
| EC_RELOC = EC_SIMPLE | EC_SELFREL | EC_SEG | EC_WRT, |
| EC_UNKNOWN = 32, /* Has an "unknown" part */ |
| EC_REGISTER = 64, /* Has a register */ |
| EC_REGEXPR = 128, /* Has more than one register and/or reg*n */ |
| EC_COMPLEX = 256 /* Even more complex, problematic */ |
| }; |
| |
| enum expr_classes expr_class(const expr *vect); |
| bool is_reloc(const expr *vect); |
| bool is_simple(const expr *vect); |
| bool is_really_simple(const expr *vect); |
| bool is_unknown(const expr *vect); |
| bool is_just_unknown(const expr *vect); |
| int64_t reloc_value(const expr *vect); |
| int32_t reloc_seg(const expr *vect); |
| int32_t reloc_wrt(const expr *vect); |
| bool is_self_relative(const expr *vect); |
| void dump_expr(const expr *vect); |
| |
| /* |
| * The evaluator can also return hints about which of two registers |
| * used in an expression should be the base register. See also the |
| * `operand' structure. |
| */ |
| struct eval_hints { |
| int64_t base; |
| int type; |
| }; |
| |
| /* |
| * The actual expression evaluator function looks like this. When |
| * called, it expects the first token of its expression to already |
| * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and |
| * it will start by calling the scanner. |
| * |
| * If a forward reference happens during evaluation, the evaluator |
| * must set `*fwref' to true if `fwref' is non-NULL. |
| * |
| * `critical' is non-zero if the expression may not contain forward |
| * references. The evaluator will report its own error if this |
| * occurs; if `critical' is 1, the error will be "symbol not |
| * defined before use", whereas if `critical' is 2, the error will |
| * be "symbol undefined". |
| * |
| * If `critical' has bit 8 set (in addition to its main value: 0x101 |
| * and 0x102 correspond to 1 and 2) then an extended expression |
| * syntax is recognised, in which relational operators such as =, < |
| * and >= are accepted, as well as low-precedence logical operators |
| * &&, ^^ and ||. |
| * |
| * If `hints' is non-NULL, it gets filled in with some hints as to |
| * the base register in complex effective addresses. |
| */ |
| #define CRITICAL 0x100 |
| typedef expr *(*evalfunc)(scanner sc, void *scprivate, |
| struct tokenval *tv, int *fwref, int critical, |
| struct eval_hints *hints); |
| |
| /* |
| * Special values for expr->type. |
| * These come after EXPR_REG_END as defined in regs.h. |
| * Expr types : 0 ~ EXPR_REG_END, EXPR_UNKNOWN, EXPR_...., EXPR_RDSAE, |
| * EXPR_SEGBASE ~ EXPR_SEGBASE + SEG_ABS, ... |
| */ |
| #define EXPR_UNKNOWN (EXPR_REG_END+1) /* forward references */ |
| #define EXPR_SIMPLE (EXPR_REG_END+2) |
| #define EXPR_WRT (EXPR_REG_END+3) |
| #define EXPR_RDSAE (EXPR_REG_END+4) |
| #define EXPR_SEGBASE (EXPR_REG_END+5) |
| |
| /* |
| * preprocessors ought to look like this: |
| */ |
| |
| enum preproc_mode { |
| PP_NORMAL, /* Assembly */ |
| PP_DEPS, /* Dependencies only */ |
| PP_PREPROC /* Preprocessing only */ |
| }; |
| |
| enum preproc_opt { |
| PP_TRIVIAL = 1, /* Only %line or # directives */ |
| PP_NOLINE = 2, /* Ignore %line and # directives */ |
| PP_TASM = 4 /* TASM compatibility hacks */ |
| }; |
| |
| /* |
| * Called once at the very start of assembly. |
| */ |
| void pp_init(enum preproc_opt opt); |
| |
| /* |
| * Called at the start of a pass; given a file name, the number |
| * of the pass, an error reporting function, an evaluator |
| * function, and a listing generator to talk to. |
| */ |
| void pp_reset(const char *file, enum preproc_mode mode, |
| struct strlist *deplist); |
| |
| /* |
| * Called to fetch a line of preprocessed source. The line |
| * returned has been malloc'ed, and so should be freed after |
| * use. |
| */ |
| char *pp_getline(void); |
| |
| /* Called at the end of each pass. */ |
| void pp_cleanup_pass(void); |
| |
| /* |
| * Called at the end of the assembly session, |
| * after cleanup_pass() has been called for the |
| * last pass. |
| */ |
| void pp_cleanup_session(void); |
| |
| /* Early definitions and undefinitions for macros */ |
| void pp_pre_define(char *definition); |
| void pp_pre_undefine(char *definition); |
| |
| /* Include file from command line */ |
| void pp_pre_include(char *fname); |
| |
| /* Add a command from the command line */ |
| void pp_pre_command(const char *what, char *str); |
| |
| /* Include path from command line */ |
| void pp_include_path(struct strlist *ipath); |
| |
| /* Unwind the macro stack when printing an error message */ |
| void pp_error_list_macros(errflags severity); |
| |
| /* Return true if an error message should be suppressed */ |
| bool pp_suppress_error(errflags severity); |
| |
| /* List of dependency files */ |
| extern struct strlist *depend_list; |
| |
| /* TASM mode changes some properties */ |
| extern bool tasm_compatible_mode; |
| |
| /* |
| * inline function to skip past an identifier; returns the first character past |
| * the identifier if valid, otherwise NULL. |
| */ |
| static inline char *nasm_skip_identifier(const char *str) |
| { |
| const char *p = str; |
| |
| if (!nasm_isidstart(*p++)) { |
| p = NULL; |
| } else { |
| while (nasm_isidchar(*p++)) |
| ; |
| } |
| return (char *)p; |
| } |
| |
| /* |
| * ----------------------------------------------------------- |
| * Format of the `insn' structure returned from `parser.c' and |
| * passed into `assemble.c' |
| * ----------------------------------------------------------- |
| */ |
| |
| /* |
| * REX flags |
| * |
| * Note: REX_[BXRW] and REX_P must match the locations of these |
| * bits within an actual REX prefix (with REX_P being the invariant |
| * 0x40 bit. REX_[BXR]1 must match the locations of these bits |
| * within the REX2 prefix, shifted into the second byte (<< 12). |
| * Finally, REX_[BXR]V are should match BXR << 16. |
| * |
| * REX_W64 is a separate bit to indicate that REX.W should be set |
| * if the operand size is 64. It can be overridden by the "nw" (0327) |
| * byte code. |
| */ |
| #define REX_MASK 0x4f /* Actual REX prefix bits */ |
| #define REX_B 0x01 /* ModRM r/m extension */ |
| #define REX_X 0x02 /* SIB index extension */ |
| #define REX_R 0x04 /* ModRM reg extension */ |
| #define REX_W 0x08 /* 64-bit operand size */ |
| #define REX_L 0x20 /* Use LOCK prefix instead of REX.R */ |
| #define REX_P 0x40 /* REX prefix present/required */ |
| #define REX_H 0x80 /* High register present, REX forbidden */ |
| #define REX_V 0x0100 /* Instruction uses VEX/XOP instead of REX */ |
| #define REX_NH 0x0200 /* Instruction which doesn't use high regs */ |
| #define REX_EV 0x0400 /* Instruction uses EVEX instead of REX */ |
| #define REX_2 0x0800 /* Instruction requires REX2 */ |
| #define REX_B1 0x1000 /* REX2/EVEX B second bit */ |
| #define REX_X1 0x2000 /* REX2/EVEX X second bit */ |
| #define REX_R1 0x4000 /* REX2/EVEX R second bit */ |
| #define REX_NW 0x8000 /* REX.W not required for 64-bit operand mode */ |
| |
| #define REX_BV 0x10000 /* B is not a GPR or CREG */ |
| #define REX_XV 0x20000 /* X is not a GPR or CREG */ |
| #define REX_RV 0x40000 /* R is not a GPR or CREG */ |
| |
| #define REX_BXR0 0x0007 |
| #define REX_BXR1 0x7000 |
| #define REX_BXR 0x7007 |
| #define REX_BXRV 0x70000 |
| |
| /* All flags pertaining to B, X, and R */ |
| #define REX_rB (REX_B | REX_B1 | REX_BV | REX_H | REX_P) |
| #define REX_rX (REX_X | REX_X1 | REX_XV | REX_H | REX_P) |
| #define REX_rR (REX_R | REX_R1 | REX_RV | REX_H | REX_P) |
| |
| /* |
| * EVEX bit fields. Note that the P[] numbers in the SDM does not include |
| * the leading 0x62 byte, so add 8 to the position. |
| * |
| * NOTES: B4 is in bit X3 = P[5] if B is a vector |
| * X4 is in bit V4 = P[19] if X is a vector |
| */ |
| #define evexf(name,pos,width) \ |
| mk_field(EVEX_ ## name, 8+(pos), width) |
| |
| enum evex_fields { |
| evexf(MM, 0, 3), /* EVEX P[2:0] : Opcode map */ |
| evexf(B4, 3, 1), /* EVEX P[3] : Bit 4 B register (B4*) */ |
| evexf(R4, 4, 1), /* EVEX P[4] : Bit 4 R register (R4) */ |
| evexf(B3, 5, 1), /* EVEX P[5] : Bit 3 B register (B3) */ |
| evexf(X3, 6, 1), /* EVEX P[5] : Bit 3 X register (X3*) */ |
| evexf(R3, 7, 1), /* EVEX P[7] : Bit 3 R register (R3) */ |
| evexf(PP, 8, 2), /* EVEX P[9:8] : Legacy prefix */ |
| evexf(X4, 10, 1), /* EVEX P[10] : Bit 4 X register (X4) */ |
| evexf(VVVV, 11, 4), /* EVEX P[14:11] : V register (V3-V0) */ |
| evexf(W, 15, 1), /* EVEX P[15] : Osize extension (REX.W) */ |
| evexf(AAA, 16, 3), /* EVEX P[18:16] : Embedded opmask */ |
| evexf(NF, 18, 1), /* EVEX P[18]: No flags bit */ |
| evexf(V4, 19, 1), /* EVEX P[19] : Bit 4 V register (V4*) */ |
| evexf(SCC, 16, 4), /* EVEX P[19:16]: Modified condition */ |
| evexf(B, 20, 1), /* EVEX P[20] : Broadcast / RC / SAE */ |
| evexf(ND, 20, 1), /* EVEX P[20] : New destination */ |
| evexf(ZU, 20, 1), /* EVEX P[20] : Zero upper */ |
| evexf(LL, 21, 2), /* EVEX P[22:21] : Vector length */ |
| evexf(RC, 21, 2), /* EVEX P[22:21] : Rounding control */ |
| evexf(Z, 23, 1) /* EVEX P[23] : Zeroing/Merging */ |
| }; |
| |
| /* |
| * REX_V "classes" (prefixes which behave like VEX) |
| */ |
| enum vex_class { |
| RV_VEX = 0, /* C4/C5 */ |
| RV_XOP = 1, /* 8F */ |
| RV_EVEX = 2 /* 62 */ |
| }; |
| |
| /* |
| * Note that because segment registers may be used as instruction |
| * prefixes, we must ensure the enumerations for prefixes and |
| * register names do not overlap. |
| * |
| * These MUST match the table in common/common.c |
| */ |
| enum prefixes { /* instruction prefixes */ |
| P_none = 0, |
| P_any = 1, |
| PREFIX_ENUM_START = REG_ENUM_LIMIT, |
| P_A16 = PREFIX_ENUM_START, |
| P_A32, |
| P_A64, |
| P_ASP, |
| P_LOCK, |
| P_O16, |
| P_O32, |
| P_O64, |
| P_OSP, |
| P_REP, |
| P_REPE, |
| P_REPNE, |
| P_REPNZ, |
| P_REPZ, |
| P_WAIT, |
| P_XACQUIRE, |
| P_XRELEASE, |
| P_BND, |
| P_NOBND, |
| P_REX, |
| P_REX2, |
| P_EVEX, |
| P_VEX, |
| P_VEX3, |
| P_VEX2, |
| P_NF, |
| P_ZU, |
| P_PT, |
| P_PN, |
| PREFIX_ENUM_LIMIT |
| }; |
| |
| enum ea_flags { /* special EA flags */ |
| EAF_BYTEOFFS = 1, /* force offset part to byte size */ |
| EAF_WORDOFFS = 2, /* force offset part to [d]word size */ |
| EAF_TIMESTWO = 4, /* really do EAX*2 not EAX+EAX */ |
| EAF_REL = 8, /* IP-relative addressing */ |
| EAF_ABS = 16, /* non-IP-relative addressing */ |
| EAF_MIB = 32, /* mib operand */ |
| EAF_SIB = 64, /* SIB encoding obligatory */ |
| EAF_NOTFSGS = 128, /* no fs: or gs: */ |
| EAF_FS = 256, /* fs segment override present */ |
| EAF_GS = 512 /* gs segment override present */ |
| }; |
| |
| enum eval_hint { /* values for `hinttype' */ |
| EAH_NOHINT = 0, /* no hint at all - our discretion */ |
| EAH_MAKEBASE = 1, /* try to make given reg the base */ |
| EAH_NOTBASE = 2, /* try _not_ to make reg the base */ |
| EAH_SUMMED = 3 /* base and index are summed into index */ |
| }; |
| |
| typedef struct operand { /* operand to an instruction */ |
| opflags_t type; /* type of operand */ |
| opflags_t xsize; /* size flags used in find_match() */ |
| enum reg_enum basereg; |
| enum reg_enum indexreg; /* address registers */ |
| int scale; /* index scale */ |
| int hintbase; |
| enum eval_hint hinttype; /* hint as to real base register */ |
| int32_t segment; /* immediate segment, if needed */ |
| int64_t offset; /* any immediate number */ |
| int32_t wrt; /* segment base it's relative to */ |
| int eaflags; /* special EA flags */ |
| int opflags; /* see OPFLAG_* defines below */ |
| int iflag; /* Requires a specific IF_* flag */ |
| decoflags_t decoflags; /* decorator flags such as {...} */ |
| bool bcast; /* broadcast operand */ |
| uint8_t disp_size; /* 0 means default; 16; 32; 64 */ |
| uint8_t opidx; /* Operand index */ |
| } operand; |
| |
| #define OPFLAG_FORWARD 1 /* operand is a forward reference */ |
| #define OPFLAG_EXTERN 2 /* operand is an external reference */ |
| #define OPFLAG_UNKNOWN 4 /* operand is an unknown reference |
| (always a forward reference also) */ |
| #define OPFLAG_RELATIVE 8 /* operand is self-relative, e.g. [foo - $] |
| where foo is not in the current segment */ |
| #define OPFLAG_SIMPLE 16 /* operand is a simple expression */ |
| |
| enum extop_type { /* extended operand types */ |
| EOT_NOTHING = 0, |
| EOT_EXTOP, /* Subexpression */ |
| EOT_DB_STRING, /* Byte string */ |
| EOT_DB_FLOAT, /* Floating-pointer number (special byte string) */ |
| EOT_DB_STRING_FREE, /* Byte string which should be nasm_free'd*/ |
| EOT_DB_NUMBER, /* Integer */ |
| EOT_DB_RESERVE /* ? */ |
| }; |
| |
| typedef struct extop { /* extended operand */ |
| struct extop *next; /* linked list */ |
| union { |
| struct { /* text or byte string */ |
| char *data; |
| size_t len; |
| } string; |
| struct { /* numeric expression */ |
| int64_t offset; /* numeric value or address offset */ |
| int32_t segment; /* address segment */ |
| int32_t wrt; /* address wrt */ |
| bool relative; /* self-relative expression */ |
| } num; |
| struct extop *subexpr; /* actual expressions */ |
| } val; |
| size_t dup; /* duplicated? */ |
| enum extop_type type; /* defined above */ |
| int elem; /* element size override, if any (bytes) */ |
| } extop; |
| |
| enum ea_type { |
| EA_INVALID, /* Not a valid EA at all */ |
| EA_SCALAR, /* Scalar EA */ |
| EA_XMMVSIB, /* XMM vector EA */ |
| EA_YMMVSIB, /* YMM vector EA */ |
| EA_ZMMVSIB /* ZMM vector EA */ |
| }; |
| |
| /* |
| * Prefix positions: each type of prefix goes in a specific slot. |
| * This affects the final ordering of the assembled output, which |
| * shouldn't matter to the processor, but if you have stylistic |
| * preferences, you can change this. REX prefixes are handled |
| * differently for the time being. |
| * |
| * LOCK and REP used to be one slot; this is no longer the case since |
| * the introduction of HLE. |
| * |
| * The prefixes are emitted in order by slot number. |
| * |
| * Note: these are stored in an PPS_BITS-bit field in the token hash! |
| * |
| */ |
| enum prefix_pos { |
| PPS_WAIT = 0, /* WAIT (technically not a prefix!) */ |
| PPS_SEG, /* Segment override prefix */ |
| PPS_ASIZE, /* Address size prefix */ |
| PPS_LOCK, /* LOCK prefix */ |
| PPS_OSIZE, /* Operand size prefix */ |
| PPS_REP, /* REP/HLE prefix */ |
| PPS_REX, /* REX/VEX type */ |
| PPS_NF, /* Do not set flags */ |
| PPS_ZU, /* Zero upper register */ |
| MAXPREFIX /* Total number of prefix slots */ |
| }; |
| |
| /* |
| * Tuple types that are used when determining Disp8*N eligibility |
| * The order must match with a hash %tuple_codes in insns.pl |
| */ |
| enum ttypes { |
| FV = 001, |
| HV = 002, |
| FVM = 003, |
| T1S8 = 004, |
| T1S16 = 005, |
| T1S = 006, |
| T1F32 = 007, |
| T1F64 = 010, |
| T2 = 011, |
| T4 = 012, |
| T8 = 013, |
| HVM = 014, |
| QVM = 015, |
| OVM = 016, |
| M128 = 017, |
| DUP = 020 |
| }; |
| |
| /* EVEX.L'L : Vector length on vector insns */ |
| enum vectlens { |
| VL128 = 0, |
| VL256 = 1, |
| VL512 = 2, |
| VLMAX = 3 |
| }; |
| |
| /* A postprocessed effective address (EA) */ |
| struct ea_data { |
| enum ea_type type; /* what kind of EA is this? */ |
| uint32_t rex; /* EA-derived REX flags */ |
| bool sib_present; /* is a SIB byte necessary? */ |
| uint8_t bytes; /* # of bytes of offset needed */ |
| uint8_t size; /* lazy - this is sib+bytes+1 */ |
| uint8_t modrm, sib; /* the bytes themselves */ |
| bool rip; /* RIP-relative? */ |
| int8_t disp8; /* 8-bit displacement, possibly compressed */ |
| uint8_t disp8_shift; /* Shift for 8-bit displacement */ |
| bool disp8_ok; /* 8-bit displacement is valid */ |
| }; |
| |
| /* |
| * flag to disable optimizations selectively |
| * this is useful to turn-off certain optimizations |
| */ |
| enum optimization { |
| /* Individual flags */ |
| OPTIM_NO_Jcc_RELAX = 1, /* Disable Jcc relaxation */ |
| OPTIM_NO_JMP_RELAX = 2, /* Disable JMP relaxation */ |
| OPTIM_STRICT_INSTR = 4, /* Disable alternate instructions */ |
| OPTIM_STRICT_OPER = 8, /* Disable operand relaxation */ |
| OPTIM_DISABLE_FWREF = 16, /* Disable forward reference relaxation */ |
| OPTIM_STRICT_OSIZE = 32, /* Disable osize adjustments */ |
| |
| /* Everything */ |
| OPTIM_ALL_ENABLED = 0, |
| |
| /* Disable all jump relaxations */ |
| OPTIM_DISABLE_JMP_MATCH = OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX, |
| |
| /* Level 0 : 0.98 behavior */ |
| OPTIM_LEVEL_0 = |
| OPTIM_STRICT_INSTR | OPTIM_STRICT_OSIZE | OPTIM_STRICT_OPER | |
| OPTIM_NO_JMP_RELAX, |
| |
| /* Level 1 : 0.98.09 behavior */ |
| OPTIM_LEVEL_1 = |
| OPTIM_STRICT_INSTR | OPTIM_STRICT_OSIZE | OPTIM_NO_Jcc_RELAX | |
| OPTIM_NO_JMP_RELAX | OPTIM_DISABLE_FWREF, |
| |
| /* Default */ |
| OPTIM_DEFAULT = OPTIM_ALL_ENABLED |
| }; |
| |
| /* |
| * Used with byte values for prefixes when no single byte value applies |
| */ |
| enum prefix_err { |
| PFE_NULL = -1, /* No output */ |
| PFE_MULTI = -2, /* Multibyte output (VEX, EVEX, REX2) */ |
| PFE_ERR = -3, /* Invalid prefix use */ |
| PFE_WHAT = -4 /* Not a valid prefix (internal error) */ |
| }; |
| |
| typedef struct insn { /* an instruction itself */ |
| enum opcode opcode; /* the opcode - not just the string */ |
| struct location loc; /* assembly location */ |
| int prefixes[MAXPREFIX]; /* instruction prefixes, if any */ |
| int need_pfx[MAXPREFIX]; /* byte prefixes used as opcodes */ |
| char *label; /* the label defined, or NULL */ |
| extop *eops; /* extended operands */ |
| int eops_float; /* true if DD and floating */ |
| int32_t times; /* repeat count (TIMES prefix) */ |
| bool rex_done; /* REX prefix emitted? */ |
| bool dummy; /* not a real instruction, no errors */ |
| uint8_t bits; /* Execution mode (16, 32, 64) */ |
| uint8_t op_size; /* operand size */ |
| uint8_t addr_size; /* address size */ |
| uint8_t operands; /* how many operands? 0-7 unless eops */ |
| uint8_t vexreg; /* Register encoded in VEX.V */ |
| uint8_t veximm; /* Bit-inverted immediate encoded |
| in VEX.V */ |
| uint8_t vex_cm; /* Class and M field for VEX prefix */ |
| uint8_t vex_wlp; /* W, P and L information for VEX prefix */ |
| uint32_t rex; /* REX prefix flags */ |
| uint32_t evex; /* EVEX prefix under construction */ |
| enum ttypes evex_tuple; /* Tuple type for compressed Disp8*N */ |
| int evex_rm; /* static rounding mode for AVX512 (EVEX) */ |
| enum optimization opt; /* Optimization flags to use */ |
| struct ea_data ea; /* Effective address data */ |
| const struct itemplate *itemp; /* Instruction template */ |
| const struct operand *evex_brerop; /* BR/ER/SAE operand position */ |
| struct operand oprs[MAX_OPERANDS]; /* the operands, defined as above */ |
| |
| int itempindex; /* For debug: instruction template index in insnsa.c */ |
| } insn; |
| |
| /* Instruction flags type: IF_* flags are defined in insns.h */ |
| typedef uint64_t iflags_t; |
| |
| /* |
| * What to return from a directive- or pragma-handling function. |
| * Currently DIRR_OK and DIRR_ERROR are treated the same way; |
| * in both cases the backend is expected to produce the appropriate |
| * error message on its own. |
| * |
| * DIRR_BADPARAM causes a generic error message to be printed. Note |
| * that it is an error, not a warning, even in the case of pragmas; |
| * don't use it where forward compatibility would be compromised |
| * (instead consider adding a DIRR_WARNPARAM.) |
| */ |
| enum directive_result { |
| DIRR_UNKNOWN, /* Directive not handled by backend */ |
| DIRR_OK, /* Directive processed */ |
| DIRR_ERROR, /* Directive processed unsuccessfully */ |
| DIRR_BADPARAM /* Print bad argument error message */ |
| }; |
| |
| /* |
| * A pragma facility: this structure is used to request passing a |
| * parsed pragma directive for a specific facility. If the handler is |
| * NULL then this pragma facility is recognized but ignored; pragma |
| * processing stops at that point. |
| * |
| * Note that the handler is passed a pointer to the facility structure |
| * as part of the struct pragma. |
| */ |
| struct pragma; |
| typedef enum directive_result (*pragma_handler)(const struct pragma *); |
| |
| struct pragma_facility { |
| const char *name; |
| pragma_handler handler; |
| }; |
| |
| /* |
| * This structure defines how a pragma directive is passed to a |
| * facility. This structure may be augmented in the future. |
| * |
| * Any facility MAY, but is not required to, add its operations |
| * keywords or a subset thereof into asm/directiv.dat, in which case |
| * the "opcode" field will be set to the corresponding D_ constant |
| * from directiv.h; otherwise it will be D_unknown. |
| */ |
| struct pragma { |
| const struct pragma_facility *facility; |
| const char *facility_name; /* Facility name exactly as entered by user */ |
| const char *opname; /* First word after the facility name */ |
| const char *tail; /* Anything after the operation */ |
| enum directive opcode; /* Operation as a D_ directives constant */ |
| }; |
| |
| /* |
| * These are semi-arbitrary limits to keep the assembler from going |
| * into a black hole on certain kinds of bugs. They can be overridden |
| * by command-line options or %pragma. |
| */ |
| enum nasm_limit { |
| LIMIT_PASSES, |
| LIMIT_STALLED, |
| LIMIT_MACRO_LEVELS, |
| LIMIT_MACRO_TOKENS, |
| LIMIT_MMACROS, |
| LIMIT_REP, |
| LIMIT_EVAL, |
| LIMIT_LINES, |
| LIMIT_PARAMS, |
| LIMIT_MAX /* Must be at end */ |
| }; |
| |
| #define LIMIT_MAX_VAL (INT64_MAX >> 1) /* Absolute maximum for any limit */ |
| |
| extern int64_t nasm_limit[LIMIT_MAX]; |
| extern enum directive_result nasm_set_limit(const char *, const char *); |
| |
| enum get_limit_which { |
| GET_LIMIT_CURRENT, |
| GET_LIMIT_INIT, |
| GET_LIMIT_DEFAULT, |
| GET_LIMIT_MAX |
| }; |
| extern int64_t nasm_get_limit(const char *, enum get_limit_which); |
| extern const char *nasm_limit_name(enum nasm_limit); |
| |
| /* |
| * The data structure defining an output format driver, and the |
| * interfaces to the functions therein. |
| */ |
| struct ofmt { |
| /* |
| * This is a short (one-liner) description of the type of |
| * output generated by the driver. |
| */ |
| const char *fullname; |
| |
| /* |
| * This is a single keyword used to select the driver. |
| */ |
| const char *shortname; |
| |
| /* |
| * Default output filename extension, or a null string |
| */ |
| const char *extension; |
| |
| /* |
| * Output format flags. |
| */ |
| #define OFMT_TEXT 1 /* Text file format */ |
| #define OFMT_KEEP_ADDR 2 /* Keep addr; no conversion to data */ |
| #define OFMT_ZERODATA 4 /* "Native" OUT_ZERODATA support */ |
| |
| unsigned int flags; |
| |
| int maxbits; /* Maximum segment bits supported */ |
| |
| /* |
| * this is a pointer to the first element of the debug information |
| */ |
| const struct dfmt * const *debug_formats; |
| |
| /* |
| * the default debugging format if -F is not specified |
| */ |
| const struct dfmt *default_dfmt; |
| |
| /* |
| * This, if non-NULL, is a NULL-terminated list of `char *'s |
| * pointing to extra standard macros supplied by the object |
| * format (e.g. a sensible initial default value of __?SECT?__, |
| * and user-level equivalents for any format-specific |
| * directives). |
| */ |
| macros_t *stdmac; |
| |
| /* |
| * This procedure is called at the start of an output session to set |
| * up internal parameters. |
| */ |
| void (*init)(void); |
| |
| /* |
| * This procedure is called at the start of each pass. |
| */ |
| void (*reset)(void); |
| |
| /* |
| * This is the modern output function, which gets passed |
| * a struct out_data with much more information. See the |
| * definition of struct out_data. |
| */ |
| void (*output)(const struct out_data *data); |
| |
| /* |
| * This procedure is called once for every symbol defined in |
| * the module being assembled. It gives the name and value of |
| * the symbol, in NASM's terms, and indicates whether it has |
| * been declared to be global. Note that the parameter "name", |
| * when passed, will point to a piece of static storage |
| * allocated inside the label manager - it's safe to keep using |
| * that pointer, because the label manager doesn't clean up |
| * until after the output driver has. |
| * |
| * Values of `is_global' are: 0 means the symbol is local; 1 |
| * means the symbol is global; 2 means the symbol is common (in |
| * which case `offset' holds the _size_ of the variable). |
| * Anything else is available for the output driver to use |
| * internally. |
| * |
| * This routine explicitly _is_ allowed to call the label |
| * manager to define further symbols, if it wants to, even |
| * though it's been called _from_ the label manager. That much |
| * re-entrancy is guaranteed in the label manager. However, the |
| * label manager will in turn call this routine, so it should |
| * be prepared to be re-entrant itself. |
| * |
| * The `special' parameter contains special information passed |
| * through from the command that defined the label: it may have |
| * been an EXTERN, a COMMON or a GLOBAL. The distinction should |
| * be obvious to the output format from the other parameters. |
| */ |
| void (*symdef)(char *name, int32_t segment, int64_t offset, |
| int is_global, char *special); |
| |
| /* |
| * This procedure is called when the source code requests a |
| * segment change. It should return the corresponding segment |
| * _number_ for the name, or NO_SEG if the name is not a valid |
| * segment name. |
| * |
| * It may also be called with NULL, in which case it is to |
| * return the _default_ section number for starting assembly in. |
| * |
| * It is allowed to modify the string it is given a pointer to. |
| * |
| * It is also allowed to specify a default instruction size for |
| * the segment, by setting `*bits' to 16, 32 or 64. Or, if it |
| * doesn't wish to define a default, it can leave `bits' alone. |
| */ |
| int32_t (*section)(char *name, int *bits); |
| |
| /* |
| * This function is called when a label is defined |
| * in the source code. It is allowed to change the section |
| * number as a result, but not the bits value. |
| * This is *only* called if the symbol defined is at the |
| * current offset, i.e. "foo:" or "foo equ $". |
| * The offset isn't passed; and may not be stable at this point. |
| * The subsection number is a field available for use by the |
| * backend. It is initialized to NO_SEG. |
| * |
| * If "copyoffset" is set by the backend then the offset is |
| * copied from the previous segment, otherwise the new segment |
| * is treated as a new segment the normal way. |
| */ |
| int32_t (*herelabel)(const char *name, enum label_type type, |
| int32_t seg, int32_t *subsection, |
| bool *copyoffset); |
| |
| /* |
| * This procedure is called to modify section alignment, |
| * note there is a trick, the alignment can only increase |
| */ |
| void (*sectalign)(int32_t seg, unsigned int value); |
| |
| /* |
| * This procedure is called to modify the segment base values |
| * returned from the SEG operator. It is given a segment base |
| * value (i.e. a segment value with the low bit set), and is |
| * required to produce in return a segment value which may be |
| * different. It can map segment bases to absolute numbers by |
| * means of returning SEG_ABS types. |
| * |
| * It should return NO_SEG if the segment base cannot be |
| * determined; the evaluator (which calls this routine) is |
| * responsible for throwing an error condition if that occurs |
| * in pass two or in a critical expression. |
| */ |
| int32_t (*segbase)(int32_t segment); |
| |
| /* |
| * This procedure is called to allow the output driver to |
| * process its own specific directives. When called, it has the |
| * directive word in `directive' and the parameter string in |
| * `value'. |
| * |
| * The following values are (currently) possible for |
| * directive_result: |
| * |
| * 0 - DIRR_UNKNOWN - directive not recognized by backend |
| * 1 - DIRR_OK - directive processed ok |
| * 2 - DIRR_ERROR - backend printed its own error message |
| * 3 - DIRR_BADPARAM - print the generic message |
| * "invalid parameter to [*] directive" |
| * |
| * When called with "value" as NULL (as opposed to the empty |
| * string!), it should perform no action and not print any |
| * messages, but return DIRR_UNKNOWN if this directive is |
| * unsupported by the backend, DIRR_OK if it is, and either |
| * DIRR_ERROR or DIRR_BADPARAM if it *would* be supported by the |
| * backend if configured otherwise, but it would be invalid in the |
| * current context, regardless of the parameter(s). |
| * |
| * This is used by %ifdirective. |
| */ |
| enum directive_result |
| (*directive)(enum directive directive, char *value); |
| |
| /* |
| * This procedure is called after assembly finishes, to allow |
| * the output driver to clean itself up and free its memory. |
| * Typically, it will also be the point at which the object |
| * file actually gets _written_. |
| * |
| * One thing the cleanup routine should always do is to close |
| * the output file pointer. |
| */ |
| void (*cleanup)(void); |
| |
| /* |
| * List of pragma facility names that apply to this backend. |
| */ |
| const struct pragma_facility *pragmas; |
| }; |
| |
| /* |
| * Output format driver alias |
| */ |
| struct ofmt_alias { |
| const char *shortname; |
| const struct ofmt *ofmt; |
| }; |
| |
| extern const struct ofmt *ofmt; |
| extern FILE *ofile; |
| |
| /* |
| * ------------------------------------------------------------ |
| * The data structure defining a debug format driver, and the |
| * interfaces to the functions therein. |
| * ------------------------------------------------------------ |
| */ |
| struct debug_macro_info; |
| |
| struct dfmt { |
| /* |
| * This is a short (one-liner) description of the type of |
| * output generated by the driver. |
| */ |
| const char *fullname; |
| |
| /* |
| * This is a single keyword used to select the driver. |
| */ |
| const char *shortname; |
| |
| /* |
| * init - called initially to set up local pointer to object format. |
| */ |
| void (*init)(void); |
| |
| /* |
| * linenum - called any time there is output with a change of |
| * line number or file. |
| */ |
| void (*linenum)(const char *filename, int32_t linenumber, int32_t segto); |
| |
| /* |
| * debug_deflabel - called whenever a label is defined. Parameters |
| * are the same as to 'symdef()' in the output format. This function |
| * is called after the output format version. |
| */ |
| |
| void (*debug_deflabel)(char *name, int32_t segment, int64_t offset, |
| int is_global, char *special); |
| |
| /* |
| * debug_smacros - called when an smacro is defined or undefined |
| * during the code-generation pass. The definition string contains |
| * the macro name, any arguments, a single space, and the macro |
| * definition; this is what is expected by e.g. DWARF. |
| * |
| * The definition is provided even for an undef. |
| */ |
| void (*debug_smacros)(bool define, const char *def); |
| |
| /* |
| * debug_include - called when a file is included or the include |
| * is finished during the code-generation pass. The filename is |
| * kept by the srcfile system and so can be compared for pointer |
| * equality. |
| * |
| * A filename of NULL means builtin (initial or %use) or command |
| * line statements. |
| */ |
| void (*debug_include)(bool start, struct src_location outer, |
| struct src_location inner); |
| |
| /* |
| * debug_mmacros - called once at the end with a definition for each |
| * non-.nolist macro that has been invoked at least once in the program, |
| * and the corresponding address ranges. See dbginfo.h. |
| */ |
| void (*debug_mmacros)(const struct debug_macro_info *); |
| |
| /* |
| * debug_directive - called whenever a DEBUG directive other than 'LINE' |
| * is encountered. 'directive' contains the first parameter to the |
| * DEBUG directive, and params contains the rest. For example, |
| * 'DEBUG VAR _somevar:int' would translate to a call to this |
| * function with 'directive' equal to "VAR" and 'params' equal to |
| * "_somevar:int". |
| */ |
| void (*debug_directive)(const char *directive, const char *params); |
| |
| /* |
| * typevalue - called whenever the assembler wishes to register a type |
| * for the last defined label. This routine MUST detect if a type was |
| * already registered and not re-register it. |
| */ |
| void (*debug_typevalue)(int32_t type); |
| |
| /* |
| * debug_output - called whenever output is required |
| * 'type' is the type of info required, and this is format-specific |
| */ |
| void (*debug_output)(int type, void *param); |
| |
| /* |
| * cleanup - called after processing of file is complete |
| */ |
| void (*cleanup)(void); |
| |
| /* |
| * List of pragma facility names that apply to this backend. |
| */ |
| const struct pragma_facility *pragmas; |
| }; |
| |
| extern const struct dfmt *dfmt; |
| |
| /* |
| * The type definition macros |
| * for debugging |
| * |
| * low 3 bits: reserved |
| * next 5 bits: type |
| * next 24 bits: number of elements for arrays (0 for labels) |
| */ |
| |
| #define TY_UNKNOWN 0x00 |
| #define TY_LABEL 0x08 |
| #define TY_BYTE 0x10 |
| #define TY_WORD 0x18 |
| #define TY_DWORD 0x20 |
| #define TY_FLOAT 0x28 |
| #define TY_QWORD 0x30 |
| #define TY_TBYTE 0x38 |
| #define TY_OWORD 0x40 |
| #define TY_YWORD 0x48 |
| #define TY_ZWORD 0x50 |
| #define TY_COMMON 0xE0 |
| #define TY_SEG 0xE8 |
| #define TY_EXTERN 0xF0 |
| #define TY_EQU 0xF8 |
| |
| #define TYM_TYPE(x) ((x) & 0xF8) |
| #define TYM_ELEMENTS(x) (((x) & 0xFFFFFF00) >> 8) |
| |
| #define TYS_ELEMENTS(x) ((x) << 8) |
| |
| /* Sizes corresponding to various tokens */ |
| enum byte_sizes { |
| SIZE_BYTE = 1, |
| SIZE_WORD = 2, |
| SIZE_DWORD = 4, |
| SIZE_LONG = 4, |
| SIZE_QWORD = 8, |
| SIZE_TWORD = 10, |
| SIZE_OWORD = 16, |
| SIZE_YWORD = 32, |
| SIZE_ZWORD = 64 |
| }; |
| |
| enum special_tokens { |
| SIZE_ENUM_START = PREFIX_ENUM_LIMIT, |
| S_BYTE = SIZE_ENUM_START, |
| S_WORD, |
| S_DWORD, |
| S_LONG, |
| S_QWORD, |
| S_TWORD, |
| S_OWORD, |
| S_YWORD, |
| S_ZWORD, |
| SIZE_ENUM_LIMIT, |
| |
| SPECIAL_ENUM_START = SIZE_ENUM_LIMIT, |
| S_ABS = SPECIAL_ENUM_START, |
| S_FAR, |
| S_NEAR, |
| S_NOSPLIT, |
| S_REL, |
| S_SHORT, |
| S_STRICT, |
| S_TO, |
| SPECIAL_ENUM_LIMIT |
| }; |
| |
| enum decorator_tokens { |
| DECORATOR_ENUM_START = SPECIAL_ENUM_LIMIT, |
| BRC_1TO2 = DECORATOR_ENUM_START, |
| BRC_1TO4, |
| BRC_1TO8, |
| BRC_1TO16, |
| BRC_1TO32, |
| BRC_RN, |
| BRC_RD, |
| BRC_RU, |
| BRC_RZ, |
| BRC_SAE, |
| BRC_Z, |
| DECORATOR_ENUM_LIMIT |
| }; |
| |
| /* |
| * AVX512 Decorator (decoflags_t) bits distribution (counted from 0) |
| * 3 2 1 |
| * 10987654321098765432109876543210 |
| * | |
| * | word boundary |
| * ............................1111 opmask |
| * ...........................1.... zeroing / merging |
| * ..........................1..... broadcast |
| * .........................1...... static rounding |
| * ........................1....... SAE |
| * ....................1111........ broadcast element size |
| * .................111............ number of broadcast elements |
| */ |
| #define OP_GENVAL(val, bits, shift) (((val) & ((UINT64_C(1) << (bits)) - 1)) << (shift)) |
| |
| /* |
| * Opmask register number |
| * identical to EVEX.aaa |
| * |
| * Bits: 0 - 3 |
| */ |
| #define OPMASK_SHIFT (0) |
| #define OPMASK_BITS (4) |
| #define OPMASK_MASK OP_GENMASK(OPMASK_BITS, OPMASK_SHIFT) |
| #define GEN_OPMASK(bit) OP_GENBIT(bit, OPMASK_SHIFT) |
| #define VAL_OPMASK(val) OP_GENVAL(val, OPMASK_BITS, OPMASK_SHIFT) |
| |
| /* |
| * zeroing / merging control available |
| * matching to EVEX.z |
| * |
| * Bits: 4 |
| */ |
| #define Z_SHIFT (4) |
| #define Z_BITS (1) |
| #define Z_MASK OP_GENMASK(Z_BITS, Z_SHIFT) |
| #define GEN_Z(bit) OP_GENBIT(bit, Z_SHIFT) |
| |
| /* |
| * broadcast - Whether this operand can be broadcasted |
| * |
| * Bits: 5 |
| */ |
| #define BRDCAST_SHIFT (5) |
| #define BRDCAST_BITS (1) |
| #define BRDCAST_MASK OP_GENMASK(BRDCAST_BITS, BRDCAST_SHIFT) |
| #define GEN_BRDCAST(bit) OP_GENBIT(bit, BRDCAST_SHIFT) |
| |
| /* |
| * Whether this instruction can have a static rounding mode. |
| * It goes with the last simd operand because the static rounding mode |
| * decorator is located between the last simd operand and imm8 (if any). |
| * |
| * Bits: 6 |
| */ |
| #define STATICRND_SHIFT (6) |
| #define STATICRND_BITS (1) |
| #define STATICRND_MASK OP_GENMASK(STATICRND_BITS, STATICRND_SHIFT) |
| #define GEN_STATICRND(bit) OP_GENBIT(bit, STATICRND_SHIFT) |
| |
| /* |
| * SAE(Suppress all exception) available |
| * |
| * Bits: 7 |
| */ |
| #define SAE_SHIFT (7) |
| #define SAE_BITS (1) |
| #define SAE_MASK OP_GENMASK(SAE_BITS, SAE_SHIFT) |
| #define GEN_SAE(bit) OP_GENBIT(bit, SAE_SHIFT) |
| |
| /* |
| * Broadcasting element size. |
| * |
| * Bits: 8 - 11 |
| */ |
| #define BRSIZE_SHIFT (8) |
| #define BRSIZE_BITS (4) |
| #define BRSIZE_MASK OP_GENMASK(BRSIZE_BITS, BRSIZE_SHIFT) |
| #define GEN_BRSIZE(bit) OP_GENBIT(bit, BRSIZE_SHIFT) |
| |
| #define BR_BITS8 GEN_BRSIZE(0) /* For potential future use */ |
| #define BR_BITS16 GEN_BRSIZE(1) |
| #define BR_BITS32 GEN_BRSIZE(2) |
| #define BR_BITS64 GEN_BRSIZE(3) |
| |
| /* |
| * Number of broadcasting elements |
| * |
| * Bits: 12 - 14 |
| */ |
| #define BRNUM_SHIFT (12) |
| #define BRNUM_BITS (3) |
| #define BRNUM_MASK OP_GENMASK(BRNUM_BITS, BRNUM_SHIFT) |
| #define VAL_BRNUM(val) OP_GENVAL(val, BRNUM_BITS, BRNUM_SHIFT) |
| |
| #define BR_1TO2 VAL_BRNUM(0) |
| #define BR_1TO4 VAL_BRNUM(1) |
| #define BR_1TO8 VAL_BRNUM(2) |
| #define BR_1TO16 VAL_BRNUM(3) |
| #define BR_1TO32 VAL_BRNUM(4) |
| #define BR_1TO64 VAL_BRNUM(5) /* For potential future use */ |
| |
| #define MASK OPMASK_MASK /* Opmask (k1 ~ 7) can be used */ |
| #define Z Z_MASK |
| #define B16 (BRDCAST_MASK|BR_BITS16) /* {1to32} : broadcast 16b * 32 to zmm(512b) */ |
| #define B32 (BRDCAST_MASK|BR_BITS32) /* {1to16} : broadcast 32b * 16 to zmm(512b) */ |
| #define B64 (BRDCAST_MASK|BR_BITS64) /* {1to8} : broadcast 64b * 8 to zmm(512b) */ |
| #define ER STATICRND_MASK /* ER(Embedded Rounding) == Static rounding mode */ |
| #define SAE SAE_MASK /* SAE(Suppress All Exception) */ |
| |
| /* |
| * Broadcast flags (BR_BITS*) to sizes (BITS*) |
| */ |
| static inline opflags_t brsize_to_size(opflags_t brbits) |
| { |
| return (brbits & BRSIZE_MASK) << (SIZE_SHIFT - BRSIZE_SHIFT); |
| } |
| |
| /* |
| * Global modes |
| */ |
| |
| /* |
| * Various types of compiler passes we may execute. |
| * If these are changed, you need to also change _pass_types[] |
| * in asm/nasm.c. |
| */ |
| enum pass_type { |
| PASS_INIT, /* Initialization, not doing anything yet */ |
| PASS_PREPROC, /* Preprocess-only mode (similar to PASS_FIRST) */ |
| PASS_FIRST, /* The very first pass over the code */ |
| PASS_OPT, /* Optimization pass */ |
| PASS_STAB, /* Stabilization pass (original pass 1) */ |
| PASS_FINAL /* Code generation pass (original pass 2) */ |
| }; |
| extern const char * const _pass_types[]; |
| extern enum pass_type _pass_type; |
| static inline enum pass_type pass_type(void) |
| { |
| return _pass_type; |
| } |
| static inline const char *pass_type_name(void) |
| { |
| return _pass_types[_pass_type]; |
| } |
| /* True during initialization, no code read yet */ |
| static inline bool not_started(void) |
| { |
| return pass_type() == PASS_INIT; |
| } |
| /* True for the initial pass and setup (old "pass2 < 2") */ |
| static inline bool pass_first(void) |
| { |
| return pass_type() <= PASS_FIRST; |
| } |
| /* At this point we better have stable definitions */ |
| static inline bool pass_stable(void) |
| { |
| return pass_type() >= PASS_STAB; |
| } |
| /* True for the code generation pass only, (old "pass1 >= 2") */ |
| static inline bool pass_final(void) |
| { |
| return pass_type() >= PASS_FINAL; |
| } |
| /* True for code generation *or* preprocess-only mode */ |
| static inline bool pass_final_or_preproc(void) |
| { |
| return pass_type() >= PASS_FINAL || pass_type() == PASS_PREPROC; |
| } |
| |
| /* |
| * The actual pass number. 0 is used during initialization, the very |
| * first pass is 1, and then it is simply increasing numbers until we are |
| * done. |
| */ |
| extern int64_t _passn; /* Actual pass number */ |
| static inline int64_t pass_count(void) |
| { |
| return _passn; |
| } |
| |
| extern enum optimization optimizing; |
| |
| /* Pass-wide state; reset on top of each pass */ |
| struct globalopt { |
| int bits; /* 16, 32 or 64-bit mode */ |
| enum ea_flags rel; /* default to relative addressing? */ |
| enum ea_flags reldef; /* default rel/abs explicitly defined? */ |
| bool bnd; /* default to using bnd prefix? */ |
| bool dollarhex; /* $-prefixed hexadecimal numbers? */ |
| }; |
| extern struct globalopt globl; |
| void reset_global_defaults(int bits); |
| |
| extern const char *inname; /* primary input filename */ |
| extern const char *outname; /* output filename */ |
| |
| /* |
| * Switch to a different segment and return the current offset |
| */ |
| int64_t switch_segment(int32_t segment); |
| |
| #endif /* NASM_NASM_H */ |