From: H. P. A. <hp...@us...> - 2007-04-17 20:23:17
|
Update of /cvsroot/nasm/nasm In directory sc8-pr-cvs16:/tmp/cvs-serv10885 Modified Files: assemble.c disasm.c insns.dat insns.h nasm.c nasmlib.c nasmlib.h Log Message: Handle "LOCK as REX.R" for MOV CRx; fix warning for invalid 64-bit regs - MOV gpr,CRx or MOV CRx,gpr can access high control registers with a LOCK prefix; handle that in both the assembler and disassembler. - Get a saner error message when trying to access high resources in non-64-bit mode. Index: assemble.c =================================================================== RCS file: /cvsroot/nasm/nasm/assemble.c,v retrieving revision 1.40 retrieving revision 1.41 diff -u -d -r1.40 -r1.41 --- assemble.c 16 Apr 2007 15:46:46 -0000 1.40 +++ assemble.c 17 Apr 2007 20:23:11 -0000 1.41 @@ -67,6 +67,7 @@ * \332 - disassemble a rep (0xF3 byte) prefix as repe not rep. * \333 - REP prefix (0xF3 byte); for SSE instructions. Not encoded * as a literal byte in order to aid the disassembler. + * \334 - LOCK prefix used instead of REX.R * \340 - reserve <operand 0> bytes of uninitialized storage. * Operand 0 had better be a segmentless constant. * \370,\371,\372 - match only if operand 0 meets byte jump criteria. @@ -108,6 +109,18 @@ static ea *process_ea(operand *, ea *, int, int, int); static int chsize(operand *, int); +static void assert_no_prefix(insn * ins, int prefix) +{ + int j; + + for (j = 0; j < ins->nprefix; j++) { + if (ins->prefixes[j] == prefix) { + errfunc(ERR_NONFATAL, "invalid %s prefix", prefix_name(prefix)); + break; + } + } +} + /* * This routine wrappers the real output format's output routine, * in order to pass a copy of the data off to the listing file @@ -455,7 +468,9 @@ break; case P_A16: if (bits == 64) { - error(ERR_PANIC, "16-bit addressing is deprecated in 64-bit mode"); + error(ERR_NONFATAL, + "16-bit addressing is not supported " + "in 64-bit mode"); break; } if (bits != 16) @@ -512,7 +527,9 @@ else if (size_prob == 3) error(ERR_NONFATAL, "no instruction for this cpu level"); else if (size_prob == 4) - error(ERR_NONFATAL, "instruction deprecated in 64-bit mode"); + error(ERR_NONFATAL, "instruction not supported in 64-bit mode"); + else if (size_prob == 5) + error(ERR_NONFATAL, "invalid operands in non-64-bit mode"); else error(ERR_NONFATAL, "invalid combination of opcode and operands"); @@ -680,6 +697,7 @@ int t; ins->rex = 0; /* Ensure REX is reset */ int rex_mask = 0xFF; + int lock_is_rex_r = 0; (void)segment; /* Don't warn that this parameter is unused */ (void)offset; /* Don't warn that this parameter is unused */ @@ -700,17 +718,15 @@ case 010: case 011: case 012: - if (bits == 64) { - t = regval(&ins->oprs[c - 010]); - if (t >= 0400 && t < 0500) { /* Calculate REX.B */ - if (t < 0410 || (t >= 0440 && t < 0450)) - ins->rex |= 0xF0; /* Set REX.0 */ - else - ins->rex |= 0xF1; /* Set REX.B */ - if (t >= 0440) - ins->rex |= 0xF8; /* Set REX.W */ - } - } + t = regval(&ins->oprs[c - 010]); + if (t >= 0400 && t < 0500) { /* Calculate REX.B */ + if (t < 0410 || (t >= 0440 && t < 0450)) + ins->rex |= 0xF0; /* Set REX.0 */ + else + ins->rex |= 0xF1; /* Set REX.B */ + if (t >= 0440) + ins->rex |= 0xF8; /* Set REX.W */ + } codes++, length++; break; case 017: @@ -811,15 +827,14 @@ case 0300: case 0301: case 0302: - if (bits == 64) { /* Calculate REX */ - t = ins->oprs[c - 0300].basereg; - if (t >= EXPR_REG_START && t < REG_ENUM_LIMIT) { - t = regvals[t]; - if ((t >= 0410 && t < 0440) || (t >= 0450 && t < 0500)) { - ins->rex |= 0xF1; /* Set REX.B */ - } - } - } + /* Calculate REX */ + t = ins->oprs[c - 0300].basereg; + if (t >= EXPR_REG_START && t < REG_ENUM_LIMIT) { + t = regvals[t]; + if ((t >= 0410 && t < 0440) || (t >= 0450 && t < 0500)) { + ins->rex |= 0xF1; /* Set REX.B */ + } + } length += chsize(&ins->oprs[c - 0300], bits); break; case 0310: @@ -856,6 +871,10 @@ case 0333: length++; break; + case 0334: + assert_no_prefix(ins, P_LOCK); + lock_is_rex_r = 1; + break; case 0340: case 0341: case 0342: @@ -878,13 +897,10 @@ int rfield; ea_data.rex = 0; /* Ensure ea.REX is initially 0 */ - if (bits == 64) { - if (c <= 0177) /* pick rfield from operand b */ - rfield = regval(&ins->oprs[c & 7]); - else - rfield = c & 7; - } else - rfield = 0; + if (c <= 0177) /* pick rfield from operand b */ + rfield = regval(&ins->oprs[c & 7]); + else + rfield = c & 7; if (!process_ea (&ins->oprs[(c >> 3) & 7], &ea_data, bits, @@ -892,8 +908,7 @@ errfunc(ERR_NONFATAL, "invalid effective address"); return -1; } else { - if (bits == 64) - ins->rex |= ea_data.rex; + ins->rex |= ea_data.rex; length += ea_data.size; } } else @@ -901,13 +916,17 @@ ": instruction code 0x%02X given", c); } - if (bits == 64) { - ins->rex &= rex_mask; - if (ins->rex) - length += 1; + ins->rex &= rex_mask; + if (ins->rex) { + if (bits == 64 || + (lock_is_rex_r && ins->rex == 0xf4 && cpu >= IF_X86_64)) + length++; + else + errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode"); } -return length; } + return length; +} static void gencode(int32_t segment, int32_t offset, int bits, insn * ins, const char *codes, int32_t insn_end) @@ -1347,6 +1366,14 @@ offset += 1; break; + case 0334: + if (ins->rex & 0x04) { + *bytes = 0xF0; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + } + break; + case 0340: case 0341: case 0342: @@ -1509,7 +1536,7 @@ size[i] = BITS32; } else if (itemp->flags & IF_SQ) { if (bits != 64) - return 2; + return 5; size[i] = BITS64; } } else { @@ -1525,7 +1552,7 @@ oprs = itemp->operands; } else if (itemp->flags & IF_SQ) { if (bits != 64) - return 2; + return 5; asize = BITS64; oprs = itemp->operands; } @@ -1555,7 +1582,7 @@ if ( (((itemp->opd[i] & SIZE_MASK) == BITS64) || ((instruction->oprs[i].type & SIZE_MASK) == BITS64)) && bits != 64) - return 2; + return 5; x = instruction->oprs[i].indexreg; b = instruction->oprs[i].basereg; Index: insns.dat =================================================================== RCS file: /cvsroot/nasm/nasm/insns.dat,v retrieving revision 1.54 retrieving revision 1.55 diff -u -d -r1.54 -r1.55 --- insns.dat 16 Apr 2007 18:16:46 -0000 1.54 +++ insns.dat 17 Apr 2007 20:23:11 -0000 1.55 @@ -679,9 +679,9 @@ MOV mem_offs,reg_ax \300\320\1\xA3\44 8086,SM MOV mem_offs,reg_eax \300\321\1\xA3\44 386,SM MOV mem_offs,reg_rax \300\324\1\xA3\44 X64,SM -MOV reg32,reg_creg \2\x0F\x20\101 386,PRIV +MOV reg32,reg_creg \334\2\x0F\x20\101 386,PRIV,NOLONG MOV reg64,reg_creg \323\2\x0F\x20\101 X64,PRIV -MOV reg_creg,reg32 \2\x0F\x22\110 386,PRIV +MOV reg_creg,reg32 \334\2\x0F\x22\110 386,PRIV,NOLONG MOV reg_creg,reg64 \323\2\x0F\x22\110 X64,PRIV MOV reg32,reg_dreg \2\x0F\x21\101 386,PRIV MOV reg64,reg_dreg \323\2\x0F\x21\101 X64,PRIV Index: nasm.c =================================================================== RCS file: /cvsroot/nasm/nasm/nasm.c,v retrieving revision 1.50 retrieving revision 1.51 diff -u -d -r1.50 -r1.51 --- nasm.c 14 Apr 2007 00:46:25 -0000 1.50 +++ nasm.c 17 Apr 2007 20:23:11 -0000 1.51 @@ -1693,7 +1693,7 @@ return IF_PRESCOTT; if (!nasm_stricmp(value, "x64") || !nasm_stricmp(value, "x86-64")) - return IF_X64; + return IF_X86_64; if (!nasm_stricmp(value, "ia64") || !nasm_stricmp(value, "ia-64") || !nasm_stricmp(value, "itanium") || @@ -1719,7 +1719,7 @@ i = 16; } } else if (i == 64) { - if (cpu < IF_X64) { + if (cpu < IF_X86_64) { report_error(ERR_NONFATAL, "cannot specify 64-bit segment on processor below an x86-64"); i = 16; Index: nasmlib.h =================================================================== RCS file: /cvsroot/nasm/nasm/nasmlib.h,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- nasmlib.h 13 Apr 2007 16:47:55 -0000 1.12 +++ nasmlib.h 17 Apr 2007 20:23:11 -0000 1.13 @@ -271,4 +271,6 @@ extern struct dfmt null_debug_form; extern struct dfmt *null_debug_arr[2]; +const char *prefix_name(int); + #endif Index: disasm.c =================================================================== RCS file: /cvsroot/nasm/nasm/disasm.c,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- disasm.c 16 Apr 2007 02:39:56 -0000 1.24 +++ disasm.c 17 Apr 2007 20:23:11 -0000 1.25 @@ -115,9 +115,6 @@ if (regval < 0 || regval > 15) return 0; - if (!(rex & REX_P) && regval > 7) - return 0; /* Internal error! */ - if (!((REGMEM | BITS8) & ~regflags)) { if (rex & REX_P) return rd_reg8_rex[regval]; @@ -322,7 +319,7 @@ */ static int matches(struct itemplate *t, uint8_t *data, int asize, int osize, int segsize, int rep, insn * ins, - int rex, int *rexout) + int rex, int *rexout, int lock) { uint8_t *r = (uint8_t *)(t->code); uint8_t *origdata = data; @@ -331,13 +328,8 @@ *rexout = rex; - if (segsize == 64) { - if (t->flags & IF_NOLONG) - return FALSE; - } else { - if (t->flags & IF_X64) - return FALSE; - } + if (t->flags & (segsize == 64 ? IF_NOLONG : IF_LONG)) + return FALSE; if (rep == 0xF2) drep = P_REPNE; @@ -559,21 +551,26 @@ if (rep != 0xF3) return FALSE; drep = 0; - } + } else if (c == 0334) { + if (lock) { + rex |= REX_R; + lock = 0; + } + } } /* * Check for unused rep or a/o prefixes. */ ins->nprefix = 0; + if (lock) + ins->prefixes[ins->nprefix++] = P_LOCK; if (drep) ins->prefixes[ins->nprefix++] = drep; if (!a_used && asize != segsize) ins->prefixes[ins->nprefix++] = asize == 16 ? P_A16 : P_A32; - if (!o_used && osize == ((segsize == 16) ? 32 : 16)) { - fprintf(stderr, "osize = %d, segsize = %d\n", osize, segsize); + if (!o_used && osize == ((segsize == 16) ? 32 : 16)) ins->prefixes[ins->nprefix++] = osize == 16 ? P_O16 : P_O32; - } /* Fix: check for redundant REX prefixes */ @@ -645,8 +642,8 @@ best_p = NULL; best_rex = 0; for (p = itable[*data]; *p; p++) { - if ((length = matches(*p, data, asize, osize, - segsize, rep, &tmp_ins, rex, &rexout))) { + if ((length = matches(*p, data, asize, osize, segsize, rep, + &tmp_ins, rex, &rexout, lock))) { works = TRUE; /* * Final check to make sure the types of r/m match up. @@ -703,10 +700,11 @@ * the return value is "sane." Maybe a macro wrapper could * be used for that purpose. */ - if (lock) - slen += snprintf(output + slen, outbufsize - slen, "lock "); for (i = 0; i < ins.nprefix; i++) switch (ins.prefixes[i]) { + case P_LOCK: + slen += snprintf(output + slen, outbufsize - slen, "lock "); + break; case P_REP: slen += snprintf(output + slen, outbufsize - slen, "rep "); break; Index: nasmlib.c =================================================================== RCS file: /cvsroot/nasm/nasm/nasmlib.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- nasmlib.c 14 Apr 2007 00:46:25 -0000 1.23 +++ nasmlib.c 17 Apr 2007 20:23:11 -0000 1.24 @@ -669,6 +669,15 @@ "repnz", "repz", "times" }; +const char *prefix_name(int token) +{ + unsigned int prefix = token-PREFIX_ENUM_START; + if (prefix > sizeof prefix_names / sizeof(const char *)) + return NULL; + + return prefix_names[prefix]; +} + /* * Standard scanner routine used by parser.c and some output * formats. It keeps a succession of temporary-storage strings in Index: insns.h =================================================================== RCS file: /cvsroot/nasm/nasm/insns.h,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- insns.h 13 Apr 2007 16:47:54 -0000 1.34 +++ insns.h 17 Apr 2007 20:23:11 -0000 1.35 @@ -81,10 +81,11 @@ #define IF_SSE2 0x00020000UL /* it's a SSE2 instruction */ #define IF_SSE3 0x00040000UL /* it's a SSE3 (PNI) instruction */ #define IF_VMX 0x00080000UL /* it's a VMX instruction */ +#define IF_LONG 0x00100000UL /* long mode instruction */ #define IF_PMASK 0xFF000000UL /* the mask for processor types */ #define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */ /* also the highest possible processor */ -#define IF_PFMASK 0xF001FF00UL /* the mask for disassembly "prefer" */ +#define IF_PFMASK 0xF01FFF00UL /* the mask for disassembly "prefer" */ #define IF_8086 0x00000000UL /* 8086 instruction */ #define IF_186 0x01000000UL /* 186+ instruction */ #define IF_286 0x02000000UL /* 286+ instruction */ @@ -95,8 +96,9 @@ #define IF_KATMAI 0x07000000UL /* Katmai instructions */ #define IF_WILLAMETTE 0x08000000UL /* Willamette instructions */ #define IF_PRESCOTT 0x09000000UL /* Prescott instructions */ -#define IF_X64 0x0A000000UL /* x86-64 instructions */ -#define IF_IA64 0x0F000000UL /* IA64 instructions */ +#define IF_X86_64 0x0A000000UL /* x86-64 instruction (long or legacy mode) */ +#define IF_X64 (IF_LONG|IF_X86_64) +#define IF_IA64 0x0F000000UL /* IA64 instructions (in x86 mode) */ #define IF_CYRIX 0x10000000UL /* Cyrix-specific instruction */ #define IF_AMD 0x20000000UL /* AMD-specific instruction */ |