WIP: more matching and template work

Further work on a better matching system. Still a work in progress,
however.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2024-08-20 12:59:07 -07:00
parent f114a6276e
commit 75f6f4cdb2
34 changed files with 486 additions and 379 deletions

View file

@ -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.
*/

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -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],
[

View file

@ -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])

View file

@ -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])])

View file

@ -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.])
])])

View file

@ -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)

View file

@ -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 */

View file

@ -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);

View file

@ -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)

View file

@ -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);

View file

@ -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);
/*

View file

@ -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 */

View file

@ -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);

View file

@ -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

View file

@ -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: --- */

View file

@ -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 */

View file

@ -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();

View file

@ -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);

View file

@ -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));

View file

@ -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());
}

View file

@ -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;

View file

@ -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;

View file

@ -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]

View file

@ -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 <operand 0> bytes of uninitialized storage.
Operand 0 had better be a segmentless constant.

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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') {

View file

@ -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";