diff --git a/asm/assemble.c b/asm/assemble.c index 897345309..205e36df5 100644 --- a/asm/assemble.c +++ b/asm/assemble.c @@ -113,6 +113,7 @@ static uint32_t rexflags(int, opflags_t, uint32_t); static uint32_t op_rexflags(const operand *, uint32_t); static uint32_t op_evexflags(const operand *, uint32_t); static void add_asp(insn *); +static void set_initial_opsize(insn *); static int process_ea(operand *input, int rfield, opflags_t rflags, insn *ins, enum ea_type expected, @@ -945,6 +946,9 @@ int64_t assemble(insn *instruction) /* Check to see if we need an address-size prefix */ add_asp(instruction); + /* Set default/prefix-controlled operand size */ + set_initial_opsize(instruction); + m = find_match(&temp, instruction); if (m >= MOK_GOOD) { @@ -1785,7 +1789,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp) } case 0334: - ins->rex |= REX_L; + ins->rex |= REX_L; /* Ignored in 64-bit mode */ break; case 0335: @@ -2934,11 +2938,15 @@ static enum match_result matches(const struct itemplate * const itemp, unsigned int arflag; unsigned int armask, smmask; bool if_anysize, if_sx; - opflags_t arsize, smsize; + opflags_t opsize, arsize, smsize; opflags_t isize[MAX_OPERANDS]; /* Adjusted instruction operand sizes */ opflags_t tsize[MAX_OPERANDS]; /* Adjusted template operand sizes */ opflags_t itype[MAX_OPERANDS]; /* Adjusted instruction flags */ + /* Jump size/type declarators are more like types than sizes */ + const opflags_t jsize_mask = NEAR|FAR|SHORT|ABS; + const opflags_t msize_mask = SIZE_MASK & ~jsize_mask; + /* * Check the opcode */ @@ -3012,7 +3020,7 @@ static enum match_result matches(const struct itemplate * const itemp, const struct operand * const op = &ins->oprs[i]; const opflags_t ttype = itemp->opd[i]; - isize[i] = op->type & SIZE_MASK; + isize[i] = op->type & msize_mask; itype[i] = op->type - isize[i]; if (op->type & ~ttype & (COLON | TO)) return MERR_INVALOP; @@ -3020,6 +3028,15 @@ static enum match_result matches(const struct itemplate * const itemp, return MERR_WRONGIMM; } + /* "Default" operand size (from mode and prefixes only) */ + opsize = mode_to_op(ins->op_size); + if (itemp_has(itemp, IF_NWSIZE) && bits == 64 && opsize == BITS32) + opsize = BITS64; + + /* Some key flags */ + if_anysize = itemp_has(itemp, IF_ANYSIZE); + if_sx = itemp_has(itemp, IF_SX); + /* * Compare various operand flags that don't depend on sizes, * and compute the "true" template operand sizes. @@ -3030,8 +3047,8 @@ static enum match_result matches(const struct itemplate * const itemp, const decoflags_t ideco = itemp->deco[i]; const bool is_broadcast = deco & BRDCAST_MASK; - if (!is_broadcast) { - tsize[i] = ttype & SIZE_MASK; + if (likely(!is_broadcast)) { + tsize[i] = ttype & msize_mask; } else { const decoflags_t ideco_brsize = ideco & BRSIZE_MASK; @@ -3048,12 +3065,32 @@ static enum match_result matches(const struct itemplate * const itemp, tsize[i] = 0; /* Is this even possible? */ } + /* Handle implied SHORT or NEAR */ + if (unlikely(ttype & (NEAR|SHORT))) { + if ((ttype & (NEAR|SHORT)) == (NEAR|SHORT)) { + /* Only a short form exists; allow both NEAR and SHORT */ + if (!(itype[i] & (FAR|ABS))) + itype[i] |= NEAR|SHORT; + } else if ((itype[i] & SHORT) || isize[i] == BITS8) { + /* An explicit SHORT or BITS8 cancel NEAR; are synonyms */ + itype[i] &= ~NEAR; + if (!isize[i]) + isize[i] = BITS8; + } else if (!(itype[i] & (FAR|ABS|SHORT))) { + /* NEAR is implicit unless otherwise specified */ + itype[i] |= ttype & NEAR; + } + } + /* Check to see if we need to coerce an explicitly sized immediate */ if (unlikely(itype[i] & ttype & IMMEDIATE)) { /* * If this is an *explicitly* sized immediate, * allow it to match an extending pattern. + * + * Handle sizing of SHORT/NEAR here, too. */ + switch (isize[i]) { case BITS8: if (ttype & BYTEEXTMASK) { @@ -3077,7 +3114,7 @@ static enum match_result matches(const struct itemplate * const itemp, itype[i] |= SDWORD; } - if (ttype & ~itype[i] & ~(SIZE_MASK|REGSET_MASK)) + if (ttype & ~itype[i] & ~(msize_mask|REGSET_MASK)) return MERR_INVALOP; if (~ideco & deco & OPMASK_MASK) @@ -3098,35 +3135,33 @@ static enum match_result matches(const struct itemplate * const itemp, nasm_static_assert(SIZE_SHIFT >= IF_SB); nasm_static_assert((BITS8 >> SIZE_SHIFT) == 1); - arsize = (arflag & (IFM_SB|IFM_SW|IFM_SD|IFM_SQ| - IFM_ST|IFM_SO|IFM_SY|IFM_SZ)) - << (SIZE_SHIFT - IF_SB); + arsize = (arflag & IF_TSMASK) << (SIZE_SHIFT - IF_SB); - if (arflag & IFM_SIZE) - arsize = mode_to_op(bits); - - if_anysize = itemp_has(itemp, IF_ANYSIZE); - if_sx = itemp_has(itemp, IF_SX); + if (arflag & IFM_OSIZE) + arsize = opsize; + else if (arflag & IFM_ASIZE) + arsize = mode_to_op(ins->addr_size); /* Flags for which the AR and SM flags apply */ armask = itemp_arx(itemp); smmask = itemp_smx(itemp); /* Apply ARx sizes and handle size coersion */ - for (i = 0; i < oprs; i++) { - const unsigned int bit = 1U << i; + if (!if_sx) { + for (i = 0; i < oprs; i++) { + const unsigned int bit = 1U << i; - if (!isize[i] && is_class(REGISTER, itype[i])) - isize[i] = tsize[i]; - - if (armask & bit) { - if (!isize[i] && !if_sx) - isize[i] = arsize; + if (!isize[i]) { + if (is_class(REGISTER, itype[i]) && tsize[i]) + isize[i] = tsize[i]; + else if (armask & bit) + isize[i] = arsize; + } } } /* Look the common subset for the size-matched operands */ - smsize = SIZE_MASK; + smsize = msize_mask; if (smmask) { unsigned int nosizemask = 0; for (i = 0; i < oprs; i++) { @@ -3924,6 +3959,33 @@ static void add_asp(insn *ins) } } +/* + * Set the initial operand size, based only on the mode and any prefixes. + * The actual operand size may change after instruction pattern selection. + */ +static void set_initial_opsize(insn *ins) +{ + const int bits = ins->bits; + + switch (ins->prefixes[PPS_OSIZE]) { + case P_OSP: + ins->op_size = bits == 16 ? 32 : 16; + break; + case P_O16: + ins->op_size = 16; + break; + case P_O32: + ins->op_size = 32; + break; + case P_O64: + ins->op_size = 64; + break; + default: + ins->op_size = bits == 16 ? 16 : 32; + break; + } +} + /* * This is the main entry point to this module, called from asm/nasm.c. */ diff --git a/asm/exprlib.c b/asm/exprlib.c index f7cfbceed..f689ffb6d 100644 --- a/asm/exprlib.c +++ b/asm/exprlib.c @@ -79,6 +79,57 @@ bool is_really_simple(const expr *vect) return true; } +/* + * Classify an expression based on its components + */ +enum expr_classes expr_class(const expr *vect) +{ + enum expr_classes class = EC_ZERO; + + for (; vect->type; vect++) { + if (!vect->value) { + /* Value-0 term */ + } else if (vect->type < EXPR_UNKNOWN) { + if ((class & EC_REGISTER) || vect->value != 1) + class |= EC_REGEXPR; + else + class |= EC_REGISTER; + } else if (vect->type == EXPR_UNKNOWN) { + class |= EC_UNKNOWN; + } else if (vect->type == EXPR_SIMPLE) { + /* Pure number term */ + class |= EC_CONST; + } else if (vect->type == EXPR_WRT) { + class |= EC_WRT; + } else if (vect->type < EXPR_SEGBASE) { + class |= EC_COMPLEX; + } else if (vect->type >= EXPR_SEGBASE + SEG_ABS) { + /* It is an absolute segment */ + if (class & (EC_SEG|EC_SEGABS)) + class |= EC_COMPLEX; + class |= EC_SEGABS; + } else { + /* It is a segment */ + if (vect->value == 1) { + if (class & (EC_SEG|EC_SEGABS)) + class |= EC_COMPLEX; + class |= EC_SEG; + } else if (vect->value == -1) { + /* can only subtract current segment, and only once */ + if (vect->type != location.segment + EXPR_SEGBASE || + (class & EC_SELFREL)) + class |= EC_COMPLEX; + class |= EC_SELFREL; + } else { + /* Non-simple segment arithmetic */ + class |= EC_COMPLEX; + } + } + } + + return class; +} + /* * Return true if the argument is relocatable (i.e. a simple * scalar, plus at most one segment-base, possibly a subtraction @@ -86,39 +137,7 @@ bool is_really_simple(const expr *vect) */ bool is_reloc(const expr *vect) { - bool has_rel = false; /* Has a self-segment-subtract */ - bool has_seg = false; /* Has a segment base */ - - for (; vect->type; vect++) { - if (!vect->value) { - /* skip value-0 terms */ - continue; - } else if (vect->type < EXPR_SIMPLE) { - /* false if a register is present */ - return false; - } else if (vect->type == EXPR_SIMPLE) { - /* skip over a pure number term... */ - continue; - } else if (vect->type == EXPR_WRT) { - /* skip over a WRT term... */ - continue; - } else if (vect->type < EXPR_SEGBASE) { - /* other special type -> problem */ - return false; - } else if (vect->value == 1) { - if (has_seg) - return false; /* only one segbase allowed */ - has_seg = true; - } else if (vect->value == -1) { - if (vect->type != location.segment + EXPR_SEGBASE) - return false; /* can only subtract current segment */ - if (has_rel) - return false; /* already is relative */ - has_rel = true; - } - } - - return true; + return !(expr_class(vect) & ~EC_RELOC); } /* @@ -126,9 +145,7 @@ bool is_reloc(const expr *vect) */ bool is_unknown(const expr *vect) { - while (vect->type && vect->type < EXPR_UNKNOWN) - vect++; - return (vect->type == EXPR_UNKNOWN); + return !!(expr_class(vect) & EC_UNKNOWN); } /* @@ -137,9 +154,7 @@ bool is_unknown(const expr *vect) */ bool is_just_unknown(const expr *vect) { - while (vect->type && !vect->value) - vect++; - return (vect->type == EXPR_UNKNOWN); + return expr_class(vect) == EC_UNKNOWN; } /* @@ -191,10 +206,5 @@ int32_t reloc_wrt(const expr *vect) */ bool is_self_relative(const expr *vect) { - for (; vect->type; vect++) { - if (vect->type == location.segment + EXPR_SEGBASE && vect->value == -1) - return true; - } - - return false; + return !!(expr_class(vect) & EC_SELFREL); } diff --git a/asm/floats.h b/asm/floats.h index c46351369..ebf001ed9 100644 --- a/asm/floats.h +++ b/asm/floats.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 1996-2020 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. @@ -14,7 +14,7 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF @@ -31,7 +31,7 @@ * * ----------------------------------------------------------------------- */ -/* +/* * floats.h header file for the floating-point constant module of * the Netwide Assembler */ @@ -61,7 +61,7 @@ struct ieee_format { extern const struct ieee_format fp_formats[FLOAT_ERR]; int float_const(const char *str, int s, uint8_t *result, enum floatize ffmt); -enum floatize float_deffmt(int bytes); +enum floatize const_func float_deffmt(int bytes); int float_option(const char *option); #endif /* NASM_FLOATS_H */ diff --git a/asm/nasm.c b/asm/nasm.c index 1ba0694d8..8924f0132 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -1776,7 +1776,7 @@ static void assemble_file(const char *fname, struct strlist *depend_list) /** * get warning index; 0 if this is non-suppressible. */ -static size_t warn_index(errflags severity) +static size_t pure_func warn_index(errflags severity) { size_t index; @@ -1853,7 +1853,7 @@ static bool is_suppressed(errflags severity) * @param severity the severity of the warning or error * @return true if we should error out */ -static errflags true_error_type(errflags severity) +static errflags pure_func true_error_type(errflags severity) { const uint8_t warn_is_err = WARN_ST_ENABLED|WARN_ST_ERROR; int type; diff --git a/asm/parser.c b/asm/parser.c index 747f08e17..2cedc4cf5 100644 --- a/asm/parser.c +++ b/asm/parser.c @@ -1230,27 +1230,39 @@ restart_parse: nasm_nonfatal("invalid use of FAR operand specifier"); recover = true; } else { /* it's not a memory reference */ - if (is_just_unknown(value)) { /* it's immediate but unknown */ - op->type |= IMM_NORMAL; - op->opflags |= OPFLAG_UNKNOWN; - op->offset = 0; /* don't care */ - op->segment = NO_SEG; /* don't care again */ - op->wrt = NO_SEG; /* still don't care */ + const enum expr_classes eclass = expr_class(value); - set_imm_flags(op, result->opt); - } else if (is_reloc(value)) { /* it's immediate */ - uint64_t n = reloc_value(value); - - op->type |= IMM_NORMAL; - op->offset = n; + if (!(eclass & ~(EC_RELOC | EC_UNKNOWN))) { + /* It is an immediate */ + op->offset = reloc_value(value); op->segment = reloc_seg(value); op->wrt = reloc_wrt(value); - if (is_self_relative(value)) + if (eclass & EC_SELFREL) op->opflags |= OPFLAG_RELATIVE; - if (is_simple(value)) + if (!(eclass & ~EC_SIMPLE)) op->opflags |= OPFLAG_SIMPLE; + if (eclass & EC_UNKNOWN) + op->opflags |= OPFLAG_UNKNOWN; + op->type |= IMM_NORMAL; set_imm_flags(op, result->opt); + + /* + * Special hack: if the previous operand was a colon + * immediate operand with an explicit size, and this + * one does not have an explicit size, move the size + * specifier to this operand. This handles the case: + * "jmp dword foo:bar" (really being "jmp foo:dword bar".) + */ + if (opnum > 0 && + unlikely(is_class(op[-1].type, IMM_NORMAL|COLON))) { + opflags_t nsize = op->type & SIZE_MASK; + opflags_t osize = op[-1].type & SIZE_MASK; + if (osize && !nsize) { + op->type ^= osize; + op[-1].type ^= osize; + } + } } else if (value->type == EXPR_RDSAE) { /* * it's not an operand but a rounding or SAE decorator. @@ -1316,7 +1328,7 @@ restart_parse: * we want to produce a warning iff the specified size * is different from the register size */ - rs = op->type & SIZE_MASK; + rs = op->type & (SIZE_MASK & ~NEAR); } else { rs = 0; } @@ -1346,7 +1358,7 @@ restart_parse: op->basereg = value->type; if (rs) { - opflags_t opsize = nasm_reg_flags[value->type] & SIZE_MASK; + opflags_t opsize = nasm_reg_flags[value->type] & (SIZE_MASK & ~NEAR); if (!opsize) { op->type |= rs; /* For non-size-specific registers, permit size override */ } else if (opsize != rs) { diff --git a/asm/stdscan.h b/asm/stdscan.h index 1893cd9f8..5cd399fad 100644 --- a/asm/stdscan.h +++ b/asm/stdscan.h @@ -43,7 +43,7 @@ struct stdscan_state; void stdscan_set(const struct stdscan_state *); const struct stdscan_state *stdscan_get(void); -char *stdscan_tell(void); +char * pure_func stdscan_tell(void); void stdscan_reset(char *buffer); int stdscan(void *pvt, struct tokenval *tv); void stdscan_pushback(const struct tokenval *tv); diff --git a/autoconf/m4/pa_add_flags.m4 b/autoconf/m4/pa_add_flags.m4 index 23f96f126..c7fb76560 100644 --- a/autoconf/m4/pa_add_flags.m4 +++ b/autoconf/m4/pa_add_flags.m4 @@ -1,9 +1,10 @@ dnl -------------------------------------------------------------------------- -dnl PA_ADD_FLAGS(flagvar, flags) +dnl PA_ADD_FLAGS(flagvar, flags [, real-flags [, success [, failure]]]) dnl -dnl Add [flags] to the variable [flagvar] if and only if it is accepted -dnl by all languages affected by [flagvar], if those languages have -dnl been previously seen in the script. +dnl Add [real-flags] (default [flags]) to the variable [flagvar] if +dnl and only if [flags] are accepted by all languages affected by +dnl [flagvar], if those languages have been previously seen in the +dnl script. dnl -------------------------------------------------------------------------- AC_DEFUN([PA_ADD_FLAGS], [ diff --git a/autoconf/m4/pa_common_attributes.m4 b/autoconf/m4/pa_common_attributes.m4 index 8b8dc9e34..0594f3e11 100644 --- a/autoconf/m4/pa_common_attributes.m4 +++ b/autoconf/m4/pa_common_attributes.m4 @@ -15,5 +15,6 @@ AC_DEFUN([PA_COMMON_ATTRIBUTES], PA_FUNC_ATTRIBUTE(const) PA_FUNC_ATTRIBUTE(pure) PA_FUNC_ATTRIBUTE(cold,,,,,unlikely_func) + PA_FUNC_ATTRIBUTE(used) PA_FUNC_ATTRIBUTE(unused) PA_FUNC_ATTRIBUTE_ERROR]) diff --git a/autoconf/m4/pa_option_debug.m4 b/autoconf/m4/pa_option_debug.m4 index ae7d9db89..0c9dd3729 100644 --- a/autoconf/m4/pa_option_debug.m4 +++ b/autoconf/m4/pa_option_debug.m4 @@ -9,5 +9,7 @@ AC_DEFUN([PA_OPTION_DEBUG], [PA_ADD_LANGFLAGS([-g3])], [PA_ADD_LANGFLAGS([-ggdb3 -g3])]) PA_ARG_ENABLED([debug], [optimize for debugging], [PA_ADD_LANGFLAGS([-Og -O0]) + AC_DEFINE([WITH_DEBUG], 1, + [Define to 1 to include code specifically indended to help debugging.]) $1], [$2])]) diff --git a/autoconf/m4/pa_option_profiling.m4 b/autoconf/m4/pa_option_profiling.m4 index 39a3f6cf7..fb409e42d 100644 --- a/autoconf/m4/pa_option_profiling.m4 +++ b/autoconf/m4/pa_option_profiling.m4 @@ -5,4 +5,7 @@ dnl Try to enable profiling if --enable-profiling is set. dnl -------------------------------------------------------------------------- AC_DEFUN([PA_OPTION_PROFILING], [PA_ARG_ENABLED([profiling], [compile with profiling (-pg option)], -[PA_ADD_LANGFLAGS([-pg])])]) +[PA_ADD_LANGFLAGS([-pg]) + AC_DEFINE([WITH_PROFILING], 1, + [Define to 1 to include code specifically indended to help profiling.]) +])]) diff --git a/config/unconfig.h b/config/unconfig.h index 3afcb2064..3713ecfa7 100644 --- a/config/unconfig.h +++ b/config/unconfig.h @@ -107,6 +107,22 @@ # endif #endif +#ifndef used_func +# ifdef HAVE_FUNC_ATTRIBUTE_USED +# define used_func ATTRIBUTE(used) +# else +# define used_func +# endif +#endif + +#ifndef used_func_ptr +# ifdef HAVE_FUNC_PTR_ATTRIBUTE_USED +# define used_func_ptr ATTRIBUTE(used) +# else +# define used_func_ptr +# endif +#endif + #ifndef unused_func # ifdef HAVE_FUNC_ATTRIBUTE_UNUSED # define unused_func ATTRIBUTE(unused) diff --git a/include/compiler.h b/include/compiler.h index 607f68210..62ed65307 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -168,7 +168,7 @@ size_t strlcpy(char *, const char *, size_t); #endif #if !defined(HAVE_STRCHRNUL) || !HAVE_DECL_STRCHRNUL -char *strrchrnul(const char *, int); +char * pure_func strrchrnul(const char *, int); #endif #ifndef __cplusplus /* C++ has false, true, bool as keywords */ diff --git a/include/hashtbl.h b/include/hashtbl.h index 9ea94dcbc..af5d67552 100644 --- a/include/hashtbl.h +++ b/include/hashtbl.h @@ -67,10 +67,10 @@ struct hash_iterator { const struct hash_node *next; }; -uint64_t crc64(uint64_t crc, const char *string); -uint64_t crc64i(uint64_t crc, const char *string); -uint64_t crc64b(uint64_t crc, const void *data, size_t len); -uint64_t crc64ib(uint64_t crc, const void *data, size_t len); +uint64_t pure_func crc64(uint64_t crc, const char *string); +uint64_t pure_func crc64i(uint64_t crc, const char *string); +uint64_t pure_func crc64b(uint64_t crc, const void *data, size_t len); +uint64_t pure_func crc64ib(uint64_t crc, const void *data, size_t len); #define CRC64_INIT UINT64_C(0xffffffffffffffff) static inline uint64_t crc64_byte(uint64_t crc, uint8_t v) @@ -79,7 +79,7 @@ static inline uint64_t crc64_byte(uint64_t crc, uint8_t v) return crc64_tab[(uint8_t)(v ^ crc)] ^ (crc >> 8); } -uint32_t crc32b(uint32_t crc, const void *data, size_t len); +uint32_t pure_func crc32b(uint32_t crc, const void *data, size_t len); void **hash_find(struct hash_table *head, const char *string, struct hash_insert *insert); diff --git a/include/iflag.h b/include/iflag.h index 9413dece4..ef376421e 100644 --- a/include/iflag.h +++ b/include/iflag.h @@ -71,8 +71,11 @@ static inline int iflag_cmp(const iflag_t *a, const iflag_t *b) IF_GEN_HELPER(xor, ^) /* Some helpers which are to work with predefined masks */ -#define IF_SMASK (IFM_SB|IFM_SW|IFM_SD|IFM_SQ|IFM_ST|IFM_SO|\ - IFM_SY|IFM_SZ|IFM_SIZE|IFM_ANYSIZE|IFM_SX) +/* TSMASK = "True size" mask */ +#define IF_TSMASK (IFM_SB|IFM_SW|IFM_SD|IFM_SQ|IFM_ST|IFM_SO|\ + IFM_SY|IFM_SZ) +#define IF_SMASK (IF_TSMASK|IFM_NWSIZE|IFM_OSIZE|IFM_ASIZE|\ + IFM_ANYSIZE|IFM_SX) #define IF_ARMASK (IFM_AR0|IFM_AR1|IFM_AR2|IFM_AR3|IFM_AR4) #define IF_SMMASK (IFM_SM0|IFM_SM1|IFM_SM2|IFM_SM3|IFM_SM4) diff --git a/include/nasm.h b/include/nasm.h index 6243dc4ae..961af7c86 100644 --- a/include/nasm.h +++ b/include/nasm.h @@ -368,6 +368,22 @@ typedef struct { /* * 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); diff --git a/include/nasmlib.h b/include/nasmlib.h index 62e172665..6488effaf 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -364,14 +364,14 @@ void fwriteaddr(uint64_t data, int size, FILE * fp); * * bsi() is case sensitive, bsii() is case insensitive. */ -int bsi(const char *string, const char **array, int size); -int bsii(const char *string, const char **array, int size); +int pure_func bsi(const char *string, const char **array, int size); +int pure_func bsii(const char *string, const char **array, int size); /* * Convenient string processing helper routines */ -char *nasm_skip_spaces(const char *p); -char *nasm_skip_word(const char *p); +char * pure_func nasm_skip_spaces(const char *p); +char * pure_func nasm_skip_word(const char *p); char *nasm_zap_spaces_fwd(char *p); char *nasm_zap_spaces_rev(char *p); char *nasm_trim_spaces(char *p); @@ -395,8 +395,8 @@ char * safe_alloc nasm_catfile(const char *dir, const char *path); /* * Various tokens to readable strings, with limit checking */ -const char * pure_func register_name(int); -const char * pure_func prefix_name(int); +const char * const_func register_name(int); +const char * const_func prefix_name(int); bool const_func is_hint_nop(uint64_t); /* diff --git a/include/perfhash.h b/include/perfhash.h index 43e536c1f..f61d7d749 100644 --- a/include/perfhash.h +++ b/include/perfhash.h @@ -47,6 +47,6 @@ struct perfect_hash { const char * const *strings; }; -int perfhash_find(const struct perfect_hash *, const char *); +int pure_func perfhash_find(const struct perfect_hash *, const char *); #endif /* PERFHASH_H */ diff --git a/include/raa.h b/include/raa.h index e08d90bcb..c374d81c0 100644 --- a/include/raa.h +++ b/include/raa.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 1996-2009 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. @@ -14,7 +14,7 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF @@ -41,8 +41,8 @@ typedef uint64_t raaindex; #define raa_init() NULL void raa_free(struct RAA *); -int64_t raa_read(struct RAA *, raaindex); -void *raa_read_ptr(struct RAA *, raaindex); +int64_t pure_func raa_read(struct RAA *, raaindex); +void * pure_func raa_read_ptr(struct RAA *, raaindex); struct RAA * never_null raa_write(struct RAA *r, raaindex posn, int64_t value); struct RAA * never_null raa_write_ptr(struct RAA *r, raaindex posn, void *value); diff --git a/include/rbtree.h b/include/rbtree.h index 39d45affe..9ad0fa686 100644 --- a/include/rbtree.h +++ b/include/rbtree.h @@ -70,27 +70,27 @@ struct rbtree *rb_insert(struct rbtree *, struct rbtree *); * Find a node in the tree corresponding to the key immediately * <= the passed-in key value. */ -struct rbtree *rb_search(const struct rbtree *, uint64_t); +struct rbtree * pure_func rb_search(const struct rbtree *, uint64_t); /* * Find a node in the tree exactly matching the key value. */ -struct rbtree *rb_search_exact(const struct rbtree *, uint64_t); +struct rbtree * pure_func rb_search_exact(const struct rbtree *, uint64_t); /* * Return the immediately previous or next node in key order. * Returns NULL if this node is the end of the tree. - * These operations are safe for complee (but not partial!) + * These operations are safe for complete (but not partial!) * tree walk-with-destruction in key order. */ -struct rbtree *rb_prev(const struct rbtree *); -struct rbtree *rb_next(const struct rbtree *); +struct rbtree * pure_func rb_prev(const struct rbtree *); +struct rbtree * pure_func rb_next(const struct rbtree *); /* * Return the very first or very last node in key order. */ -struct rbtree *rb_first(const struct rbtree *); -struct rbtree *rb_last(const struct rbtree *); +struct rbtree * pure_func rb_first(const struct rbtree *); +struct rbtree * pure_func rb_last(const struct rbtree *); /* * Left and right nodes, if real. These operations are diff --git a/include/tables.h b/include/tables.h index 2b36357e2..9341746c9 100644 --- a/include/tables.h +++ b/include/tables.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 1996-2016 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. @@ -14,7 +14,7 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF @@ -55,7 +55,7 @@ struct use_package { const unsigned char *macros; int index; }; -extern const struct use_package *nasm_find_use_package(const char *); +extern const struct use_package * pure_func nasm_find_use_package(const char *); extern const int use_package_count; /* --- From insns.dat via insns.pl: --- */ diff --git a/include/ver.h b/include/ver.h index a5bbf3840..a1a1b1006 100644 --- a/include/ver.h +++ b/include/ver.h @@ -46,10 +46,10 @@ extern const char nasm_compile_options[]; extern bool reproducible; -extern const char *nasm_comment(void); -extern size_t nasm_comment_len(void); +extern const char * pure_func nasm_comment(void); +extern size_t pure_func nasm_comment_len(void); -extern const char *nasm_signature(void); -extern size_t nasm_signature_len(void); +extern const char * pure_func nasm_signature(void); +extern size_t pure_func nasm_signature_len(void); #endif /* NASM_VER_H */ diff --git a/nasmlib/alloc.h b/nasmlib/alloc.h index 9b8ad192c..501aac59c 100644 --- a/nasmlib/alloc.h +++ b/nasmlib/alloc.h @@ -38,7 +38,7 @@ fatal_func nasm_alloc_failed(void); -static inline void *validate_ptr(void *p) +static inline void * pure_func validate_ptr(void *p) { if (unlikely(!p)) nasm_alloc_failed(); diff --git a/nasmlib/path.c b/nasmlib/path.c index d228ed1e1..482bc32df 100644 --- a/nasmlib/path.c +++ b/nasmlib/path.c @@ -90,7 +90,7 @@ * This is an inline, because most compilers can greatly simplify this * for a fixed string, like we have here. */ -static inline bool ismatch(const char *charset, char ch) +static inline bool pure_func ismatch(const char *charset, char ch) { const char *p; @@ -102,7 +102,7 @@ static inline bool ismatch(const char *charset, char ch) return false; } -static const char *first_filename_char(const char *path) +static const char * pure_func first_filename_char(const char *path) { #ifdef separators const char *p = path + strlen(path); diff --git a/nasmlib/raa.c b/nasmlib/raa.c index 038f97acb..5d2995268 100644 --- a/nasmlib/raa.c +++ b/nasmlib/raa.c @@ -114,7 +114,8 @@ void raa_free(struct RAA *r) nasm_free(r); } -static const union intorptr *real_raa_read(struct RAA *r, raaindex posn) +static const union intorptr * pure_func +real_raa_read(struct RAA *r, raaindex posn) { nasm_assert(posn <= (~(raaindex)0 >> 1)); diff --git a/nasmlib/ver.c b/nasmlib/ver.c index 96260b6ca..34239874f 100644 --- a/nasmlib/ver.c +++ b/nasmlib/ver.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 1996-2020 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. @@ -14,7 +14,7 @@ * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF @@ -59,22 +59,22 @@ static const char * const _nasm_signature[2] = { "NASM" }; -const char *nasm_comment(void) +const char * pure_func nasm_comment(void) { return _nasm_comment[reproducible]; } -size_t nasm_comment_len(void) +size_t pure_func nasm_comment_len(void) { return strlen(nasm_comment()); } -const char *nasm_signature(void) +const char * pure_func nasm_signature(void) { return _nasm_signature[reproducible]; } -size_t nasm_signature_len(void) +size_t pure_func nasm_signature_len(void) { return strlen(nasm_signature()); } diff --git a/output/outform.h b/output/outform.h index 3b846749d..849cde034 100644 --- a/output/outform.h +++ b/output/outform.h @@ -346,7 +346,7 @@ static const struct ofmt_alias ofmt_aliases[] = { #endif /* BUILD_DRIVERS_ARRAY */ const struct ofmt *ofmt_find(const char *name, const struct ofmt_alias **ofmt_alias); -const struct dfmt *dfmt_find(const struct ofmt *, const char *); +const struct dfmt * pure_func dfmt_find(const struct ofmt *, const char *); void ofmt_list(const struct ofmt *, FILE *); void dfmt_list(FILE *); extern const struct dfmt null_debug_form; diff --git a/stdlib/strrchrnul.c b/stdlib/strrchrnul.c index 2fc8eb629..70900ffef 100644 --- a/stdlib/strrchrnul.c +++ b/stdlib/strrchrnul.c @@ -35,7 +35,7 @@ #ifndef HAVE_STRRCHRNUL -char *strrchrnul(const char *s, int c) +char * pure_func strrchrnul(const char *s, int c) { char *p; diff --git a/test/avx005.asm b/test/avx005.asm index 08765140d..d79d46f48 100644 --- a/test/avx005.asm +++ b/test/avx005.asm @@ -1,5 +1,3 @@ -;Testname=avx005; Arguments=-fbin -oavx005.bin -Ox; Files=stdout stderr avx005.bin - %define regxmm xmm0 %define regymm ymm0 %define mem [0] diff --git a/x86/bytecode.txt b/x86/bytecode.txt index e1a44fc91..24681d903 100644 --- a/x86/bytecode.txt +++ b/x86/bytecode.txt @@ -133,7 +133,7 @@ t = 0 for VEX (C4/C5), t = 1 for XOP (8F). \331 norep not valid with 0xF2 or 0xF3 REP prefixes. \332 f2i REP prefix (0xF2 byte) used as opcode extension. \333 f3i REP prefix (0xF3 byte) used as opcode extension. -\334 rex.l LOCK prefix used as REX. +\334 rex.l LOCK prefix used as REX.R in 16/32-bit mode. \335 repe disassemble a rep (0xF3 byte) prefix as repe not rep. \340 resb reserve bytes of uninitialized storage. Operand 0 had better be a segmentless constant. diff --git a/x86/iflags.ph b/x86/iflags.ph index 09a80e258..4fc21109c 100644 --- a/x86/iflags.ph +++ b/x86/iflags.ph @@ -17,6 +17,7 @@ if_("AR2", "SB, SW, SD applies to operand 2"); if_("AR3", "SB, SW, SD applies to operand 3"); if_("AR4", "SB, SW, SD applies to operand 4"); # These must match the order of the BITSx flags in opflags.h +# Are these obsolete? if_("SB", "Unsized operands can't be non-byte"); if_("SW", "Unsized operands can't be non-word"); if_("SD", "Unsized operands can't be non-dword"); @@ -26,10 +27,11 @@ if_("SO", "Unsized operands can't be non-oword"); if_("SY", "Unsized operands can't be non-yword"); if_("SZ", "Unsized operands can't be non-zword"); # End BITSx order match requirement -if_("SIZE", "Unsized operands must match the bitsize"); +if_("NWSIZE", "Operand size defaults to 64 in 64-bit mode"); +if_("OSIZE", "Unsized operands must match the default operand size"); +if_("ASIZE", "Unsized operands must match the address size"); if_("ANYSIZE", "Ignore operand size even if explicit"); if_("SX", "Unsized operands not allowed"); -if_("SX_W", "At least one sized SMx operand required"); if_("SDWORD", "Strict sdword64 matching"); if_break_ok(); diff --git a/x86/insns-iflags.ph b/x86/insns-iflags.ph index 48a51273d..915e85356 100644 --- a/x86/insns-iflags.ph +++ b/x86/insns-iflags.ph @@ -195,7 +195,7 @@ sub set_implied_flags($;$) { sub size_flag($) { my %sflags = ( 'SB' => 8, 'SW' => 16, 'SD' => 32, 'SQ' => 64, 'ST' => 80, 'SO' => 128, 'SY' => 256, 'SZ' => 512, - 'SX' => 0, 'SIZE' => 0, 'ANYSIZE' => 0 ); + 'SX' => 0, 'OSIZE' => 0, 'ASIZE' => 0, 'ANYSIZE' => 0 ); my($flags) = @_; foreach my $fl (keys(%sflags)) { @@ -260,14 +260,14 @@ sub split_flags($) { # Merge a flags field and strip flags with leading ! sub merge_flags($;$) { - my($flags, $merge) = @_; + my($flags, $human) = @_; clean_flags(\%flags); my @flagslist = sort { $flag_byname{$a} <=> $flag_byname{$b} } grep { !/^(\s*|\!.*)$/ } keys(%$flags); - if ($merge) { + if ($human) { # For possibe human consumption. Merge subsequent SM and AR # flags back into ranges. my @ofl = @flagslist; @@ -309,7 +309,7 @@ sub merge_flags($;$) { } } - return scalar(@flagslist) ? join(',', @flagslist) : '0'; + return scalar(@flagslist) ? join(',', @flagslist) : $human ? 'ignore' : '0'; } # Compute the combinations of instruction flags actually used in templates diff --git a/x86/insns.dat b/x86/insns.dat index ca4530ac9..18e1f19ed 100644 --- a/x86/insns.dat +++ b/x86/insns.dat @@ -76,8 +76,8 @@ NOP void [ osz norexb nof3 90] 8086 NOP2 void [ norexb nof3 66 90] 386,ND $wdq NOP rm# [m: o# 0f 1f /0] P6 -;# The basic 8 arithmetic operations -$arith ADD OR ADC SBB AND SUB XOR -zu,-lock,-hle,!apx,CMP +;# The basic 7 arithmetic operations +$arith ADD OR ADC SBB AND SUB XOR ;# The basic shift and rotate operations $shift !x,xs="0f38 f7" ROL x=f3,xs="0f3a f0",ROR RCL RCR x=66,SHL,SAL x=f2,SHR - x=f3,SAR @@ -194,88 +194,54 @@ $bwdq XCHG reg#,rm# [rm: hlenl o16 87 /r] 8086,SM,LOCK1,ND ;# Jumps ; Call/jmp near imm/reg/mem is always 64-bit in long mode. -JMP imm|short [i: nw eb rel8] 8086,NOAPX,SX -JMP imm8 [i: nw eb rel8] 8086,NOAPX,SX -JMP imm8|short [i: nw eb rel8] 8086,NOAPX,SX -JMP imm [i: jmp8 nw eb rel8] 8086,SX,ND,NOAPX -JMP imm [i: nw odf e9 rel] 8086,SX,BND,NOAPX -JMP imm|near [i: nw odf e9 rel] 8086,SX,ND,BND,NOAPX -JMP imm|far [i: odf ea iwd seg] 8086,SX,ND,NOLONG -JMP imm16 [i: o16 e9 rel] 8086,SX,NOLONG,BND -JMP imm16|near [i: o16 e9 rel] 8086,SX,ND,NOLONG,BND -JMP imm16|far [i: o16 ea iwd seg] 8086,SX,ND,NOLONG -JMP imm32 [i: o32 e9 rel] 386,SX,NOLONG,BND -JMP imm32|near [i: o32 e9 rel] 386,SX,ND,NOLONG,BND -JMP imm32|far [i: o32 ea iwd seg] 386,SX,ND,NOLONG -JMP imm64 [i: o64nw e9 rel] X86_64,SX,LONG,BND,NOAPX -JMP imm64|near [i: o64nw e9 rel] X86_64,SX,LONG,ND,BND,NOAPX -JMP imm:imm [ji: odf ea iwd iw] 8086,NOLONG -JMP imm16:imm [ji: o16 ea iw iw] 8086,SX,AR0,NOLONG -JMP imm:imm16 [ji: o16 ea iw iw] 8086,SX,AR1,NOLONG -JMP imm32:imm [ji: o32 ea id iw] 386,SX,AR0,NOLONG -JMP imm:imm32 [ji: o32 ea id iw] 386,SX,AR1,NOLONG -JMP mem|far [m: odf ff /5] 8086,SX,NOLONG -JMP mem|far [m: o64 ff /5] X86_64,SX,LONG -JMP mem16|far [m: o16 ff /5] 8086,SX -JMP mem32|far [m: o32 ff /5] 386,SX -JMP mem64|far [m: o64 ff /5] X86_64,LONG,SX -JMP mem|near [m: odf ff /4] 8086,ND,BND,SX -JMP rm16|near [m: o16 ff /4] 8086,NOLONG,ND,SX,BND -JMP rm32|near [m: o32 ff /4] 386,NOLONG,ND,SX,BND -JMP rm64|near [m: o64nw ff /4] X86_64,LONG,ND,SX,BND -JMP mem [m: odf ff /4] 8086,BND -JMP rm16 [m: o16 ff /4] 8086,NOLONG,BND -JMP rm32 [m: o32 ff /4] 386,NOLONG,BND -JMP rm64 [m: o64nw ff /4] X86_64,LONG,BND + JMP imm8|short [i: nw eb rel8] 8086,NOAPX + JMP imm [i: jmp8 nw eb rel8] 8086,SX,ND,NOAPX +$wdq JMP imm#|near [i: nw o# e9 rel] 8086,OSIZE,ND,BND,NOLONG16 +$wdq JMP rm#|near [m: nw o# ff /4] 8086,OSIZE,BND,NOLONG16 +$wd JMP imm#|far [i: o# ea iwd seg] 8086,OSIZE,ND,NOLONG +$wd JMP imm16:imm# [ji: o# ea iwd iw] 8086,OSIZE,AR1,NOLONG +$wd JMP imm16:imm#|far [ji: o# ea iwd iw] 8086,OSIZE,AR1,NOLONG,ND +$wdq JMP mem#|far [m: o# ff /5] 8086,OSIZE ; APX absolute 64-bit jmp -JMP imm|abs [i: a64 np rex2 a1 iq ] APX -JMP imm64|abs [i: a64 np rex2 a1 iq ] APX,ND -JMPABS imm [i: a64 np rex2 a1 iq ] APX,ND -JMPABS imm64 [i: a64 np rex2 a1 iq ] APX,ND + JMP imm64|abs [i: a64 np rex2 a1 iq ] APX + JMPABS imm64 [i: a64 np rex2 a1 iq ] APX,ND + JMPABS imm64|abs [i: a64 np rex2 a1 iq ] APX,ND -Jcc imm|near [i: odf 0f 80+c rel] 386,BND,SX,NOAPX -Jcc imm16|near [i: o16 0f 80+c rel] 386,NOLONG,SX,BND -Jcc imm32|near [i: o32 0f 80+c rel] 386,NOLONG,SX,BND -Jcc imm64|near [i: o64nw 0f 80+c rel] X86_64,LONG,SX,BND,NOAPX -Jcc imm|short [i: nw 70+c rel8] 8086,ND,BND,SX,NOAPX -Jcc imm8 [i: nw 70+c rel8] 8086,ND,BND,SX,NOAPX -Jcc imm [i: jcc8 nw 70+c rel8] 8086,BND,NOAPX -Jcc imm [i: nw 0f 80+c rel] 386,ND,BND,NOAPX -Jcc imm [i: nw 71+c jlen e9 rel] 8086,ND,NOAPX +Jcc imm8|short [i: nw 70+c rel8] 8086,ND,BND,SX,NOAPX +Jcc imm [i: jcc8 nw 70+c rel8] 8086,BND,SX,NOAPX +$zwdq Jcc imm#|near [i: o# 0f 80+c rel] 386,BND,NOAPX,NOLONGwd +; Jump-over emulation of Jcc on < 386 +Jcc imm16|near [i: nw 71+c jlen e9 rel] 8086,ND,NOAPX,NOLONG -JCXZ imm [i: a16 e3 rel8] 8086,NOLONG -JECXZ imm [i: a32 e3 rel8] 386,NOAPX -JRCXZ imm [i: a64 e3 rel8] X86_64,LONG,NOAPX +; These only have short forms, hence imm8|near|short +JCXZ imm8|near|short [i: a16 e3 rel8] 8086,NOLONG +JECXZ imm8|near|short [i: a32 e3 rel8] 386,NOAPX +JRCXZ imm8|near|short [i: a64 e3 rel8] X86_64,LONG,NOAPX +$wdq JCXZ imm8|near|short,cx# [i-: a# e3 rel8] 8086,ND -$z LOOP% imm [i: a# nw e2 rel8] 8086,NOAPX -$z LOOPE% imm [i: a# nw e1 rel8] 8086,NOAPX -$z LOOPNE% imm [i: a# nw e0 rel8] 8086,NOAPX -$z LOOPZ% imm [i: a# nw e1 rel8] 8086,NOAPX,ND -$z LOOPNZ% imm [i: a# nw e0 rel8] 8086,NOAPX,ND -$wdq LOOP imm,cx# [i-: a# nw e2 rel8] 8086,NOAPX -$wdq LOOPE imm,cx# [i-: a# nw e1 rel8] 8086,NOAPX -$wdq LOOPNE imm,cx# [i: a# nw e0 rel8] 8086,NOAPX -$wdq LOOPZ imm,cx# [i-: a# nw e1 rel8] 8086,NOAPX,ND -$wdq LOOPNZ imm,cx# [i: a# nw e0 rel8] 8086,NOAPX,ND -$wdq LOOP% imm [i: a# nw e2 rel8] 8086,NOAPX,ND -$wdq LOOPE% imm [i: a# nw e1 rel8] 8086,NOAPX,ND -$wdq LOOPNE% imm [i: a# nw e0 rel8] 8086,NOAPX,ND -$wdq LOOPZ% imm [i: a# nw e1 rel8] 8086,NOAPX,ND -$wdq LOOPNZ% imm [i: a# nw e0 rel8] 8086,NOAPX,ND +$zwdq LOOP% imm8|near|short [i: a# nw e2 rel8] 8086,NOAPX,(wdq:ND) +$zwdq LOOPE% imm8|near|short [i: a# nw e1 rel8] 8086,NOAPX,(wdq:ND) +$zwdq LOOPNE% imm8|near|short [i: a# nw e0 rel8] 8086,NOAPX,(wdq:ND) +$zwdq LOOPZ% imm8|near|short [i: a# nw e1 rel8] 8086,NOAPX,ND +$zwdq LOOPNZ% imm8|near|short [i: a# nw e0 rel8] 8086,NOAPX,ND +$wdq LOOP imm8|near|short,cx# [i-: a# nw e2 rel8] 8086,NOAPX +$wdq LOOPE imm8|near|short,cx# [i-: a# nw e1 rel8] 8086,NOAPX +$wdq LOOPNE imm8|near|short,cx# [i-: a# nw e0 rel8] 8086,NOAPX +$wdq LOOPZ imm8|near|short,cx# [i-: a# nw e1 rel8] 8086,NOAPX,ND +$wdq LOOPNZ imm8|near|short,cx# [i-: a# nw e0 rel8] 8086,NOAPX,ND ; JMPE is obsolete, but seems to be used by a fair number of virtual environments? - JMPE imm [i: nw odf 0f b8 rel] IA64,SIZE -$wdq JMPE imm# [i: nw o# 0f b8 rel] IA64 +$zwdq JMPE imm#|near [i: nw o# 0f b8 rel] IA64 ; 0f 00 /6 with a prefix has been repurposed in long mode -$wdq JMPE rm# [m: o# np 0f 00 /6] IA64 -$wd JMPE rm# [m: o# 0f 00 /6] IA64,NOLONG +$wdq JMPE rm#|near [m: nw o# np 0f 00 /6] IA64 +$wd JMPE rm#|near [m: o# 0f 00 /6] IA64,NOLONG ;# Call and return -CALL imm [i: odf e8 rel] 8086,BND,NOAPX,SIZE -CALL imm|near [i: odf e8 rel] 8086,ND,BND,NOAPX,SIZE -CALL imm|far [i: odf 9a iwd seg] 8086,ND,NOLONG,SIZE -CALL imm:imm [ji: odf 9a iwd iw] 8086,NOLONG,SIZE,AR1 +CALL imm [i: odf e8 rel] 8086,BND,NOAPX,OSIZE +CALL imm|near [i: odf e8 rel] 8086,ND,BND,NOAPX,OSIZE +CALL imm|far [i: odf 9a iwd seg] 8086,ND,NOLONG,OSIZE +CALL imm:imm [ji: odf 9a iwd iw] 8086,NOLONG,OSIZE,AR1 ; Call/jmp near imm/reg/mem is always 64-bit in long mode. CALL imm16 [i: o16 e8 rel] 8086,NOLONG,BND,SX CALL imm16|near [i: o16 e8 rel] 8086,ND,NOLONG,BND,SX,ND @@ -298,7 +264,7 @@ CALL mem|near [m: odf ff /2] 8086,ND,BND,SX CALL rm16|near [m: o16 ff /2] 8086,NOLONG,ND,BND,SX CALL rm32|near [m: o32 ff /2] 386,NOLONG,ND,BND,SX CALL rm64|near [m: o64nw ff /2] X86_64,LONG,ND,BND,SX -CALL mem [m: odf ff /2] 8086,BND,SIZE +CALL mem [m: odf ff /2] 8086,BND,OSIZE CALL rm16 [m: o16 ff /2] 8086,NOLONG,BND CALL rm32 [m: o32 ff /2] 386,NOLONG,BND CALL rm64 [m: o64nw ff /2] X86_64,LONG,BND @@ -387,8 +353,8 @@ WBNOINVD void [ f3 0f 09] WBNOINVD,FUTURE,PRIV INVPCID reg32,mem128 [rm: 66 0f38 82 /r] FUTURE,INVPCID,PRIV,NOLONG INVPCID reg64,mem128 [rm: 66 0f38 82 /r] FUTURE,INVPCID,PRIV,LONG INVLPG mem [m: 0f 01 /7] 486,PRIV - INVLPGA void [ adf 0f 01 df] X86_64,AMD -$wdq INVLPGA ax#,reg_ecx [--: a# 0f 01 df] X86_64,AMD,NOLONG +$wdq INVLPGA ax#,reg_ecx [--: a# 0f 01 df] X86_64,AMD + INVLPGA void [ adf 0f 01 df] X86_64,AMD,ND ;# Special reads: timestamp, CPU number, performance counters, randomness RDPMC void [ 0f 33] P6,NOAPX @@ -402,30 +368,26 @@ $dq RDPID reg# [m: o# f3 0f c7 /7] FUTURE ;# Machine control and management instructions CLTS void [ 0f 06] 286,PRIV CPUID void [ 0f a2] PENT -LMSW mem [m: 0f 01 /6] 286,PRIV -LMSW mem16 [m: 0f 01 /6] 286,PRIV -LMSW reg16 [m: 0f 01 /6] 286,PRIV -SMSW mem [m: 0f 01 /4] 286 -SMSW mem16 [m: 0f 01 /4] 286 -SMSW reg16 [m: o16 0f 01 /4] 286 -SMSW reg32 [m: o32 0f 01 /4] 386 -SMSW reg64 [m: o64 0f 01 /4] X86_64,LONG -MOV reg32,reg_creg [mr: rex.l 0f 20 /r] 386,PRIV,NOLONG -MOV reg64,reg_creg [mr: o64nw 0f 20 /r] X86_64,LONG,PRIV -MOV reg_creg,reg32 [rm: rex.l 0f 22 /r] 386,PRIV,NOLONG -MOV reg_creg,reg64 [rm: o64nw 0f 22 /r] X86_64,LONG,PRIV -MOV reg32,reg_dreg [mr: 0f 21 /r] 386,PRIV,NOLONG -MOV reg64,reg_dreg [mr: o64nw 0f 21 /r] X86_64,LONG,PRIV -MOV reg_dreg,reg32 [rm: 0f 23 /r] 386,PRIV,NOLONG -MOV reg_dreg,reg64 [rm: o64nw 0f 23 /r] X86_64,LONG,PRIV -MOV reg32,reg_treg [mr: 0f 24 /r] 386,NOLONG,ND,OBSOLETE -MOV reg_treg,reg32 [rm: 0f 26 /r] 386,NOLONG,ND,OBSOLETE +LMSW rm16 [m: 0f 01 /6] 286,PRIV + SMSW rm16 [m: 0f 01 /4] 286 +$wdq SMSW reg# [m: o# 0f 01 /4] 286 + +$dq MOV reg#,reg_creg [mr: nw w# rex.l 0f 20 /r] 386,PRIV +$dq MOV reg_creg,reg# [rm: nw w# rex.l 0f 22 /r] 386,PRIV +$dq MOV reg#,reg_dreg [mr: nw w# 0f 21 /r] 386,PRIV +$dq MOV reg_dreg,reg# [rm: nw w# 0f 23 /r] 386,PRIV,NOLONG + MOV reg32,reg_treg [mr: 0f 24 /r] 386,NOLONG,ND,OBSOLETE + MOV reg_treg,reg32 [rm: 0f 26 /r] 386,NOLONG,ND,OBSOLETE + WRMSR void [ 0f 30] PENT,PRIV,NOAPX RDMSR void [ 0f 32] PENT,PRIV,NOAPX WRMSRNS void [ np 0f 01 c6 ] WRMSRNS,FUTURE,PRIV,LONG RDMSRLIST void [ f2 0f 01 c6 ] MSRLIST,FUTURE,PRIV,LONG WRMSRLIST void [ f3 0f 01 c6 ] MSRLIST,FUTURE,PRIV,LONG +$bwd UMOV rm#,reg# [mr: np o# 0f 10# /r] 386,UNDOC,SM,ND,NOLONG,OBSOLETE +$bwd UMOV reg#,rm# [rm: np o# 0f 12# /r] 386,UNDOC,SM,ND,NOLONG,OBSOLETE + ; Machine control instructions from old Cyrix machines, probably obsolete BB0_RESET void [ m1 3a] PENT,CYRIX,NOLONG,OBSOLETE,ND BB1_RESET void [ m1 3b] PENT,CYRIX,NOLONG,OBSOLETE,ND @@ -735,12 +697,8 @@ $wdq LSL reg#,rm16 [rm: o# 0f 03 /r] 286,PROT $wdq LSL reg#,reg32 [rm: o# 0f 03 /r] 386,PROT $wdq LSL reg#,reg64 [rm: o# 0f 03 /r] X86_64,LONG,PROT -VERR mem [m: 0f 00 /4] 286,PROT -VERR mem16 [m: 0f 00 /4] 286,PROT -VERR reg16 [m: 0f 00 /4] 286,PROT -VERW mem [m: 0f 00 /5] 286,PROT -VERW mem16 [m: 0f 00 /5] 286,PROT -VERW reg16 [m: 0f 00 /5] 286,PROT +VERR rm16 [m: 0f 00 /4] 286,PROT +VERW rm16 [m: 0f 00 /5] 286,PROT ; The privileged ones... SWAPGS void [ 0f 01 f8] X86_64,LONG @@ -754,22 +712,22 @@ LLDT mem16 [m: 0f 00 /2] 286,PROT,PRIV LLDT reg16 [m: 0f 00 /2] 286,PROT,PRIV LTR rm16 [m: 0f 00 /3] 286,PROT,PRIV -$wdq SGDT mem# [m: nw o# 0f 01 /0] 286,SIZE -$wdq SIDT mem# [m: nw o# 0f 01 /1] 286,SIZE - SLDT reg64 [m: o64nw 0f 00 /0] X86_64,LONG,ND -$wdq SLDT reg# [m: o# 0f 00 /0] 286 - SLDT mem16 [m: osz 0f 00 /0] 286 - STR reg64 [m: o64nw 0f 00 /1] X86_64,LONG,ND -$wdq STR reg# [m: o# 0f 00 /1] 286 - STR mem16 [m: osz 0f 00 /1] 286 +$wdq SGDT mem# [m: nw o# 0f 01 /0] 286,OSIZE +$wdq SIDT mem# [m: nw o# 0f 01 /1] 286,OSIZE + SLDT reg64 [m: o64nw 0f 00 /0] X86_64,LONG,ND +$wdq SLDT reg# [m: o# 0f 00 /0] 286 + SLDT mem16 [m: osz 0f 00 /0] 286 + STR reg64 [m: o64nw 0f 00 /1] X86_64,LONG,ND +$wdq STR reg# [m: o# 0f 00 /1] 286 + STR mem16 [m: osz 0f 00 /1] 286 STR mem16 [m: 0f 00 /1] 286,PROT STR reg16 [m: o16 0f 00 /1] 286,PROT STR reg32 [m: o32 0f 00 /1] 386,PROT STR reg64 [m: o64 0f 00 /1] X86_64,LONG -$wdq LEA reg#,mem [rm: o# 8d /r] 8086 -$wdq LEA reg#,imm# [rm: o# 8d /r] 8086,ND +$wdq LEA reg#,mem [rm: o# 8d /r] 8086 +$wdq LEA reg#,imm# [rm: o# 8d /r] 8086,ND LOADALL void [ 0f 07] 386,UNDOC,ND,OBSOLETE LOADALL286 void [ 0f 05] 286,UNDOC,ND,OBSOLETE @@ -780,37 +738,26 @@ MONITORX void [ 0f 01 fa] AMD MONITORX reg_rax,reg_ecx,reg_edx [---: 0f 01 fa] X86_64,LONG,AMD,ND MONITORX reg_eax,reg_ecx,reg_edx [---: 0f 01 fa] AMD,ND MONITORX reg_ax,reg_ecx,reg_edx [---: 0f 01 fa] AMD,ND -$bwdq MOV ax#,mem_offs [-i: o# a0# iwdq] 8086,SM,NOAPX -$bwdq MOV mem_offs,ax# [i-: o# a2# iwdq] 8086,SM,NOHLE,NOAPX -MOV mem8,reg8 [mr: hlexr 88 /r] 8086,SM -MOV reg8,reg8 [mr: 88 /r] 8086 -MOV mem16,reg16 [mr: hlexr o16 89 /r] 8086,SM -MOV reg16,reg16 [mr: o16 89 /r] 8086 -MOV mem32,reg32 [mr: hlexr o32 89 /r] 386,SM -MOV reg32,reg32 [mr: o32 89 /r] 386 -MOV mem64,reg64 [mr: hlexr o64 89 /r] X86_64,LONG,SM -MOV reg64,reg64 [mr: o64 89 /r] X86_64,LONG -MOV reg8,mem8 [rm: 8a /r] 8086,SM -MOV reg8,reg8 [rm: 8a /r] 8086 -MOV reg16,rm16 [rm: o16 8b /r] 8086,SM -MOV reg32,rm32 [rm: o32 8b /r] 386,SM -MOV reg64,rm64 [rm: o64 8b /r] X86_64,LONG,SM -MOV reg8,imm8 [ri: b0+r ib] 8086,SM -MOV reg16,imm16 [ri: o16 b8+r iw] 8086,SM -MOV reg32,imm32 [ri: o32 b8+r id] 386,SM -MOV reg64,udword64 [ri: o64nw b8+r id] X86_64,LONG,SM,OPT,ND -MOV reg64,sdword64 [mi: o64 c7 /0 id,s] X86_64,LONG,SM,OPT,SDWORD,ND -MOV reg64,imm64 [ri: o64 b8+r iq] X86_64,LONG,SM -MOV rm8,imm8 [mi: hlexr c6 /0 ib] 8086,SM -MOV rm16,imm16 [mi: hlexr o16 c7 /0 iw] 8086,SM -MOV rm32,imm32 [mi: hlexr o32 c7 /0 id] 386,SM -MOV rm64,sdword64 [mi: hlexr o64 c7 /0 id,s] X86_64,LONG,SM -MOVD mmxreg,rm32 [rm: np 0f 6e /r] PENT,MMX,SD -MOVD rm32,mmxreg [mr: np 0f 7e /r] PENT,MMX,SD -MOVD mmxreg,rm64 [rm: np o64 0f 6e /r] X86_64,LONG,MMX,SX,ND -MOVD rm64,mmxreg [mr: np o64 0f 7e /r] X86_64,LONG,MMX,SX,ND -MOVQ mmxreg,mmxrm [rm: np 0f 6f /r] PENT,MMX,SQ -MOVQ mmxrm,mmxreg [mr: np 0f 7f /r] PENT,MMX,SQ +$bwdq MOV ax#,mem_offs [-i: o# a0# iwdq] 8086,SM,NOAPX +$bwdq MOV mem_offs,ax# [i-: o# a2# iwdq] 8086,SM,NOHLE,NOAPX +$bwdq MOVABS ax#,mem_offs [-i: o# a0# iwdq] 8086,SM,NOAPX,ND +$bwdq MOVABS mem_offs,ax# [i-: o# a2# iwdq] 8086,SM,NOHLE,NOAPX,ND +$bwdq MOV rm#,reg# [mr: hlexr o# 88# /r] 8086,SM +$bwdq MOV reg#,rm# [rm: o# 8a# /r] 8086,SM +$bwd MOV reg#,imm# [ri: o# b0+r# i#] 8086,SM + MOV reg64,udword64 [ri: o32 b8+r id] X86_64,LONG,SM,OPT,ND + MOV reg64,sdword64 [mi: o64 c7 /0 id,s] X86_64,LONG,SM,OPT,SDWORD,ND + MOV reg64,imm64 [ri: o64 b8+r iq] X86_64,LONG,SM + MOV reg64,imm64|abs [ri: o64 b8+r iq] X86_64,LONG,ND +$bwd MOVABS reg#,imm# [ri: o64 b8+r iq] 8086,SM + MOVABS reg64,imm64 [ri: o64 b8+r iq] X86_64,LONG,SM,ND +$bwdq MOV rm#,imm# [mi: hlexr o# c6# /0 i#] 8086,SM +MOVD mmxreg,rm32 [rm: np 0f 6e /r] PENT,MMX +MOVD rm32,mmxreg [mr: np 0f 7e /r] PENT,MMX +MOVD mmxreg,rm64 [rm: np o64 0f 6e /r] X86_64,LONG,MMX,ND +MOVD rm64,mmxreg [mr: np o64 0f 7e /r] X86_64,LONG,MMX,ND +MOVQ mmxreg,mmxrm64 [rm: np 0f 6f /r] PENT,MMX +MOVQ mmxrm64,mmxreg [mr: np 0f 7f /r] PENT,MMX MOVQ mmxreg,rm64 [rm: np o64 0f 6e /r] X86_64,LONG,MMX MOVQ rm64,mmxreg [mr: np o64 0f 7e /r] X86_64,LONG,MMX MWAIT void [ 0f 01 c9] PRESCOTT @@ -906,10 +853,10 @@ PUNPCKLWD mmxreg,mmxrm [rm: np 0f 61 /r] PENT,MMX,SQ ;# Stack operations $wdq PUSH reg# [r: nw o# 50+r] 8086 -$wdq PUSH rm# [m: nw o# ff /6] 8086,SIZE +$wdq PUSH rm# [m: nw o# ff /6] 8086,OSIZE PUSH imm8 [i: nw osz 6a ib,s] 186,SX,ND -$wdq PUSH sbyte# [i: nw o# 6a ib,s] 186,SIZE -$wdq PUSH imm# [i: nw o# 68 i#] 186,SIZE +$wdq PUSH sbyte# [i: nw o# 6a ib,s] 186,OSIZE +$wdq PUSH imm# [i: nw o# 68 i#] 186,OSIZE $wdq POP reg# [r: nw o# 58+r] 8086 $wdq POP rm# [m: nw o# 8f /0] 8086 @@ -969,29 +916,6 @@ SHRD reg32,reg32,reg_cl [mr-: o32 0f ad /r] 386 SHRD mem,reg64,reg_cl [mr-: o64 0f ad /r] X86_64,LONG,SM SHRD reg64,reg64,reg_cl [mr-: o64 0f ad /r] X86_64,LONG SKINIT void [ 0f 01 de] X86_64,LONG -TEST mem,reg8 [mr: 84 /r] 8086,SM -TEST reg8,reg8 [mr: 84 /r] 8086 -TEST mem,reg16 [mr: o16 85 /r] 8086,SM -TEST reg16,reg16 [mr: o16 85 /r] 8086 -TEST mem,reg32 [mr: o32 85 /r] 386,SM -TEST reg32,reg32 [mr: o32 85 /r] 386 -TEST mem,reg64 [mr: o64 85 /r] X86_64,LONG,SM -TEST reg64,reg64 [mr: o64 85 /r] X86_64,LONG -TEST reg8,mem [rm: 84 /r] 8086,SM -TEST reg16,mem [rm: o16 85 /r] 8086,SM -TEST reg32,mem [rm: o32 85 /r] 386,SM -TEST reg64,mem [rm: o64 85 /r] X86_64,LONG,SM -TEST reg_al,imm [-i: a8 ib] 8086,SM,NOAPX -TEST reg_ax,imm [-i: o16 a9 iw] 8086,SM,NOAPX -TEST reg_eax,imm [-i: o32 a9 id] 386,SM,NOAPX -TEST reg_rax,imm [-i: o64 a9 id,s] X86_64,LONG,SM,NOAPX -TEST rm8,imm [mi: f6 /0 ib] 8086,SM -TEST rm16,imm [mi: o16 f7 /0 iw] 8086,SM -TEST rm32,imm [mi: o32 f7 /0 id] 386,SM -TEST rm64,imm [mi: o64 f7 /0 id,s] X86_64,LONG,SM -TEST mem,imm8 [mi: f6 /0 ib] 8086,SM -TEST mem,imm16 [mi: o16 f7 /0 iw] 8086,SM -TEST mem,imm32 [mi: o32 f7 /0 id] 386,SM UD0 void [ 0f ff] 186,OBSOLETE UD0 reg16,rm16 [rm: o16 0f ff /r] 186 UD0 reg32,rm32 [rm: o32 0f ff /r] 186 @@ -1006,23 +930,27 @@ UD2B reg32,rm32 [rm: o32 0f b9 /r] 186,ND UD2B reg64,rm64 [rm: o64 0f b9 /r] 186,ND UD2 void [ 0f 0b] 186 UD2A void [ 0f 0b] 186,ND -UMOV mem,reg8 [mr: np 0f 10 /r] 386,UNDOC,SM,ND -UMOV reg8,reg8 [mr: np 0f 10 /r] 386,UNDOC,ND -UMOV mem,reg16 [mr: np o16 0f 11 /r] 386,UNDOC,SM,ND -UMOV reg16,reg16 [mr: np o16 0f 11 /r] 386,UNDOC,ND -UMOV mem,reg32 [mr: np o32 0f 11 /r] 386,UNDOC,SM,ND -UMOV reg32,reg32 [mr: np o32 0f 11 /r] 386,UNDOC,ND -UMOV reg8,mem [rm: np 0f 12 /r] 386,UNDOC,SM,ND -UMOV reg8,reg8 [rm: np 0f 12 /r] 386,UNDOC,ND -UMOV reg16,mem [rm: np o16 0f 13 /r] 386,UNDOC,SM,ND -UMOV reg16,reg16 [rm: np o16 0f 13 /r] 386,UNDOC,ND -UMOV reg32,mem [rm: np o32 0f 13 /r] 386,UNDOC,SM,ND -UMOV reg32,reg32 [rm: np o32 0f 13 /r] 386,UNDOC,ND FWAIT void [ wait] 8086 XLATB void [ d7] 8086 XLAT void [ d7] 8086,ND +;# Comparing and testing +$bwdq CMP rm#,reg# [mr: o# 38# /r ] 8086,SM +$bwdq CMP reg#,rm# [rm: o# 3a# /r ] 8086,SM +$wdq CMP rm#,sbyte# [mi: o# 83 /7 ib,s ] 8086,SM +$bwdq CMP ax#,imm# [mi: o# 3c# i# ] 8086,SM +$bwdq CMP rm#,imm# [mi: o# 80# /7 i# ] 8086,SM + +$bwdq TEST rm#,reg# [mr: o# 84# /r ] 8086,SM +$bwdq TEST ax#,imm# [-i: o# a8# i# ] 8086,SM,NOAPX +$bwdq TEST rm#,imm# [mi: o# f6# /0 i# ] 8086,SM + +$bwdq CCMPscc spec4,rm#,reg# [vmr: evex.scc.dfv.l0.np.m4.o# 38# /r ] APX,SM1-2 +$bwdq CCMPscc spec4,reg#,rm# [vrm: evex.scc.dfv.l0.np.m4.o# 3a# /r ] APX,SM1-2 +$wdq CCMPscc spec4,rm#,sbyte# [vmi: evex.scc.dfv.l0.66.m4.o# 83 /7 ib,s ] APX,SM1-2 +$bwdq CCMPscc spec4,rm#,imm# [vmi: evex.scc.dfv.l0.np.m4.o# 80# /7 ib ] APX,SM1-2 + ;# Conditional instructions $wdq CMOVcc reg#,rm# [rm: o# 0f 40+c /r] P6,SM @@ -1034,11 +962,6 @@ SETccZU reg32 [m: evex.nd1.l0.f2.m4.wig 40+c /0 ] APX,ZU,ND SETcc rm8 [m: evex.zu.l0.f2.m4.wig 40+c /0 ] APX SETccZU rm8 [m: evex.nd1.l0.f2.m4.wig 40+c /0 ] APX,ZU,ND -$bwdq CCMPscc spec4,rm#,reg# [vmr: evex.scc.dfv.l0.np.m4.o# 38# /r ] APX,SM1-2 -$bwdq CCMPscc spec4,reg#,rm# [vrm: evex.scc.dfv.l0.np.m4.o# 3a# /r ] APX,SM1-2 -$wdq CCMPscc spec4,rm#,sbyte# [vmi: evex.scc.dfv.l0.66.m4.o# 83 /7 ib,s ] APX,SM1-2 -$bwdq CCMPscc spec4,rm#,imm# [vmi: evex.scc.dfv.l0.np.m4.o# 80# /7 ib ] APX,SM1-2 - ;# Katmai Streaming SIMD instructions (SSE -- a.k.a. KNI, XMM, MMX2) ADDPS xmmreg,xmmrm128 [rm: np 0f 58 /r] KATMAI,SSE ADDSS xmmreg,xmmrm32 [rm: f3 0f 58 /r] KATMAI,SSE diff --git a/x86/insns.pl b/x86/insns.pl index 2747a3584..08dcafc51 100755 --- a/x86/insns.pl +++ b/x86/insns.pl @@ -990,8 +990,6 @@ sub byte_code_compile($$$) { 'odf' => 0322, # Operand size is default 'o64' => 0324, # 64-bit operand size requiring REX.W 'w1' => 0324, - 'o64nw' => 0323, # Implied 64-bit operand size (no REX.W) - 'nw' => 0327, # REX.W not needed 'a16' => 0310, 'a32' => 0311, 'adf' => 0312, # Address size is default (disassembly) @@ -1070,6 +1068,9 @@ sub byte_code_compile($$$) { # Plain code my $pc = $plain_codes{$op}; push(@codes, $pc) if (defined($pc)); + } elsif ($op =~ /^(o64)?(nw)$/) { + push(@codes, $1 eq '' ? 0327 : 0323); + $flags->{'NWSIZE'}++; } elsif ($prefix_ok && $op =~ /^(66|f2|f3)$/) { # 66/F2/F3 prefix used as an opcode extension if ($op eq '66') { diff --git a/x86/preinsns.pl b/x86/preinsns.pl index 000475580..d448bf993 100755 --- a/x86/preinsns.pl +++ b/x86/preinsns.pl @@ -18,7 +18,7 @@ require 'x86/insns-iflags.ph'; our %macros; our($macro, $outfile, $infile, $line); # Public for error messages -# Common pattern for the basic 8 arithmetric functions +# Common pattern for the basic 7 arithmetric functions $macros{'arith'} = { 'def' => *def_eightfold, 'txt' => <<'EOL' @@ -68,27 +68,62 @@ for (my $i = 1; $i <= 31; $i++) { sub func_multisize($$$) { my($mac, $args, $rawargs) = @_; my @sbyte = ('imm8', 'imm8', 'sbyteword16', 'sbytedword32', 'sbytedword64'); + my $long = 0; # 1 for LONG, 2 for NOLONG, 3 for invalid my @ol; my $mask = $mac->{'mask'}; for (my $i = 0; $i < scalar(@sizename); $i++) { next unless ($mask & (1 << $i)); - my $s = ($i > 0) ? 4 << $i : 'sz'; + my $s = ($i > 0) ? 4 << $i : ''; + my $sn = $sizename[$i]; + my $sz = $s || 'sz'; my $o; my $ins = join("\t", @$rawargs); - while ($ins =~ /^(.*?)((?:\b[0-9a-f]{2}|\bsbyte|\bimm|\bi|\b(?:reg_)?[abcd]x|\bw)?\#|\%)(.*)$/) { + + # Conditional pattern inclusions + # Syntax: (which1:text1/which2:text2/text3) + # ... where "which" is a combination of sizename letters. + # No colon means unconditional ("else" clause) + while ($ins =~ /^(.*?)\(([^\)]+)\)(.*)$/) { + $o .= $1; + my @cpp = split(/\//, $2); + $ins = $3; + + my $found; + foreach my $cp (@cpp) { + if ($cp =~ /^([a-z]+)\:(.*)$/) { + $cp = $2; + $found = $1 =~ /$sn/; + } else { + $found = 1; + } + if ($found) { + $o .= $cp; + last; + } + } + } + + $ins = $o.$ins; + $o = ''; + + while ($ins =~ /^(.*?)((?:\b[0-9a-f]{2}(?:\+r)?|\bsbyte|\bimm|\b[ioa]|\b(?:reg_)?[abcd]x|\breg|\brm|\bw)?\#|\b(?:reg|rm)64\b|\b(?:o64)?nw\b|\b(?:NO)?LONG\w+\b|\%)(.*)$/) { $o .= $1; my $mw = $2; $ins = $3; if ($mw eq '%') { - $o .= uc($sizename[$i]) if ($i); - } elsif ($mw =~ /^([0-9a-f]{2})\#$/) { - $o .= sprintf('%02x', hex($1) | ($s != 8)); + $o .= uc($sn) if ($i); + } elsif ($mw =~ /^([0-9a-f]{2})(\+r)?\#$/) { + $o .= sprintf('%02x%s', hex($1) | + (($s == 8) ? 0 : + ($2 eq '') ? 1 : 8), $2); } elsif ($mw eq 'sbyte#') { $o .= $sbyte[$i]; } elsif ($mw eq 'imm#') { $o .= !$i ? 'imm' : ($s >= 64) ? "sdword$s" : "imm$s"; + } elsif ($mw =~ '^([ao])\#$') { + $o .= $1 . $sz; } elsif ($mw eq 'i#') { $o .= !$i ? 'iwd' : ($s >= 64) ? 'id,s' : 'i'.$sizename[$i]; } elsif ($mw =~ /^(?:reg_)?([abcd])x\#$/) { @@ -100,28 +135,38 @@ sub func_multisize($$$) { $o .= "reg_e${1}x"; } elsif ($i == 4) { $o .= "reg_r${1}x"; + $long |= 1; } else { die "$0:$infile:$line: register cannot be used with z\n"; } + } elsif ($mw =~ /^(o64)?nw$/) { + $long |= 2 if ($i == 32); # nw = 32 bits not encodable in long mode + $o .= $mw; + } elsif ($mw =~ /^(reg|rm)(\#|[0-9]+)$/) { + # (Possible) GPR reference + $o .= $1; + my $n = ($2 eq '#') ? $s : $2; + $o .= $n; + $long |= 1 if ($n >= 64); + } elsif ($mw =~ /^(NO)?LONG(\w+)$/) { + my $longflag = $1 ? 2 : 1; + $long |= $longflag if ($2 =~ /$sn/i); + # Drop } elsif ($mw eq 'w#') { $o .= !$i ? 'ww' : ($s >= 64) ? 'w1' : 'w0'; - } else { + } elsif ($mw eq '#') { $o .= $s; + } else { + die "$0:$infile:$line: unknown sequence \"$mw\" should not match regexp\n"; } } $o .= $ins; - $o =~ s/\bNOLONG${i}\b/NOLONG/; - $o =~ s/\bNOLONG[0-9]+\b//; - if ($o =~ /\[[^\]]*\bnw\b[^\]]*\bo32\b[^\]]*\]/) { - # nw o32 -> NOLONG - $o .= ',NOLONG'; - } - if ($i >= 64) { - next if ($o =~ /\bNOLONG\b/); - $o .= ',X86_64,LONG'; - } elsif ($i >= 32) { - $o .= ',386'; - } + + $o .= ',LONG' if ($long & 1); + $o .= ',NOLONG' if ($long & 2); + + $o .= ',386' if ($s >= 32 && $o !~ /\B\!386\b/); + push(@ol, $o); } @@ -322,7 +367,7 @@ sub has_flag($@) { return undef; } -sub adjust_instruction_flags(@) { +sub adjust_fl_zu(@) { my($opcode, $operands, $encoding, $flags) = @_; # Flag-changing instructions @@ -347,20 +392,25 @@ sub adjust_instruction_flags(@) { add_flag($flags, 'ZU'); } - return ($opcode, $operands, $encoding, $flags); + return $flags; } -sub adjust_instruction(@) { +sub adjust_instruction_flags(@) { my @i = @_; - @i = adjust_instruction_flags(@i); + $i[3] = adjust_fl_zu(@i); - return undef unless (@i); + return undef unless (defined($i[3])); + + if ($i[0] =~ /\bKILL\b/ || $i[1] =~ /\bKILL\b/ || + $i[2] =~ /\bKILL\b/ || has_flag($i[3], 'KILL')) { + return undef; + } if ($i[2] =~ /\ba16\b/) { add_flag($i[3], 'NOLONG'); } - if ($i[2] =~ /\b(o64(nw)?\b|w1\b|rex2?|a64\b)/) { + if ($i[2] =~ /\b(o64(nw)?\b|rex2?|a64\b)/) { add_flag($i[3], 'LONG'); } if (has_flag($i[3], 'NOLONG') && has_flag($i[3], 'LONG')) { @@ -368,39 +418,45 @@ sub adjust_instruction(@) { return undef; } - if ($i[0] =~ /\bKILL\b/ || $i[1] =~ /\bKILL\b/ || - $i[2] =~ /\bKILL\b/ || has_flag($i[3], 'KILL')) { - return undef; + if (has_flag($i[3], 'LONG')) { + add_flag($i[3], 'X86_64'); } - return @i; + return $i[3]; } sub process_insn($$) { my($out, $l) = @_; - if ($l !~ /^(\s*)([^\s\;]+)(\s+)([^\s\;]+)(\s+)([^\s\;]+|\[[^\;]*\])(\s+)([^\s\;]+)(\s*(\;.*)?)$/) { + if ($l !~ /^\s*([^\s\;]+)\s+([^\s\;]+)\s+([^\s\;]+|\[[^\;]*?\])\s+([^\s\;]+)\s*(\;.*?)?\s*$/) { print $out $l, "\n"; return; } - # Opcode = $f[1] - # Operands = $f[3] - # Encoding = $f[5] - # Flags = $f[7] - my @f = ($1, $2, $3, $4, $5, $6, $7, $8); + print $out $5, "\n" unless ($5 eq ''); # Comment - my $nopr = ($f[3] =~ /^(void|ignore)$/) ? 0 : - scalar(split(/[\,\:]/, $f[3])); + my $opcode = $1; + my $operands = $2; + my $encoding = $3; + my $flagstr = $4; + + my $nopr = ($operands =~ /^(void|ignore)$/) ? 0 : scalar(split(/[\,\:]/, $operands)); # Modify the instruction flags - my %flags = split_flags($f[7]); - set_implied_flags(\%flags, $nopr); + my $flags = {split_flags($flagstr)}; + set_implied_flags($flags, $nopr); - next unless (adjust_instruction($f[1], $f[3], $f[5], \%flags)); + $flags = adjust_instruction_flags($opcode, $operands, $encoding, $flags); + return unless (defined($flags)); + $flagstr = merge_flags($flags, 1); - $f[7] = merge_flags(\%flags, 1); - print $out @f, "\n"; + # Tidy up the encoding for readability + $encoding =~ s/\s+/ /g; + if ($encoding =~ /^\s*\[\s*(.*?\:)?\s*([^\:]*?)\s*\]\s*$/) { + $encoding = sprintf('[%-10s%-34s]', $1, $2); + } + + print $out sprintf("%-23s %-39s %-47s %s\n", $opcode, $operands, $encoding, $flagstr); } open(my $in, '<', $infile) or die "$0:$infile: $!\n";