diff --git a/Makefile.in b/Makefile.in index e4c56b54..c3dbc0f8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -89,10 +89,13 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \ strfunc.$(O) tokhash.$(O) regvals.$(O) regflags.$(O) \ ilog2.$(O) \ lib/strlcpy.$(O) \ - preproc-nop.$(O) disp8.$(O) + preproc-nop.$(O) \ + disp8.$(O) \ + iflag.$(O) NDISASM = ndisasm.$(O) disasm.$(O) sync.$(O) nasmlib.$(O) ver.$(O) \ - insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) disp8.$(O) + insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) \ + disp8.$(O) iflag.$(O) #-- End File Lists --# all: nasm$(X) ndisasm$(X) manpages rdf @@ -108,6 +111,10 @@ ndisasm$(X): $(NDISASM) $(XOBJS) # though, so it isn't necessary to have Perl just to recompile NASM # from the distribution. +insns.pl: insns-iflags.pl + +iflag.c iflag.h: insns.dat insns.pl + $(PERL) $(srcdir)/insns.pl -t $(srcdir)/insns.dat insnsb.c: insns.dat insns.pl $(PERL) $(srcdir)/insns.pl -b $(srcdir)/insns.dat insnsa.c: insns.dat insns.pl @@ -185,7 +192,8 @@ PERLREQ = macros.c insnsb.c insnsa.c insnsd.c insnsi.h insnsn.c \ regs.c regs.h regflags.c regdis.c regdis.h regvals.c \ tokhash.c tokens.h pptok.h pptok.c pptok.ph \ directiv.c directiv.h \ - version.h version.mac version.mak version.nsh + version.h version.mac version.mak version.nsh \ + iflag.c iflag.h perlreq: $(PERLREQ) # Generated manpages, also pregenerated for distribution diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak index a96bd153..e93219fa 100644 --- a/Mkfiles/msvc.mak +++ b/Mkfiles/msvc.mak @@ -51,10 +51,11 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \ strfunc.$(O) tokhash.$(O) regvals.$(O) regflags.$(O) \ ilog2.$(O) \ lib/strlcpy.$(O) \ - preproc-nop.$(O) + preproc-nop.$(O) \ + iflag.$(O) NDISASM = ndisasm.$(O) disasm.$(O) sync.$(O) nasmlib.$(O) ver.$(O) \ - insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) + insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) iflag.$(O) #-- End File Lists --# all: nasm$(X) ndisasm$(X) @@ -71,6 +72,10 @@ ndisasm$(X): $(NDISASM) # though, so it isn't necessary to have Perl just to recompile NASM # from the distribution. +insns.pl: insns-iflags.pl + +iflag.c iflag.h: insns.dat insns.pl + $(PERL) $(srcdir)/insns.pl -t $(srcdir)/insns.dat insnsb.c: insns.dat insns.pl $(PERL) $(srcdir)/insns.pl -b $(srcdir)/insns.dat insnsa.c: insns.dat insns.pl @@ -142,7 +147,7 @@ directiv.c: directiv.dat directiv.pl perllib/phash.ph # This allows easier generation of distribution (see dist target). PERLREQ = macros.c insnsb.c insnsa.c insnsd.c insnsi.h insnsn.c \ regs.c regs.h regflags.c regdis.c regvals.c tokhash.c tokens.h \ - version.h version.mac pptok.h pptok.c + version.h version.mac pptok.h pptok.c iflag.c iflag.h perlreq: $(PERLREQ) clean: diff --git a/Mkfiles/netware.mak b/Mkfiles/netware.mak index 178dbdc3..8615431e 100644 --- a/Mkfiles/netware.mak +++ b/Mkfiles/netware.mak @@ -47,10 +47,11 @@ NASM = nasm.o nasmlib.o ver.o \ strfunc.o tokhash.o regvals.o regflags.o \ ilog2.o \ strlcpy.o \ - preproc-nop.o + preproc-nop.o \ + iflag.o NDISASM = ndisasm.o disasm.o sync.o nasmlib.o ver.o \ - insnsd.o insnsb.o insnsn.o regs.o regdis.o + insnsd.o insnsb.o insnsn.o regs.o regdis.o iflag.o #-- End File Lists --# NASM_OBJ = $(addprefix $(OBJDIR)/,$(notdir $(NASM))) $(EOLIST) diff --git a/Mkfiles/openwcom.mak b/Mkfiles/openwcom.mak index 8a0ffef8..222163d6 100644 --- a/Mkfiles/openwcom.mak +++ b/Mkfiles/openwcom.mak @@ -63,10 +63,11 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) & strfunc.$(O) tokhash.$(O) regvals.$(O) regflags.$(O) & ilog2.$(O) & lib/strlcpy.$(O) & - preproc-nop.$(O) + preproc-nop.$(O) & + iflag.$(O) NDISASM = ndisasm.$(O) disasm.$(O) sync.$(O) nasmlib.$(O) ver.$(O) & - insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) + insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) iflag.$(O) #-- End File Lists --# what: .SYMBOLIC @@ -106,6 +107,10 @@ ndisasm$(X): $(NDISASM) # though, so it isn't necessary to have Perl just to recompile NASM # from the distribution. +insns.pl: insns-iflags.pl + +iflag.c iflag.h: insns.dat insns.pl + $(PERL) $(srcdir)/insns.pl -t $(srcdir)/insns.dat insnsb.c: insns.dat insns.pl $(PERL) $(srcdir)/insns.pl -b $(srcdir)/insns.dat insnsa.c: insns.dat insns.pl @@ -177,7 +182,8 @@ PERLREQ = pptok.ph macros.c insnsb.c insnsa.c insnsd.c insnsi.h insnsn.c & regs.c regs.h regflags.c regdis.c regdis.h regvals.c & tokhash.c tokens.h pptok.h pptok.c & directiv.c directiv.h & - version.h version.mac + version.h version.mac & + iflag.c iflag.h perlreq: $(PERLREQ) .SYMBOLIC clean: .SYMBOLIC diff --git a/Mkfiles/owlinux.mak b/Mkfiles/owlinux.mak index d04c80d7..04fb90a6 100644 --- a/Mkfiles/owlinux.mak +++ b/Mkfiles/owlinux.mak @@ -74,10 +74,11 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \ strfunc.$(O) tokhash.$(O) regvals.$(O) regflags.$(O) \ ilog2.$(O) \ lib/strlcpy.$(O) \ - preproc-nop.$(O) + preproc-nop.$(O) \ + iflag.$(O) NDISASM = ndisasm.$(O) disasm.$(O) sync.$(O) nasmlib.$(O) ver.$(O) \ - insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) + insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) iflag.$(O) #-- End File Lists --# what: @@ -105,6 +106,10 @@ ndisasm$(X): $(NDISASM) # though, so it isn't necessary to have Perl just to recompile NASM # from the distribution. +insns.pl: insns-iflags.pl + +iflag.c iflag.h: insns.dat insns.pl + $(PERL) $(srcdir)/insns.pl -t $(srcdir)/insns.dat insnsb.c: insns.dat insns.pl $(PERL) $(srcdir)/insns.pl -b $(srcdir)/insns.dat insnsa.c: insns.dat insns.pl @@ -167,7 +172,7 @@ pptok.c: pptok.dat pptok.pl perllib/phash.ph PERLREQ = macros.c insnsb.c insnsa.c insnsd.c insnsi.h insnsn.c \ regs.c regs.h regflags.c regdis.c regdis.h regvals.c \ tokhash.c tokens.h pptok.h pptok.c \ - version.h version.mac + version.h version.mac iflag.c iflag.h perlreq: $(PERLREQ) clean: diff --git a/assemble.c b/assemble.c index 0667ef7d..193c4872 100644 --- a/assemble.c +++ b/assemble.c @@ -218,7 +218,7 @@ typedef struct { #define GEN_MODRM(mod, reg, rm) \ (((mod) << 6) | (((reg) & 7) << 3) | ((rm) & 7)) -static iflags_t cpu; /* cpu level received from nasm.c */ +static iflag_t cpu; /* cpu level received from nasm.c */ static efunc errfunc; static struct ofmt *outfmt; static ListGen *list; @@ -390,7 +390,7 @@ static bool jmp_match(int32_t segment, int64_t offset, int bits, return is_byte; } -int64_t assemble(int32_t segment, int64_t offset, int bits, iflags_t cp, +int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp, insn * instruction, struct ofmt *output, efunc error, ListGen * listgen) { @@ -704,7 +704,7 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflags_t cp, return 0; } -int64_t insn_size(int32_t segment, int64_t offset, int bits, iflags_t cp, +int64_t insn_size(int32_t segment, int64_t offset, int bits, iflag_t cp, insn * instruction, efunc error) { const struct itemplate *temp; @@ -1231,7 +1231,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits, * only for mib operands, make a single reg index [reg*1]. * gas uses this form to explicitly denote index register. */ - if ((temp->flags & IF_MIB) && + if (itemp_has(temp, IF_MIB) && (opy->indexreg == -1 && opy->hintbase == opy->basereg && opy->hinttype == EAH_NOTBASE)) { opy->indexreg = opy->basereg; @@ -1310,7 +1310,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits, length++; } else if ((ins->rex & REX_L) && !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) && - cpu >= IF_X86_64) { + iflag_ffs(&cpu) >= IF_X86_64) { /* LOCK-as-REX.R */ assert_no_prefix(ins, PPS_LOCK); lockcheck = false; /* Already errored, no need for warning */ @@ -1322,7 +1322,7 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits, } if (has_prefix(ins, PPS_LOCK, P_LOCK) && lockcheck && - (!(temp->flags & IF_LOCK) || !is_class(MEMORY, ins->oprs[0].type))) { + (!itemp_has(temp,IF_LOCK) || !is_class(MEMORY, ins->oprs[0].type))) { errfunc(ERR_WARNING | ERR_WARN_LOCK | ERR_PASS2 , "instruction is not lockable"); } @@ -2003,8 +2003,7 @@ static enum match_result find_match(const struct itemplate **tempp, m = MOK_GOOD; else m = MERR_INVALOP; - } else if (m == MERR_OPSIZEMISSING && - (temp->flags & IF_SMASK) != IF_SX) { + } else if (m == MERR_OPSIZEMISSING && !itemp_has(temp, IF_SX)) { /* * Missing operand size and a candidate for fuzzy matching... */ @@ -2090,7 +2089,7 @@ static enum match_result matches(const struct itemplate *itemp, /* * Is it legal? */ - if (!(optimizing > 0) && (itemp->flags & IF_OPT)) + if (!(optimizing > 0) && itemp_has(itemp, IF_OPT)) return MERR_INVALOP; /* @@ -2103,29 +2102,29 @@ static enum match_result matches(const struct itemplate *itemp, /* * Process size flags */ - switch (itemp->flags & IF_SMASK) { - case IF_SB: + switch (itemp_smask(itemp)) { + case IF_GENBIT(IF_SB): asize = BITS8; break; - case IF_SW: + case IF_GENBIT(IF_SW): asize = BITS16; break; - case IF_SD: + case IF_GENBIT(IF_SD): asize = BITS32; break; - case IF_SQ: + case IF_GENBIT(IF_SQ): asize = BITS64; break; - case IF_SO: + case IF_GENBIT(IF_SO): asize = BITS128; break; - case IF_SY: + case IF_GENBIT(IF_SY): asize = BITS256; break; - case IF_SZ: + case IF_GENBIT(IF_SZ): asize = BITS512; break; - case IF_SIZE: + case IF_GENBIT(IF_SIZE): switch (bits) { case 16: asize = BITS16; @@ -2146,9 +2145,9 @@ static enum match_result matches(const struct itemplate *itemp, break; } - if (itemp->flags & IF_ARMASK) { + if (itemp_armask(itemp)) { /* S- flags only apply to a specific operand */ - i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1; + i = itemp_arg(itemp); memset(size, 0, sizeof size); size[i] = asize; } else { @@ -2235,10 +2234,10 @@ static enum match_result matches(const struct itemplate *itemp, } } else if (is_register(instruction->oprs[i].basereg) && nasm_regvals[instruction->oprs[i].basereg] >= 16 && - !(itemp->flags & IF_AVX512)) { + !itemp_has(itemp, IF_AVX512)) { return MERR_ENCMISMATCH; } else if (instruction->prefixes[PPS_EVEX] && - !(itemp->flags & IF_AVX512)) { + !itemp_has(itemp, IF_AVX512)) { return MERR_ENCMISMATCH; } } @@ -2249,8 +2248,8 @@ static enum match_result matches(const struct itemplate *itemp, /* * Check operand sizes */ - if (itemp->flags & (IF_SM | IF_SM2)) { - oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands); + if (itemp_has(itemp, IF_SM) || itemp_has(itemp, IF_SM2)) { + oprs = (itemp_has(itemp, IF_SM2) ? 2 : itemp->operands); for (i = 0; i < oprs; i++) { asize = itemp->opd[i] & SIZE_MASK; if (asize) { @@ -2272,19 +2271,19 @@ static enum match_result matches(const struct itemplate *itemp, /* * Check template is okay at the set cpu level */ - if (((itemp->flags & IF_PLEVEL) > cpu)) + if (iflag_cmp_cpu_level(&insns_flags[itemp->iflag_idx], &cpu) > 0) return MERR_BADCPU; /* * Verify the appropriate long mode flag. */ - if ((itemp->flags & (bits == 64 ? IF_NOLONG : IF_LONG))) + if (itemp_has(itemp, (bits == 64 ? IF_NOLONG : IF_LONG))) return MERR_BADMODE; /* * If we have a HLE prefix, look for the NOHLE flag */ - if ((itemp->flags & IF_NOHLE) && + if (itemp_has(itemp, IF_NOHLE) && (has_prefix(instruction, PPS_REP, P_XACQUIRE) || has_prefix(instruction, PPS_REP, P_XRELEASE))) return MERR_BADHLE; @@ -2298,7 +2297,7 @@ static enum match_result matches(const struct itemplate *itemp, /* * Check if BND prefix is allowed */ - if ((IF_BND & ~itemp->flags) && + if (!itemp_has(itemp, IF_BND) && has_prefix(instruction, PPS_REP, P_BND)) return MERR_BADBND; diff --git a/assemble.h b/assemble.h index 1197d591..381e3ab5 100644 --- a/assemble.h +++ b/assemble.h @@ -38,10 +38,11 @@ #ifndef NASM_ASSEMBLE_H #define NASM_ASSEMBLE_H -int64_t insn_size(int32_t segment, int64_t offset, int bits, iflags_t cp, - insn * instruction, efunc error); -int64_t assemble(int32_t segment, int64_t offset, int bits, iflags_t cp, - insn * instruction, struct ofmt *output, efunc error, - ListGen * listgen); +#include "iflag.h" +int64_t insn_size(int32_t segment, int64_t offset, int bits, iflag_t cp, + insn * instruction, efunc error); +int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp, + insn * instruction, struct ofmt *output, efunc error, + ListGen * listgen); #endif diff --git a/disasm.c b/disasm.c index 9064b650..b7c5027f 100644 --- a/disasm.c +++ b/disasm.c @@ -501,11 +501,11 @@ static int matches(const struct itemplate *t, uint8_t *data, ins->rex = prefix->rex; memset(ins->prefixes, 0, sizeof ins->prefixes); - if (t->flags & (segsize == 64 ? IF_NOLONG : IF_LONG)) + if (itemp_has(t, (segsize == 64 ? IF_NOLONG : IF_LONG))) return false; if (prefix->rep == 0xF2) - drep = (t->flags & IF_BND ? P_BND : P_REPNE); + drep = (itemp_has(t, IF_BND) ? P_BND : P_REPNE); else if (prefix->rep == 0xF3) drep = P_REP; @@ -1099,7 +1099,7 @@ static const char * const condition_name[16] = { }; int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, - int32_t offset, int autosync, iflags_t prefer) + int32_t offset, int autosync, iflag_t *prefer) { const struct itemplate * const *p, * const *best_p; const struct disasm_index *ix; @@ -1110,7 +1110,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, uint8_t *origdata; int works; insn tmp_ins, ins; - iflags_t goodness, best, flags; + iflag_t goodness, best; int best_pref; struct prefix_info prefix; bool end_prefix; @@ -1277,7 +1277,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, } } - best = -1; /* Worst possible */ + iflag_set_all(&best); /* Worst possible */ best_p = NULL; best_pref = INT_MAX; @@ -1331,13 +1331,14 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, */ if (works) { int i, nprefix; - goodness = ((*p)->flags & IF_PFMASK) ^ prefer; - nprefix = 0; - for (i = 0; i < MAXPREFIX; i++) - if (tmp_ins.prefixes[i]) - nprefix++; + goodness = iflag_pfmask(*p); + goodness = iflag_xor(&goodness, prefer); + nprefix = 0; + for (i = 0; i < MAXPREFIX; i++) + if (tmp_ins.prefixes[i]) + nprefix++; if (nprefix < best_pref || - (nprefix == best_pref && goodness < best)) { + (nprefix == best_pref && iflag_cmp(&goodness, &best) == -1)) { /* This is the best one found so far */ best = goodness; best_p = p; @@ -1355,7 +1356,6 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, /* Pick the best match */ p = best_p; length = best_length; - flags = (*p)->flags; slen = 0; @@ -1528,7 +1528,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, nasm_reg_names[(o->basereg-EXPR_REG_START)]); started = true; } - if (o->indexreg != -1 && !(flags & IF_MIB)) { + if (o->indexreg != -1 && !itemp_has(*best_p, IF_MIB)) { if (started) output[slen++] = '+'; slen += snprintf(output + slen, outbufsize - slen, "%s", @@ -1607,7 +1607,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, } } - if (o->indexreg != -1 && (flags & IF_MIB)) { + if (o->indexreg != -1 && itemp_has(*best_p, IF_MIB)) { output[slen++] = ','; slen += snprintf(output + slen, outbufsize - slen, "%s", nasm_reg_names[(o->indexreg-EXPR_REG_START)]); diff --git a/disasm.h b/disasm.h index 70a9a7bb..fa6e2e2f 100644 --- a/disasm.h +++ b/disasm.h @@ -38,10 +38,12 @@ #ifndef NASM_DISASM_H #define NASM_DISASM_H +#include "iflag.h" + #define INSN_MAX 32 /* one instruction can't be longer than this */ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, - int32_t offset, int autosync, iflags_t prefer); + int32_t offset, int autosync, iflag_t *prefer); int32_t eatbyte(uint8_t *data, char *output, int outbufsize, int segsize); #endif diff --git a/insns.h b/insns.h index dd447c5c..8f04d13c 100644 --- a/insns.h +++ b/insns.h @@ -11,6 +11,7 @@ #include "nasm.h" #include "tokens.h" +#include "iflag.h" /* if changed, ITEMPLATE_END should be also changed accordingly */ struct itemplate { @@ -19,7 +20,7 @@ struct itemplate { opflags_t opd[MAX_OPERANDS]; /* bit flags for operand types */ decoflags_t deco[MAX_OPERANDS]; /* bit flags for operand decorators */ const uint8_t *code; /* the code it assembles to */ - iflags_t flags; /* some flags */ + uint32_t iflag_idx; /* some flags referenced by index */ }; /* Disassembler table structure */ @@ -47,119 +48,4 @@ extern const uint8_t nasm_bytecodes[]; */ #define ITEMPLATE_END {-1,-1,{-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1},NULL,0} -/* - * Instruction template flags. These specify which processor - * targets the instruction is eligible for, whether it is - * privileged or undocumented, and also specify extra error - * checking on the matching of the instruction. - * - * IF_SM stands for Size Match: any operand whose size is not - * explicitly specified by the template is `really' intended to be - * the same size as the first size-specified operand. - * Non-specification is tolerated in the input instruction, but - * _wrong_ specification is not. - * - * IF_SM2 invokes Size Match on only the first _two_ operands, for - * three-operand instructions such as SHLD: it implies that the - * first two operands must match in size, but that the third is - * required to be _unspecified_. - * - * IF_SB invokes Size Byte: operands with unspecified size in the - * template are really bytes, and so no non-byte specification in - * the input instruction will be tolerated. IF_SW similarly invokes - * Size Word, and IF_SD invokes Size Doubleword. - * - * (The default state if neither IF_SM nor IF_SM2 is specified is - * that any operand with unspecified size in the template is - * required to have unspecified size in the instruction too...) - * - * iflags_t is defined to store these flags. - */ - -#define IF_SM UINT64_C(0x00000001) /* size match */ -#define IF_SM2 UINT64_C(0x00000002) /* size match first two operands */ -#define IF_SB UINT64_C(0x00000004) /* unsized operands can't be non-byte */ -#define IF_SW UINT64_C(0x00000008) /* unsized operands can't be non-word */ -#define IF_SD UINT64_C(0x0000000C) /* unsized operands can't be non-dword */ -#define IF_SQ UINT64_C(0x00000010) /* unsized operands can't be non-qword */ -#define IF_SO UINT64_C(0x00000014) /* unsized operands can't be non-oword */ -#define IF_SY UINT64_C(0x00000018) /* unsized operands can't be non-yword */ -#define IF_SZ UINT64_C(0x0000001C) /* unsized operands can't be non-zword */ -#define IF_SIZE UINT64_C(0x00000038) /* unsized operands must match the bitsize */ -#define IF_SX UINT64_C(0x0000003C) /* unsized operands not allowed */ -#define IF_SMASK UINT64_C(0x0000003C) /* mask for unsized argument size */ -#define IF_AR0 UINT64_C(0x00000040) /* SB, SW, SD applies to argument 0 */ -#define IF_AR1 UINT64_C(0x00000080) /* SB, SW, SD applies to argument 1 */ -#define IF_AR2 UINT64_C(0x000000C0) /* SB, SW, SD applies to argument 2 */ -#define IF_AR3 UINT64_C(0x00000100) /* SB, SW, SD applies to argument 3 */ -#define IF_AR4 UINT64_C(0x00000140) /* SB, SW, SD applies to argument 4 */ -#define IF_ARMASK UINT64_C(0x000001C0) /* mask for unsized argument spec */ -#define IF_ARSHFT 6 /* LSB in IF_ARMASK */ -#define IF_OPT UINT64_C(0x00000200) /* optimizing assembly only */ -/* The next 3 bits aren't actually used for anything */ -#define IF_PRIV UINT64_C(0x00000000) /* it's a privileged instruction */ -#define IF_SMM UINT64_C(0x00000000) /* it's only valid in SMM */ -#define IF_PROT UINT64_C(0x00000000) /* it's protected mode only */ -#define IF_LOCK UINT64_C(0x00000400) /* lockable if operand 0 is memory */ -#define IF_NOLONG UINT64_C(0x00000800) /* it's not available in long mode */ -#define IF_LONG UINT64_C(0x00001000) /* long mode instruction */ -#define IF_NOHLE UINT64_C(0x00002000) /* HLE prefixes forbidden */ -#define IF_MIB UINT64_C(0x00004000) /* Disassemble with split EA */ -#define IF_BND UINT64_C(0x00008000) /* BND (0xF2) prefix available */ -/* These flags are currently not used for anything - intended for insn set */ -#define IF_UNDOC UINT64_C(0x8000000000) /* it's an undocumented instruction */ -#define IF_HLE UINT64_C(0x4000000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_AVX512 UINT64_C(0x2000000000) /* it's an AVX-512F (512b) instruction */ -#define IF_FPU UINT64_C(0x0100000000) /* it's an FPU instruction */ -#define IF_MMX UINT64_C(0x0200000000) /* it's an MMX instruction */ -#define IF_3DNOW UINT64_C(0x0300000000) /* it's a 3DNow! instruction */ -#define IF_SSE UINT64_C(0x0400000000) /* it's a SSE (KNI, MMX2) instruction */ -#define IF_SSE2 UINT64_C(0x0500000000) /* it's a SSE2 instruction */ -#define IF_SSE3 UINT64_C(0x0600000000) /* it's a SSE3 (PNI) instruction */ -#define IF_VMX UINT64_C(0x0700000000) /* it's a VMX instruction */ -#define IF_SSSE3 UINT64_C(0x0800000000) /* it's an SSSE3 instruction */ -#define IF_SSE4A UINT64_C(0x0900000000) /* AMD SSE4a */ -#define IF_SSE41 UINT64_C(0x0A00000000) /* it's an SSE4.1 instruction */ -#define IF_SSE42 UINT64_C(0x0B00000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_SSE5 UINT64_C(0x0C00000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_AVX UINT64_C(0x0D00000000) /* it's an AVX (128b) instruction */ -#define IF_AVX2 UINT64_C(0x0E00000000) /* it's an AVX2 (256b) instruction */ -#define IF_FMA UINT64_C(0x1000000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_BMI1 UINT64_C(0x1100000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_BMI2 UINT64_C(0x1200000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_TBM UINT64_C(0x1300000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_RTM UINT64_C(0x1400000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_INVPCID UINT64_C(0x1500000000) /* HACK NEED TO REORGANIZE THESE BITS */ -#define IF_AVX512CD (UINT64_C(0x1600000000)|IF_AVX512) /* AVX-512 Conflict Detection insns */ -#define IF_AVX512ER (UINT64_C(0x1700000000)|IF_AVX512) /* AVX-512 Exponential and Reciprocal */ -#define IF_AVX512PF (UINT64_C(0x1800000000)|IF_AVX512) /* AVX-512 Prefetch instructions */ -#define IF_MPX UINT64_C(0x1900000000) /* MPX instructions */ -#define IF_SHA UINT64_C(0x1A00000000) /* SHA instructions */ -#define IF_PREFETCHWT1 UINT64_C(0x1F00000000) /* PREFETCHWT1 instructions */ -#define IF_INSMASK UINT64_C(0xFF00000000) /* the mask for instruction set types */ -#define IF_PMASK UINT64_C(0xFF000000) /* the mask for processor types */ -#define IF_PLEVEL UINT64_C(0x0F000000) /* the mask for processor instr. level */ - /* also the highest possible processor */ -#define IF_8086 UINT64_C(0x00000000) /* 8086 instruction */ -#define IF_186 UINT64_C(0x01000000) /* 186+ instruction */ -#define IF_286 UINT64_C(0x02000000) /* 286+ instruction */ -#define IF_386 UINT64_C(0x03000000) /* 386+ instruction */ -#define IF_486 UINT64_C(0x04000000) /* 486+ instruction */ -#define IF_PENT UINT64_C(0x05000000) /* Pentium instruction */ -#define IF_P6 UINT64_C(0x06000000) /* P6 instruction */ -#define IF_KATMAI UINT64_C(0x07000000) /* Katmai instructions */ -#define IF_WILLAMETTE UINT64_C(0x08000000) /* Willamette instructions */ -#define IF_PRESCOTT UINT64_C(0x09000000) /* Prescott instructions */ -#define IF_X86_64 UINT64_C(0x0A000000) /* x86-64 instruction (long or legacy mode) */ -#define IF_NEHALEM UINT64_C(0x0B000000) /* Nehalem instruction */ -#define IF_WESTMERE UINT64_C(0x0C000000) /* Westmere instruction */ -#define IF_SANDYBRIDGE UINT64_C(0x0D000000) /* Sandy Bridge instruction */ -#define IF_FUTURE UINT64_C(0x0E000000) /* Future processor (not yet disclosed) */ -#define IF_X64 (IF_LONG|IF_X86_64) -#define IF_IA64 UINT64_C(0x0F000000) /* IA64 instructions (in x86 mode) */ -#define IF_CYRIX UINT64_C(0x10000000) /* Cyrix-specific instruction */ -#define IF_AMD UINT64_C(0x20000000) /* AMD-specific instruction */ -#define IF_SPMASK UINT64_C(0x30000000) /* specific processor types mask */ -#define IF_PFMASK (IF_INSMASK|IF_SPMASK) /* disassembly "prefer" mask */ - #endif /* NASM_INSNS_H */ diff --git a/insns.pl b/insns.pl index 8bd76abe..bf914692 100755 --- a/insns.pl +++ b/insns.pl @@ -37,6 +37,8 @@ # # Parse insns.dat and produce generated source code files +require 'insns-iflags.pl'; + # Opcode prefixes which need their own opcode tables # LONGER PREFIXES FIRST! @disasm_prefixes = qw(0F24 0F25 0F38 0F3A 0F7A 0FA6 0FA7 0F); @@ -67,7 +69,7 @@ print STDERR "Reading insns.dat...\n"; undef $output; foreach $arg ( @ARGV ) { if ( $arg =~ /^\-/ ) { - if ( $arg =~ /^\-([abdin])$/ ) { + if ( $arg =~ /^\-([abdint])$/ ) { $output = $1; } else { die "$0: Unknown option: ${arg}\n"; @@ -393,6 +395,10 @@ if ( !defined($output) || $output eq 'n' ) { close N; } +if ( !defined($output) || $output eq 't') { + write_iflags(); +} + printf STDERR "Done: %d instructions\n", $insns; # Count primary bytecodes, for statistics @@ -424,7 +430,7 @@ sub count_bytecodes(@) { sub format_insn($$$$$) { my ($opcode, $operands, $codes, $flags, $relax) = @_; - my $num, $nd = 0; + my $num, $nd = 0, $rawflags, $flagsindex; my @bytecode; my $op, @ops, $opp, @opx, @oppx, @decos, @opevex; my @iflags = ( "FPU", "MMX", "3DNOW", "SSE", "SSE2", @@ -492,16 +498,23 @@ sub format_insn($$$$$) { } # format the flags - $flags =~ s/,/|IF_/g; - $flags =~ s/(\|IF_ND|IF_ND\|)//, $nd = 1 if $flags =~ /IF_ND/; - $flags = "IF_" . $flags; + $nd = 1 if $flags =~ /(^|\,)ND($|\,)/; + $flags =~ s/(^|\,)ND($|\,)/\1/g; + $flags =~ s/(^|\,)X64($|\,)/\1LONG,X86_64\2/g; + $flags =~ s/(^|\,)AVX512CD($|\,)/\1AVX512CD,AVX512\2/g; + $flags =~ s/(^|\,)AVX512ER($|\,)/\1AVX512ER,AVX512\2/g; + $flags =~ s/(^|\,)AVX512PF($|\,)/\1AVX512PF,AVX512\2/g; + $rawflags = $flags; + $flagsindex = insns_flag_index(split(',',$flags)); + + die "Error in flags $rawflags" if not defined($flagsindex); @bytecode = (decodify($codes, $relax), 0); push(@bytecode_list, [@bytecode]); $codes = hexstr(@bytecode); count_bytecodes(@bytecode); - ("{I_$opcode, $num, {$operands}, $decorators, \@\@CODES-$codes\@\@, $flags},", $nd); + ("{I_$opcode, $num, {$operands}, $decorators, \@\@CODES-$codes\@\@, $flagsindex},", $nd); } # diff --git a/nasm.c b/nasm.c index 3a0c0508..b83810d2 100644 --- a/nasm.c +++ b/nasm.c @@ -60,6 +60,7 @@ #include "labels.h" #include "output/outform.h" #include "listing.h" +#include "iflag.h" /* * This is the maximum number of optimization passes to do. If we ever @@ -74,7 +75,7 @@ struct forwrefinfo { /* info held on forward refs. */ }; static int get_bits(char *value); -static iflags_t get_cpu(char *cpu_str); +static iflag_t get_cpu(char *cpu_str); static void parse_cmdline(int, char **); static void assemble_file(char *, StrList **); static void nasm_verror_gnu(int severity, const char *fmt, va_list args); @@ -106,8 +107,10 @@ static FILE *error_file; /* Where to write error messages */ FILE *ofile = NULL; int optimizing = MAX_OPTIMIZE; /* number of optimization passes to take */ static int sb, cmd_sb = 16; /* by default */ -static iflags_t cmd_cpu = IF_PLEVEL; /* highest level by default */ -static iflags_t cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */ + +static iflag_t cpu; +static iflag_t cmd_cpu; + int64_t global_offset_changed; /* referenced in labels.c */ int64_t prev_offset_changed; int32_t stall_count; @@ -321,6 +324,9 @@ int main(int argc, char **argv) time(&official_compile_time); + iflag_set(&cpu, IF_PLEVEL); + iflag_set(&cmd_cpu, IF_PLEVEL); + pass0 = 0; want_usage = terminate_after_phase = false; nasm_set_verror(nasm_verror_gnu); @@ -1187,7 +1193,7 @@ static void assemble_file(char *fname, StrList **depend_ptr) expr *e; int pass_max; - if (cmd_sb == 32 && cmd_cpu < IF_386) + if (cmd_sb == 32 && iflag_ffs(&cmd_cpu) < IF_386) nasm_error(ERR_FATAL, "command line: " "32-bit segment size requires a higher cpu"); @@ -2006,44 +2012,53 @@ static void usage(void) fputs("type `nasm -h' for help\n", error_file); } -static iflags_t get_cpu(char *value) +static iflag_t get_cpu(char *value) { + iflag_t r; + + iflag_clear_all(&r); + if (!strcmp(value, "8086")) - return IF_8086; - if (!strcmp(value, "186")) - return IF_186; - if (!strcmp(value, "286")) - return IF_286; - if (!strcmp(value, "386")) - return IF_386; - if (!strcmp(value, "486")) - return IF_486; - if (!strcmp(value, "586") || !nasm_stricmp(value, "pentium")) - return IF_PENT; - if (!strcmp(value, "686") || - !nasm_stricmp(value, "ppro") || - !nasm_stricmp(value, "pentiumpro") || !nasm_stricmp(value, "p2")) - return IF_P6; - if (!nasm_stricmp(value, "p3") || !nasm_stricmp(value, "katmai")) - return IF_KATMAI; - if (!nasm_stricmp(value, "p4") || /* is this right? -- jrc */ - !nasm_stricmp(value, "willamette")) - return IF_WILLAMETTE; - if (!nasm_stricmp(value, "prescott")) - return IF_PRESCOTT; - if (!nasm_stricmp(value, "x64") || - !nasm_stricmp(value, "x86-64")) - return IF_X86_64; - if (!nasm_stricmp(value, "ia64") || - !nasm_stricmp(value, "ia-64") || - !nasm_stricmp(value, "itanium") || - !nasm_stricmp(value, "itanic") || !nasm_stricmp(value, "merced")) - return IF_IA64; - - nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL, - "unknown 'cpu' type"); - - return IF_PLEVEL; /* the maximum level */ + iflag_set(&r, IF_8086); + else if (!strcmp(value, "186")) + iflag_set(&r, IF_186); + else if (!strcmp(value, "286")) + iflag_set(&r, IF_286); + else if (!strcmp(value, "386")) + iflag_set(&r, IF_386); + else if (!strcmp(value, "486")) + iflag_set(&r, IF_486); + else if (!strcmp(value, "586") || + !nasm_stricmp(value, "pentium")) + iflag_set(&r, IF_PENT); + else if (!strcmp(value, "686") || + !nasm_stricmp(value, "ppro") || + !nasm_stricmp(value, "pentiumpro") || + !nasm_stricmp(value, "p2")) + iflag_set(&r, IF_P6); + else if (!nasm_stricmp(value, "p3") || + !nasm_stricmp(value, "katmai")) + iflag_set(&r, IF_KATMAI); + else if (!nasm_stricmp(value, "p4") || /* is this right? -- jrc */ + !nasm_stricmp(value, "willamette")) + iflag_set(&r, IF_WILLAMETTE); + else if (!nasm_stricmp(value, "prescott")) + iflag_set(&r, IF_PRESCOTT); + else if (!nasm_stricmp(value, "x64") || + !nasm_stricmp(value, "x86-64")) + iflag_set(&r, IF_X86_64); + else if (!nasm_stricmp(value, "ia64") || + !nasm_stricmp(value, "ia-64") || + !nasm_stricmp(value, "itanium")|| + !nasm_stricmp(value, "itanic") || + !nasm_stricmp(value, "merced")) + iflag_set(&r, IF_IA64); + else { + iflag_set(&r, IF_PLEVEL); + nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL, + "unknown 'cpu' type"); + } + return r; } static int get_bits(char *value) @@ -2053,13 +2068,13 @@ static int get_bits(char *value) if ((i = atoi(value)) == 16) return i; /* set for a 16-bit segment */ else if (i == 32) { - if (cpu < IF_386) { + if (iflag_ffs(&cpu) < IF_386) { nasm_error(ERR_NONFATAL, "cannot specify 32-bit segment on processor below a 386"); i = 16; } } else if (i == 64) { - if (cpu < IF_X86_64) { + if (iflag_ffs(&cpu) < IF_X86_64) { nasm_error(ERR_NONFATAL, "cannot specify 64-bit segment on processor below an x86-64"); i = 16; diff --git a/ndisasm.c b/ndisasm.c index 638299ff..3212629f 100644 --- a/ndisasm.c +++ b/ndisasm.c @@ -88,7 +88,7 @@ int main(int argc, char **argv) bool autosync = false; int bits = 16, b; bool eof = false; - iflags_t prefer = 0; + iflag_t prefer; bool rn_error; int32_t offset; FILE *fp; @@ -96,6 +96,7 @@ int main(int argc, char **argv) tolower_init(); nasm_set_verror(ndisasm_verror); nasm_init_malloc_error(); + iflag_clear_all(&prefer); offset = 0; init_sync(); @@ -229,14 +230,20 @@ int main(int argc, char **argv) return 1; } if (!strcmp(v, "intel")) { - prefer = 0; /* Default */ + iflag_clear_all(&prefer); /* default */ } else if (!strcmp(v, "amd")) { - prefer = IF_AMD | IF_3DNOW; + iflag_clear_all(&prefer); + iflag_set(&prefer, IF_AMD); + iflag_set(&prefer, IF_3DNOW); } else if (!strcmp(v, "cyrix")) { - prefer = IF_CYRIX | IF_3DNOW; - } else if (!strcmp(v, "idt") || !strcmp(v, "centaur") - || !strcmp(v, "winchip")) { - prefer = IF_3DNOW; + iflag_clear_all(&prefer); + iflag_set(&prefer, IF_CYRIX); + iflag_set(&prefer, IF_3DNOW); + } else if (!strcmp(v, "idt") || + !strcmp(v, "centaur") || + !strcmp(v, "winchip")) { + iflag_clear_all(&prefer); + iflag_set(&prefer, IF_3DNOW); } else { fprintf(stderr, "%s: unknown vendor `%s' specified with `-p'\n", @@ -311,7 +318,7 @@ int main(int argc, char **argv) while (p > q && (p - q >= INSN_MAX || lenread == 0)) { lendis = disasm((uint8_t *) q, outbuf, sizeof(outbuf), bits, - offset, autosync, prefer); + offset, autosync, &prefer); if (!lendis || lendis > (p - q) || ((nextsync || synclen) && (uint32_t)lendis > nextsync - offset))