diff --git a/assemble.c b/assemble.c index 4669ebd6..409124bb 100644 --- a/assemble.c +++ b/assemble.c @@ -85,6 +85,7 @@ #include "assemble.h" #include "insns.h" #include "preproc.h" +#include "regflags.c" #include "regvals.c" extern struct itemplate *nasm_instructions[]; @@ -103,10 +104,12 @@ static ListGen *list; static int32_t calcsize(int32_t, int32_t, int, insn *, const char *); static void gencode(int32_t, int32_t, int, insn *, const char *, int32_t); -static int regval(operand * o); -// static int regflag(operand * o); static int matches(struct itemplate *, insn *, int bits); -static ea *process_ea(operand *, ea *, int, int, int); +static int32_t regflag(const operand *); +static int32_t regval(const operand *); +static int rexflags(int, int32_t, int); +static int op_rexflags(const operand *, int); +static ea *process_ea(operand *, ea *, int, int, int, int); static int chsize(operand *, int); static void assert_no_prefix(insn * ins, int prefix) @@ -694,9 +697,7 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, { int32_t length = 0; uint8_t c; - int t; - int rex_mask = 0xFF; - int lock_is_rex_r = 0; + int rex_mask = ~0; ins->rex = 0; /* Ensure REX is reset */ (void)segment; /* Don't warn that this parameter is unused */ @@ -718,15 +719,8 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, case 010: case 011: case 012: - 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 */ - } + ins->rex |= + op_rexflags(&ins->oprs[c - 010], REX_B|REX_H|REX_P|REX_W); codes++, length++; break; case 017: @@ -827,14 +821,6 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, case 0300: case 0301: case 0302: - /* 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: @@ -857,10 +843,10 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, case 0322: break; case 0323: - rex_mask = 0x07; + rex_mask &= ~REX_W; break; case 0324: - ins->rex |= 0xF8; + ins->rex |= REX_W; break; case 0330: codes++, length++; @@ -873,7 +859,7 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, break; case 0334: assert_no_prefix(ins, P_LOCK); - lock_is_rex_r = 1; + ins->rex |= REX_L; break; case 0340: case 0341: @@ -895,16 +881,21 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, if (c >= 0100 && c <= 0277) { /* it's an EA */ ea ea_data; int rfield; + int32_t rflags; ea_data.rex = 0; /* Ensure ea.REX is initially 0 */ - if (c <= 0177) /* pick rfield from operand b */ - rfield = regval(&ins->oprs[c & 7]); - else + if (c <= 0177) { + /* pick rfield from operand b */ + rflags = regflag(&ins->oprs[c & 7]); + rfield = regvals[ins->oprs[c & 7].basereg]; + } else { + rflags = 0; rfield = c & 7; + } if (!process_ea (&ins->oprs[(c >> 3) & 7], &ea_data, bits, - rfield, ins->forw_ref)) { + rfield, rflags, ins->forw_ref)) { errfunc(ERR_NONFATAL, "invalid effective address"); return -1; } else { @@ -917,9 +908,14 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, } ins->rex &= rex_mask; - if (ins->rex) { - if (bits == 64 || - (lock_is_rex_r && ins->rex == 0xf4 && cpu >= IF_X86_64)) { + if (ins->rex & REX_REAL) { + if (ins->rex & REX_H) { + errfunc(ERR_NONFATAL, "cannot use high register in rex instruction"); + return -1; + } else if (bits == 64 || + ((ins->rex & REX_L) && + !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) && + cpu >= IF_X86_64)) { length++; } else { errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode"); @@ -930,6 +926,14 @@ static int32_t calcsize(int32_t segment, int32_t offset, int bits, return length; } +#define EMIT_REX() \ + if((ins->rex & REX_REAL) && (bits == 64)) { \ + ins->rex = (ins->rex & REX_REAL)|REX_P; \ + out(offset, segment, &ins->rex, OUT_RAWDATA+1, NO_SEG, NO_SEG); \ + ins->rex = 0; \ + offset += 1; \ + } + static void gencode(int32_t segment, int32_t offset, int bits, insn * ins, const char *codes, int32_t insn_end) { @@ -948,12 +952,7 @@ static void gencode(int32_t segment, int32_t offset, int bits, case 01: case 02: case 03: - if(ins->rex && (bits == 64)) { /* REX Supercedes all other Prefixes */ - ins->rex = (ins->rex&0x0F)+0x40; - out(offset, segment, &ins->rex, OUT_RAWDATA + 1, NO_SEG, NO_SEG); - ins->rex = 0; - offset += 1; - } + EMIT_REX(); out(offset, segment, codes, OUT_RAWDATA + c, NO_SEG, NO_SEG); codes += c; offset += c; @@ -1002,12 +1001,7 @@ static void gencode(int32_t segment, int32_t offset, int bits, case 010: case 011: case 012: - if(ins->rex && (bits == 64)) { /* REX Supercedes all other Prefixes */ - ins->rex = (ins->rex&0x0F)+0x40; - out(offset, segment, &ins->rex, OUT_RAWDATA + 1, NO_SEG, NO_SEG); - ins->rex = 0; - offset += 1; - } + EMIT_REX(); bytes[0] = *codes++ + ((regval(&ins->oprs[c - 010])) & 7); out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); offset += 1; @@ -1238,12 +1232,7 @@ static void gencode(int32_t segment, int32_t offset, int bits, case 0133: case 0134: case 0135: - if(ins->rex && (bits == 64)) { /* REX Supercedes all other Prefixes */ - ins->rex = (ins->rex&0x0F)+0x40; - out(offset, segment, &ins->rex, OUT_RAWDATA + 1, NO_SEG, NO_SEG); - ins->rex = 0; - offset += 1; - } + EMIT_REX(); codes++; bytes[0] = *codes++; if (is_sbyte(ins, c - 0133, 16)) @@ -1271,12 +1260,7 @@ static void gencode(int32_t segment, int32_t offset, int bits, case 0143: case 0144: case 0145: - if(ins->rex && (bits == 64)) { /* REX Supercedes all other Prefixes */ - ins->rex = (ins->rex&0x0F)+0x40; - out(offset, segment, &ins->rex, OUT_RAWDATA + 1, NO_SEG, NO_SEG); - ins->rex = 0; - offset += 1; - } + EMIT_REX(); codes++; bytes[0] = *codes++; if (is_sbyte(ins, c - 0143, 32)) @@ -1349,7 +1333,7 @@ static void gencode(int32_t segment, int32_t offset, int bits, break; case 0324: - ins->rex |= 0xF8; + ins->rex |= REX_W; break; case 0330: @@ -1369,11 +1353,12 @@ static void gencode(int32_t segment, int32_t offset, int bits, break; case 0334: - if (ins->rex & 0x04) { + if (ins->rex & REX_R) { *bytes = 0xF0; out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); offset += 1; } + ins->rex &= ~(REX_L|REX_R); break; case 0340: @@ -1402,20 +1387,26 @@ static void gencode(int32_t segment, int32_t offset, int bits, break; default: /* can't do it by 'case' statements */ - if ( c >= 0100 && c <= 0277) { /* it's an EA */ + if (c >= 0100 && c <= 0277) { /* it's an EA */ ea ea_data; int rfield; + int32_t rflags; uint8_t *p; int32_t s; - if (c <= 0177) /* pick rfield from operand b */ - rfield = regval(&ins->oprs[c & 7]); - else /* rfield is constant */ + if (c <= 0177) { + /* pick rfield from operand b */ + rflags = regflag(&ins->oprs[c & 7]); + rfield = regvals[ins->oprs[c & 7].basereg]; + } else { + /* rfield is constant */ + rflags = 0; rfield = c & 7; + } if (!process_ea - (&ins->oprs[(c >> 3) & 7], &ea_data, bits, rfield, - ins->forw_ref)) { + (&ins->oprs[(c >> 3) & 7], &ea_data, bits, + rfield, rflags, ins->forw_ref)) { errfunc(ERR_NONFATAL, "invalid effective address"); } @@ -1464,7 +1455,15 @@ static void gencode(int32_t segment, int32_t offset, int bits, } } -static int regval(operand * o) +static int regflag(const operand * o) +{ + if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) { + errfunc(ERR_PANIC, "invalid operand passed to regflag()"); + } + return reg_flags[o->basereg]; +} + +static int regval(const operand * o) { if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) { errfunc(ERR_PANIC, "invalid operand passed to regval()"); @@ -1472,6 +1471,37 @@ static int regval(operand * o) return regvals[o->basereg]; } +static int op_rexflags(const operand * o, int mask) +{ + int32_t flags; + int val; + + if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) { + errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()"); + } + + flags = reg_flags[o->basereg]; + val = regvals[o->basereg]; + + return rexflags(val, flags, mask); +} + +static int rexflags(int val, int32_t flags, int mask) +{ + int rex = 0; + + if (val >= 8) + rex |= REX_B|REX_X|REX_R; + if (flags & BITS64) + rex |= REX_W; + if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */ + rex |= REX_H; + else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */ + rex |= REX_P; + + return rex & mask; +} + static int matches(struct itemplate *itemp, insn * instruction, int bits) { int i, b, x, size[3], asize, oprs, ret; @@ -1620,41 +1650,29 @@ static int matches(struct itemplate *itemp, insn * instruction, int bits) } static ea *process_ea(operand * input, ea * output, int addrbits, - int rfield, int forw_ref) + int rfield, int32_t rflags, int forw_ref) { int rip = FALSE; /* Used for RIP-relative addressing */ - + /* REX flags for the rfield operand */ + output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H); + if (!(REGISTER & ~input->type)) { /* register direct */ int i; - if ( input->basereg < EXPR_REG_START /* Verify as Register */ + int32_t f; + + if (input->basereg < EXPR_REG_START /* Verify as Register */ || input->basereg >= REG_ENUM_LIMIT) return NULL; + f = regflag(input); i = regvals[input->basereg]; - if ( i >= 0100 && i < 0210) /* GPR's, MMX & XMM only */ - return NULL; - - if (i >= 0400 && i < 0500) { /* Calculate REX.B */ - if (i < 0410 || (i >= 0440 && i < 0450)) - output->rex |= 0xF0; /* Set REX.0 */ - else - output->rex |= 0xF1; /* Set REX.B */ - if (i >= 0440) - output->rex |= 0xF8; /* Set REX.W */ - } - if ((rfield >= 0400 && rfield < 0500) || /* Calculate REX.R */ - (rfield >= 0120 && rfield < 0200 && /* Include CR/DR/TR... */ - !(rfield & 0010))) { /* ... extensions, only */ - if ((rfield >= 0400 && rfield < 0410) || (rfield >= 0440 && rfield < 0450)) - output->rex |= 0xF0; /* Set REX.0 */ - else - output->rex |= 0xF4; /* Set REX.R */ - if (rfield >= 0440) - output->rex |= 0xF8; /* Set REX.W */ - } - + if (REG_EA & ~f) + return NULL; /* Invalid EA register */ + + output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H); + output->sib_present = FALSE; /* no SIB necessary */ output->bytes = 0; /* no offset necessary either */ output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7); @@ -1665,16 +1683,7 @@ static ea *process_ea(operand * input, ea * output, int addrbits, /* it's a pure offset */ if (input->addr_size) addrbits = input->addr_size; - - if (rfield >= 0400 && rfield < 0500) { /* Calculate REX.R */ - if (rfield < 0410 || (rfield >= 0440 && rfield < 0450)) - output->rex |= 0xF0; /* Set REX.0 */ - else - output->rex |= 0xF4; /* Set REX.R */ - if (rfield >= 0440) - output->rex |= 0xF8; /* Set REX.W */ - } - + output->sib_present = FALSE; output->bytes = (addrbits != 16 ? 4 : 2); output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3); @@ -1684,108 +1693,94 @@ static ea *process_ea(operand * input, ea * output, int addrbits, int hb = input->hintbase, ht = input->hinttype; int t; int it, bt; + int32_t ix, bx; /* register flags */ if (s == 0) i = -1; /* make this easy, at least */ - if (i != -1 && i >= EXPR_REG_START - && i < REG_ENUM_LIMIT) + if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) { it = regvals[i]; - else + ix = reg_flags[i]; + } else { it = -1; + ix = 0; + } - if (b != -1 && b >= EXPR_REG_START - && b < REG_ENUM_LIMIT) + if (b != -1 && b >= EXPR_REG_START && b < REG_ENUM_LIMIT) { bt = regvals[b]; - else + bx = reg_flags[b]; + } else { bt = -1; + bx = 0; + } - /* check for a 32/64-bit memory reference... */ - if ((it >= 0020 && it < 0030) || (it >= 0430 && it < 0460) || - (bt >= 0020 && bt < 0030) || (bt >= 0430 && bt < 0460) || - bt == 0500) { + /* check for a 32/64-bit memory reference... */ + if ((ix|bx) & (BITS32|BITS64)) { /* it must be a 32/64-bit memory reference. Firstly we have * to check that all registers involved are type E/Rxx. */ - t = 1; - if (it != -1) { - if (it < 0020 || (it >= 0030 && it < 0430) || it >= 0460) - return NULL; - if (it >= 0440) - t = 2; - else - t = 0; - } + int32_t sok = BITS32|BITS64; - if (bt != -1) { - if (bt < 0020 || (bt >= 0030 && bt < 0430) || (bt >= 0460 && bt < 0500)) - return NULL; - if (bt == 0500) { - bt = b = -1; - rip = TRUE; - } else if (bt >= 0440) { - if (t < 1) - return NULL; - } else { - if (t > 1) - return NULL; - } - } + if (it != -1) { + if (!(REG64 & ~ix) || !(REG32 & ~ix)) + sok &= ix; + else + return NULL; + } + + if (bt != -1) { + if ((REG_GPR & ~bx) && (IP_REG & ~bx)) + return NULL; /* Invalid register */ + if (sok & ~bx) + return NULL; /* Invalid size */ + sok &= ~bx; + if (!(IP_REG & ~bx)) { + bt = b = -1; + rip = TRUE; + } + } /* While we're here, ensure the user didn't specify WORD. */ - if (input->addr_size == 16) + if (input->addr_size == 16 || + (input->addr_size == 32 && !(sok & BITS32)) || + (input->addr_size == 64 && !(sok & BITS64))) return NULL; /* now reorganize base/index */ if (s == 1 && bt != it && bt != -1 && it != -1 && - ((hb == bt && ht == EAH_NOTBASE) - || (hb == it && ht == EAH_MAKEBASE))) - t = bt, bt = it, it = t; /* swap if hints say so */ + ((hb == b && ht == EAH_NOTBASE) + || (hb == i && ht == EAH_MAKEBASE))) { + /* swap if hints say so */ + t = bt, bt = it, it = t; + t = bx, bx = ix, ix = t; + } if (bt == it) /* convert EAX+2*EAX to 3*EAX */ - bt = -1, s++; - if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) - bt = i, it = -1; /* make single reg base, unless hint */ + bt = -1, bx = 0, s++; + if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) { + /* make single reg base, unless hint */ + bt = it, bx = ix, it = -1, ix = 0; + } if (((s == 2 && (it & 7) != (REG_NUM_ESP & 7) && !(input->eaflags & EAF_TIMESTWO)) || s == 3 || s == 5 || s == 9) && bt == -1) - bt = it, s--; /* convert 3*EAX to EAX+2*EAX */ + bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */ if (it == -1 && (bt & 7) != (REG_NUM_ESP & 7) && (input->eaflags & EAF_TIMESTWO)) - it = bt, bt = -1, s = 1; + it = bt, ix = bx, bt = -1, bx = 0, s = 1; /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */ - if (s == 1 && (it & 7) == (REG_NUM_ESP & 7)) /* swap ESP into base if scale is 1 */ + if (s == 1 && (it & 7) == (REG_NUM_ESP & 7)) { + /* swap ESP into base if scale is 1 */ t = it, it = bt, bt = t; + t = ix, ix = bx, bx = t; + } if ((it & 7) == (REG_NUM_ESP & 7) || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1)) return NULL; /* wrong, for various reasons */ - if (i >= 0400 && i < 0500) { /* Calculate REX.X */ - if (i < 0410 || (i >= 0440 && i < 0450)) - output->rex |= 0xF0; /* Set REX.0 */ - else - output->rex |= 0xF2; /* Set REX.X */ - if (i >= 0440) - output->rex |= 0xF8; /* Set REX.W */ - } - - if (b >= 0400 && b < 0500) { /* Calculate REX.B */ - if (b < 0410 || (b >= 0440 && b < 0450)) - output->rex |= 0xF0; /* Set REX.0 */ - else - output->rex |= 0xF1; /* Set REX.B */ - if (b >= 0440) - output->rex |= 0xF8; /* Set REX.W */ - } + output->rex |= rexflags(it, ix, REX_X); + output->rex |= rexflags(bt, bx, REX_B); - if (rfield >= 0400 && rfield < 0500) { /* Calculate REX.R */ - if (rfield < 0410 || (rfield >= 0440 && rfield < 0450)) - output->rex |= 0xF0; /* Set REX.0 */ - else - output->rex |= 0xF4; /* Set REX.R */ - if (rfield >= 0440) - output->rex |= 0xF8; /* Set REX.W */ - } - - if (it == -1 && (bt & 7) != (REG_NUM_ESP & 7)) { /* no SIB needed */ + if (it == -1 && (bt & 7) != (REG_NUM_ESP & 7)) { + /* no SIB needed */ int mod, rm; if (bt == -1) { @@ -1810,7 +1805,8 @@ static ea *process_ea(operand * input, ea * output, int addrbits, output->sib_present = FALSE; output->bytes = (bt == -1 || mod == 2 ? 4 : mod); output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm; - } else { /* we need a SIB */ + } else { + /* we need a SIB */ int mod, scale, index, base; if (it == -1) @@ -1859,6 +1855,26 @@ static ea *process_ea(operand * input, ea * output, int addrbits, output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4; output->sib = (scale << 6) | (index << 3) | base; } + + /* Process RIP-relative Addressing */ + if (rip) { + if (globalbits != 64 || + (output->modrm & 0xC7) != 0x05) + return NULL; + output->rip = TRUE; + } else { + output->rip = FALSE; + /* Actual Disp32 needs blank SIB on x64 */ + if (globalbits == 64 && + !(output->sib_present) && + ((output->modrm & 0xC7) == 0x05)) { + output->sib_present = TRUE; + /* RM Field = 4 (forward to Base of SIB) */ + output->modrm--; + /* Index = 4 (none), Base = 5 */ + output->sib = (4 << 3) | 5; + } + } } else { /* it's 16-bit */ int mod, rm; @@ -1948,20 +1964,6 @@ static ea *process_ea(operand * input, ea * output, int addrbits, } } - /* Process RIP-relative Addressing */ - if (rip) { - if ((output->modrm & 0xC7) != 0x05) - return NULL; - output->rip = TRUE; - } else { - output->rip = FALSE; - if (globalbits == 64 && /* Actual Disp32 needs blank SIB on x64 */ - !(output->sib_present) && ((output->modrm & 0xC7) == 0x05)) { - output->sib_present = TRUE; - output->modrm --; /* RM Field = 4 (forward to Base of SIB) */ - output->sib = (4 << 3) | 5; /* Index = 4 (none), Base = 5 */ - } - } output->size = 1 + output->sib_present + output->bytes; return output; } @@ -1969,19 +1971,19 @@ static ea *process_ea(operand * input, ea * output, int addrbits, static int chsize(operand * input, int addrbits) { if (!(MEMORY & ~input->type)) { - int i, b; + int32_t i, b; - if ( input->indexreg < EXPR_REG_START /* Verify as Register */ + if (input->indexreg < EXPR_REG_START /* Verify as Register */ || input->indexreg >= REG_ENUM_LIMIT) i = -1; else - i = regvals[input->indexreg]; + i = reg_flags[input->indexreg]; - if ( input->basereg < EXPR_REG_START /* Verify as Register */ + if (input->basereg < EXPR_REG_START /* Verify as Register */ || input->basereg >= REG_ENUM_LIMIT) b = -1; else - b = regvals[input->basereg]; + b = reg_flags[input->basereg]; if (input->scale == 0) i = -1; @@ -1989,11 +1991,11 @@ static int chsize(operand * input, int addrbits) if (i == -1 && b == -1) /* pure offset */ return (input->addr_size != 0 && input->addr_size != addrbits); - if ((i >= 0020 && i < 0030) || (i >= 0430 && i < 0440) || - (b >= 0020 && b < 0030) || (b >= 0430 && b < 0440)) + if (!(REG32 & ~i) || !(REG32 & ~b)) return (addrbits != 32); else return (addrbits == 32); - } else + } else { return 0; + } } diff --git a/disasm.c b/disasm.c index b7fd224b..fcc0c54b 100644 --- a/disasm.c +++ b/disasm.c @@ -35,15 +35,6 @@ extern struct itemplate **itable[]; #define SEG_SIGNED 128 #define SEG_64BIT 256 -/* - * REX flags - */ -#define REX_P 0x40 /* REX prefix present */ -#define REX_W 0x08 /* 64-bit operand size */ -#define REX_R 0x04 /* ModRM reg extension */ -#define REX_X 0x02 /* SIB index extension */ -#define REX_B 0x01 /* ModRM r/m extension */ - #include "regdis.c" #define getu8(x) (*(uint8_t *)(x)) diff --git a/nasm.h b/nasm.h index da66d3e7..8a110aed 100644 --- a/nasm.h +++ b/nasm.h @@ -374,7 +374,7 @@ enum { * The basic concept here is that * (class & ~operand) == 0 * - * if and only if "operand" is of type "class". + * if and only if "operand" belongs to class type "class". * * The bits are assigned as follows: * @@ -478,8 +478,8 @@ enum { #define EIPREG 0x00801004L /* EIP */ #define FPUREG 0x01001000L /* floating point stack registers */ #define FPU0 0x01011000L /* FPU stack register zero */ -#define MMXREG 0x02001008L /* MMX registers */ -#define XMMREG 0x04001001L /* XMM Katmai reg */ +#define MMXREG 0x02009008L /* MMX registers */ +#define XMMREG 0x04009001L /* XMM Katmai reg */ #define REG_CDT 0x00101004L /* CRn, DRn and TRn */ #define REG_CREG 0x00111004L /* CRn */ #define REG_DREG 0x00121004L /* DRn */ @@ -490,8 +490,8 @@ enum { #define REG_FSGS 0x00441002L /* FS, GS */ #define REG_SEG67 0x00481002L /* Unimplemented segment registers */ -#define REG_RIP 0x00809008L /* RIP relative addressing */ -#define REG_EIP 0x00809004L /* EIP relative addressing */ +#define REG_RIP 0x00801008L /* RIP relative addressing */ +#define REG_EIP 0x00801004L /* EIP relative addressing */ /* Special GPRs */ #define REG_SMASK 0x000f0000L /* a mask for the following */ @@ -527,6 +527,18 @@ enum { /* condition code names */ C_NS, C_NZ, C_O, C_P, C_PE, C_PO, C_S, C_Z }; +/* + * REX flags + */ +#define REX_H 0x80 /* High register present, REX forbidden */ +#define REX_P 0x40 /* REX prefix present/required */ +#define REX_L 0x20 /* Use LOCK prefix instead of REX.R */ +#define REX_W 0x08 /* 64-bit operand size */ +#define REX_R 0x04 /* ModRM reg extension */ +#define REX_X 0x02 /* SIB index extension */ +#define REX_B 0x01 /* ModRM r/m extension */ +#define REX_REAL 0x4f /* Actual REX prefix bits */ + /* * Note that because segment registers may be used as instruction * prefixes, we must ensure the enumerations for prefixes and diff --git a/regs.dat b/regs.dat index 36f3d6ba..14cdd50f 100644 --- a/regs.dat +++ b/regs.dat @@ -4,152 +4,111 @@ # # The columns are: # -# register name, assembler class, disassembler class(es), -# NASM register number, x86 register number +# register name, assembler class, disassembler class(es), x86 register number # -# If the register name ends in +, then it is repeated 8 times -# with the following changes: -# - a numerical tail to register number is incremented -# - the NASM and x86 register numbers are incremented +# If the register name ends in two numbers separated by a dash, then it is +# repeated as many times as indicated, and the register number is +# updated with it. # -# For 16-register register sets, two + lines are required. -# - -# Legacy Registers -# 000-007 = 8-bit Registers -# 010-017 = 16-bit Registers -# 020-027 = 32-bit Registers - -# System Registers -# 100-107 = Segment Registers -# 110-127 = Control Registers -# 130-147 = Debug Registers -# 150-167 = Test Registers - -# Legacy Extended Registers -# 200-207 = FPU Registers -# 210-217 = MMX Registers -# 220-227 = XMM Registers (XMM0-XMM7) - -# x64 Extended Registers -# 404-407 = 8-bit Extensions (SIL/DIL/BPL/SPL) -# 410-417 = 8-bit Registers (R8B-R15B) -# 420-427 = 16-bit Registers (R8W-R15W) -# 430-437 = 32-bit Registers (R8D-R15D) -# 440-457 = 64-bit Registers (RAX-RDI+R8-R15) -# 460-467 = XMM Extended Registers (XMM8-XMM15) - -# Special Registers -# 0500 = RIP (for RIP-relative Addressing) - # General-purpose registers -al REG_AL reg8,reg8_rex 0000 0 -ah REG_HIGH reg8 0004 4 -ax REG_AX reg16 0010 0 -eax REG_EAX reg32 0020 0 -rax REG_RAX reg64 0440 0 -bl REG8 reg8,reg8_rex 0003 3 -bh REG_HIGH reg8 0007 7 -bx REG16 reg16 0013 3 -ebx REG32 reg32 0023 3 -rbx REG64 reg64 0443 3 -cl REG_CL reg8,reg8_rex 0001 1 -ch REG_HIGH reg8 0005 5 -cx REG_CX reg16 0011 1 -ecx REG_ECX reg32 0021 1 -rcx REG_RCX reg64 0441 1 -dl REG_DL reg8,reg8_rex 0002 2 -dh REG_HIGH reg8 0006 6 -dx REG_DX reg16 0012 2 -edx REG_EDX reg32 0022 2 -rdx REG_RDX reg64 0442 2 -spl REG8 reg8_rex 0404 4 -sp REG16 reg16 0014 4 -esp REG32 reg32 0024 4 -rsp REG64 reg64 0444 4 -bpl REG8 reg8_rex 0405 5 -bp REG16 reg16 0015 5 -ebp REG32 reg32 0025 5 -rbp REG64 reg64 0445 5 -sil REG8 reg8_rex 0406 6 -si REG16 reg16 0016 6 -esi REG32 reg32 0026 6 -rsi REG64 reg64 0446 6 -dil REG8 reg8_rex 0407 7 -di REG16 reg16 0017 7 -edi REG32 reg32 0027 7 -rdi REG64 reg64 0447 7 -r8b REG8 reg8_rex 0410 8 -r8w REG16 reg16 0420 8 -r8d REG32 reg32 0430 8 -r8 REG64 reg64 0450 8 -r9b REG8 reg8_rex 0411 9 -r9w REG16 reg16 0421 9 -r9d REG32 reg32 0431 9 -r9 REG64 reg64 0451 9 -r10b REG8 reg8_rex 0412 10 -r10w REG16 reg16 0422 10 -r10d REG32 reg32 0432 10 -r10 REG64 reg64 0452 10 -r11b REG8 reg8_rex 0413 11 -r11w REG16 reg16 0423 11 -r11d REG32 reg32 0433 11 -r11 REG64 reg64 0453 11 -r12b REG8 reg8_rex 0414 12 -r12w REG16 reg16 0424 12 -r12d REG32 reg32 0434 12 -r12 REG64 reg64 0454 12 -r13b REG8 reg8_rex 0415 13 -r13w REG16 reg16 0425 13 -r13d REG32 reg32 0435 13 -r13 REG64 reg64 0455 13 -r14b REG8 reg8_rex 0416 14 -r14w REG16 reg16 0426 14 -r14d REG32 reg32 0436 14 -r14 REG64 reg64 0456 14 -r15b REG8 reg8_rex 0417 15 -r15w REG16 reg16 0427 15 -r15d REG32 reg32 0437 15 -r15 REG64 reg64 0457 15 +al REG_AL reg8,reg8_rex 0 +ah REG_HIGH reg8 4 +ax REG_AX reg16 0 +eax REG_EAX reg32 0 +rax REG_RAX reg64 0 +bl REG8 reg8,reg8_rex 3 +bh REG_HIGH reg8 7 +bx REG16 reg16 3 +ebx REG32 reg32 3 +rbx REG64 reg64 3 +cl REG_CL reg8,reg8_rex 1 +ch REG_HIGH reg8 5 +cx REG_CX reg16 1 +ecx REG_ECX reg32 1 +rcx REG_RCX reg64 1 +dl REG_DL reg8,reg8_rex 2 +dh REG_HIGH reg8 6 +dx REG_DX reg16 2 +edx REG_EDX reg32 2 +rdx REG_RDX reg64 2 +spl REG8 reg8_rex 4 +sp REG16 reg16 4 +esp REG32 reg32 4 +rsp REG64 reg64 4 +bpl REG8 reg8_rex 5 +bp REG16 reg16 5 +ebp REG32 reg32 5 +rbp REG64 reg64 5 +sil REG8 reg8_rex 6 +si REG16 reg16 6 +esi REG32 reg32 6 +rsi REG64 reg64 6 +dil REG8 reg8_rex 7 +di REG16 reg16 7 +edi REG32 reg32 7 +rdi REG64 reg64 7 +r8b REG8 reg8_rex 8 +r8w REG16 reg16 8 +r8d REG32 reg32 8 +r8 REG64 reg64 8 +r9b REG8 reg8_rex 9 +r9w REG16 reg16 9 +r9d REG32 reg32 9 +r9 REG64 reg64 9 +r10b REG8 reg8_rex 10 +r10w REG16 reg16 10 +r10d REG32 reg32 10 +r10 REG64 reg64 10 +r11b REG8 reg8_rex 11 +r11w REG16 reg16 11 +r11d REG32 reg32 11 +r11 REG64 reg64 11 +r12b REG8 reg8_rex 12 +r12w REG16 reg16 12 +r12d REG32 reg32 12 +r12 REG64 reg64 12 +r13b REG8 reg8_rex 13 +r13w REG16 reg16 13 +r13d REG32 reg32 13 +r13 REG64 reg64 13 +r14b REG8 reg8_rex 14 +r14w REG16 reg16 14 +r14d REG32 reg32 14 +r14 REG64 reg64 14 +r15b REG8 reg8_rex 15 +r15w REG16 reg16 15 +r15d REG32 reg32 15 +r15 REG64 reg64 15 # Segment registers -cs REG_CS sreg 0101 1 -ds REG_DESS sreg 0103 3 -es REG_DESS sreg 0100 0 -ss REG_DESS sreg 0102 2 -fs REG_FSGS sreg 0104 4 -gs REG_FSGS sreg 0105 5 -segr6 REG_SEG67 sreg 0106 6 -segr7 REG_SEG67 sreg 0107 7 +cs REG_CS sreg 1 +ds REG_DESS sreg 3 +es REG_DESS sreg 0 +ss REG_DESS sreg 2 +fs REG_FSGS sreg 4 +gs REG_FSGS sreg 5 +segr6-7 REG_SEG67 sreg 6 # Control registers -cr0+ REG_CREG creg 0110 0 -cr8+ REG_CREG creg 0120 8 +cr0-15 REG_CREG creg 0 # Debug registers -dr0+ REG_DREG dreg 0130 0 -dr8+ REG_DREG dreg 0140 8 +dr0-15 REG_DREG dreg 0 # Test registers -tr0+ REG_TREG treg 0150 0 +tr0-7 REG_TREG treg 0 # Floating-point registers -st0 FPU0 fpureg 0200 0 -st1 FPUREG fpureg 0201 1 -st2 FPUREG fpureg 0202 2 -st3 FPUREG fpureg 0203 3 -st4 FPUREG fpureg 0204 4 -st5 FPUREG fpureg 0205 5 -st6 FPUREG fpureg 0206 6 -st7 FPUREG fpureg 0207 7 +st0 FPU0 fpureg 0 +st1-7 FPUREG fpureg 1 # MMX registers -mm0+ MMXREG mmxreg 0220 0 +mm0-7 MMXREG mmxreg 0 # SSE registers -xmm0+ XMMREG xmmreg 0240 0 -xmm8+ XMMREG xmmreg 0460 8 +xmm0-15 XMMREG xmmreg 0 # Special registers -rip REG_RIP ripreg 0500 0 +eip REG_EIP eipreg 0 +rip REG_RIP ripreg 0 diff --git a/regs.pl b/regs.pl index 0910a1fe..fc27a9d1 100755 --- a/regs.pl +++ b/regs.pl @@ -16,25 +16,24 @@ sub process_line($) { my($line) = @_; my @v; - if ( $line !~ /^\s*(\S+)\s*(\S+)\s*(\S+)\s*([1-9][0-9]+|0[0-7]+|0x[0-9a-f]+)\s*([0-9]+)$/i ) { + if ( $line !~ /^\s*(\S+)\s*(\S+)\s*(\S+)\s*([0-9]+)$/i ) { die "regs.dat:$nline: invalid input\n"; } $reg = $1; $aclass = $2; $dclasses = $3; - $regval = toint($4); - $x86regno = toint($5); + $x86regno = toint($4); - if ($reg =~ /[0-9]\+$/) { - $nregs = 8; - $reg =~ s/\+$//; + if ($reg =~ /^(.*[^0-9])([0-9]+)\-([0-9]+)$/) { + $nregs = $3-$2+1; + $reg = $1.$2; } else { $nregs = 1; } while ($nregs--) { $regs{$reg} = $aclass; - $regvals{$reg} = $regval; + $regvals{$reg} = $x86regno; foreach $dclass (split(/,/, $dclasses)) { if ( !defined($disclass{$dclass}) ) { @@ -45,9 +44,8 @@ sub process_line($) { } # Compute the next register, if any - $regval++; $x86regno++; - if ($reg =~ /^(|.*[^0-9])([0-9]+)$/) { + if ($reg =~ /^(.*[^0-9])([0-9]+)$/) { $reg = sprintf("%s%u", $1, $2+1); } } @@ -83,7 +81,7 @@ if ( $fmt eq 'h' ) { print " REG_ENUM_LIMIT\n"; print "};\n\n"; foreach $reg ( sort(keys(%regs)) ) { - print "#define REG_NUM_\U${reg} $regvals{$reg}\n"; + printf "#define %-15s %2d\n", "REG_NUM_\U${reg}", $regvals{$reg}; } print "\n"; } elsif ( $fmt eq 'c' ) { @@ -111,7 +109,7 @@ if ( $fmt eq 'h' ) { print "static const int regvals[] = {\n"; print " -1"; # Dummy entry for 0 foreach $reg ( sort(keys(%regs)) ) { - printf ",\n 0%03o", $regvals{$reg}; # Print the regval of the register + printf ",\n %2d", $regvals{$reg}; # Print the regval of the register } print "\n};\n"; } elsif ( $fmt eq 'dc' ) {