Fix regular expression at doc/rdsrc.pl
[platform/upstream/nasm.git] / assemble.c
index 759e4b5..ff3cea7 100644 (file)
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1996-2013 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2014 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -196,6 +196,7 @@ enum match_result {
     MERR_BADHLE,
     MERR_ENCMISMATCH,
     MERR_BADBND,
+    MERR_BADREPNE,
     /*
      * Matching success; the conditional ones first
      */
@@ -385,6 +386,8 @@ static bool jmp_match(int32_t segment, int64_t offset, int bits,
     if (is_byte && c == 0371 && ins->prefixes[PPS_REP] == P_BND) {
         /* jmp short (opcode eb) cannot be used with bnd prefix. */
         ins->prefixes[PPS_REP] = P_none;
+        errfunc(ERR_WARNING | ERR_WARN_BND | ERR_PASS2 ,
+                "jmp short does not init bnd regs - bnd prefix dropped.");
     }
 
     return is_byte;
@@ -643,8 +646,9 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp,
                         c = 0x66;
                         break;
                     case P_EVEX:
-                        /* EVEX */
-                        break;
+                    case P_VEX3:
+                    case P_VEX2:
+                    case P_NOBND:
                     case P_none:
                         break;
                     default:
@@ -698,6 +702,11 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp,
         case MERR_BADBND:
             error(ERR_NONFATAL, "bnd prefix is not allowed");
             break;
+        case MERR_BADREPNE:
+            error(ERR_NONFATAL, "%s prefix is not allowed",
+                  (has_prefix(instruction, PPS_REP, P_REPNE) ?
+                   "repne" : "repnz"));
+            break;
         default:
             error(ERR_NONFATAL,
                   "invalid combination of opcode and operands");
@@ -810,6 +819,9 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, iflag_t cp,
             case P_A64:
             case P_O64:
             case P_EVEX:
+            case P_VEX3:
+            case P_VEX2:
+            case P_NOBND:
             case P_none:
                 break;
             default:
@@ -1219,27 +1231,18 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
                     }
                 }
 
-                /*
-                 * if a separate form of MIB (ICC style) is used,
-                 * the index reg info is merged into mem operand
-                 */
-                if (mib_index != R_none) {
-                    opy->indexreg = mib_index;
-                    opy->scale = 1;
-                    opy->hintbase = mib_index;
-                    opy->hinttype = EAH_NOTBASE;
-                }
-
-                /*
-                 * only for mib operands, make a single reg index [reg*1].
-                 * gas uses this form to explicitly denote index register.
-                 */
-                if (itemp_has(temp, IF_MIB) &&
-                    (opy->indexreg == -1 && opy->hintbase == opy->basereg &&
-                     opy->hinttype == EAH_NOTBASE)) {
-                    opy->indexreg = opy->basereg;
-                    opy->basereg  = -1;
-                    opy->scale    = 1;
+                if (itemp_has(temp, IF_MIB)) {
+                    opy->eaflags |= EAF_MIB;
+                    /*
+                     * if a separate form of MIB (ICC style) is used,
+                     * the index reg info is merged into mem operand
+                     */
+                    if (mib_index != R_none) {
+                        opy->indexreg = mib_index;
+                        opy->scale = 1;
+                        opy->hintbase = mib_index;
+                        opy->hinttype = EAH_NOTBASE;
+                    }
                 }
 
                 if (process_ea(opy, &ea_data, bits,
@@ -1270,6 +1273,20 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
         ins->rex &= ~REX_P;        /* Don't force REX prefix due to high reg */
     }
 
+    switch (ins->prefixes[PPS_VEX]) {
+    case P_EVEX:
+        if (!(ins->rex & REX_EV))
+            return -1;
+        break;
+    case P_VEX3:
+    case P_VEX2:
+        if (!(ins->rex & REX_V))
+            return -1;
+        break;
+    default:
+        break;
+    }
+
     if (ins->rex & (REX_V | REX_EV)) {
         int bad32 = REX_R|REX_W|REX_X|REX_B;
 
@@ -1301,7 +1318,8 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
         }
         if (ins->rex & REX_EV)
             length += 4;
-        else if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)))
+        else if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)) ||
+                 ins->prefixes[PPS_VEX] == P_VEX3)
             length += 3;
         else
             length += 2;
@@ -1332,16 +1350,27 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
 
     bad_hle_warn(ins, hleok);
 
+    /*
+     * when BND prefix is set by DEFAULT directive,
+     * BND prefix is added to every appropriate instruction line
+     * unless it is overridden by NOBND prefix.
+     */
+    if (globalbnd &&
+        (itemp_has(temp, IF_BND) && !has_prefix(ins, PPS_REP, P_NOBND)))
+            ins->prefixes[PPS_REP] = P_BND;
+
     return length;
 }
 
 static inline unsigned int emit_rex(insn *ins, int32_t segment, int64_t offset, int bits)
 {
     if (bits == 64) {
-        if ((ins->rex & REX_REAL) && !(ins->rex & (REX_V | REX_EV))) {
-            ins->rex = (ins->rex & REX_REAL) | REX_P;
-            out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
-            ins->rex = 0;
+        if ((ins->rex & REX_REAL) &&
+            !(ins->rex & (REX_V | REX_EV)) &&
+            !ins->rex_done) {
+            int rex = (ins->rex & REX_REAL) | REX_P;
+            out(offset, segment, &rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+            ins->rex_done = true;
             return 1;
         }
     }
@@ -1363,6 +1392,8 @@ static void gencode(int32_t segment, int64_t offset, int bits,
     uint8_t opex = 0;
     enum ea_type eat = EA_SCALAR;
 
+    ins->rex_done = false;
+
     while (*codes) {
         c = *codes++;
         op1 = (c & 3) + ((opex & 1) << 2);
@@ -1600,7 +1631,8 @@ static void gencode(int32_t segment, int64_t offset, int bits,
         case4(0260):
         case 0270:
             codes += 2;
-            if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
+            if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)) ||
+                ins->prefixes[PPS_VEX] == P_VEX3) {
                 bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
                 bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
                 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
@@ -1970,9 +2002,6 @@ static int op_evexflags(const operand * o, int mask, uint8_t byte)
 {
     int val;
 
-    if (!is_register(o->basereg))
-        errfunc(ERR_PANIC, "invalid operand passed to op_evexflags()");
-
     val = nasm_regvals[o->basereg];
 
     return evexflags(val, o->decoflags, mask, byte);
@@ -2098,8 +2127,18 @@ static enum match_result matches(const struct itemplate *itemp,
     /*
      * {evex} available?
      */
-       if (instruction->prefixes[PPS_EVEX] && !itemp_has(itemp, IF_EVEX)) {
-        return MERR_ENCMISMATCH;
+    switch (instruction->prefixes[PPS_VEX]) {
+    case P_EVEX:
+        if (!itemp_has(itemp, IF_EVEX))
+            return MERR_ENCMISMATCH;
+        break;
+    case P_VEX3:
+    case P_VEX2:
+        if (!itemp_has(itemp, IF_VEX))
+            return MERR_ENCMISMATCH;
+        break;
+    default:
+        break;
     }
 
     /*
@@ -2298,11 +2337,17 @@ static enum match_result matches(const struct itemplate *itemp,
         return MOK_JUMP;
 
     /*
-     * Check if BND prefix is allowed
+     * Check if BND prefix is allowed.
+     * Other 0xF2 (REPNE/REPNZ) prefix is prohibited.
      */
     if (!itemp_has(itemp, IF_BND) &&
-        has_prefix(instruction, PPS_REP, P_BND))
+        (has_prefix(instruction, PPS_REP, P_BND) ||
+         has_prefix(instruction, PPS_REP, P_NOBND)))
         return MERR_BADBND;
+    else if (itemp_has(itemp, IF_BND) &&
+             (has_prefix(instruction, PPS_REP, P_REPNE) ||
+              has_prefix(instruction, PPS_REP, P_REPNZ)))
+        return MERR_BADREPNE;
 
     return MOK_GOOD;
 }
@@ -2326,6 +2371,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
 {
     bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
     int addrbits = ins->addr_size;
+    int eaflags = input->eaflags;
 
     output->type    = EA_SCALAR;
     output->rip     = false;
@@ -2381,8 +2427,14 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
                 input->type |= MEMORY;
             }
 
-            if (input->eaflags & EAF_BYTEOFFS ||
-                (input->eaflags & EAF_WORDOFFS &&
+            if (bits == 64 &&
+                !(IP_REL & ~input->type) && (eaflags & EAF_MIB)) {
+                nasm_error(ERR_NONFATAL, "RIP-relative addressing is prohibited for mib.");
+                return -1;
+            }
+
+            if (eaflags & EAF_BYTEOFFS ||
+                (eaflags & EAF_WORDOFFS &&
                  input->disp_size != (addrbits != 16 ? 32 : 16))) {
                 nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address");
             }
@@ -2503,7 +2555,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
                     base = (bt & 7);
                     if (base != REG_NUM_EBP && o == 0 &&
                         seg == NO_SEG && !forw_ref &&
-                        !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
+                        !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
                         mod = 0;
                     else if (IS_MOD_01())
                         mod = 1;
@@ -2558,19 +2610,41 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
                     t = bt, bt = it, it = t;
                     x = bx, bx = ix, ix = x;
                 }
-                if (bt == it)     /* convert EAX+2*EAX to 3*EAX */
-                    bt = -1, bx = 0, s++;
+
                 if (bt == -1 && s == 1 && !(hb == i && ht == EAH_NOTBASE)) {
                     /* make single reg base, unless hint */
                     bt = it, bx = ix, it = -1, ix = 0;
                 }
-                if (((s == 2 && it != REG_NUM_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
-                      s == 3 || s == 5 || s == 9) && bt == -1)
-                    bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
-                if (it == -1 && (bt & 7) != REG_NUM_ESP &&
-                    (input->eaflags & EAF_TIMESTWO))
-                    it = bt, ix = bx, bt = -1, bx = 0, s = 1;
-                /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
+                if (eaflags & EAF_MIB) {
+                    /* only for mib operands */
+                    if (it == -1 && (hb == b && ht == EAH_NOTBASE)) {
+                        /*
+                         * make a single reg index [reg*1].
+                         * gas uses this form for an explicit index register.
+                         */
+                        it = bt, ix = bx, bt = -1, bx = 0, s = 1;
+                    }
+                    if ((ht == EAH_SUMMED) && bt == -1) {
+                        /* separate once summed index into [base, index] */
+                        bt = it, bx = ix, s--;
+                    }
+                } else {
+                    if (((s == 2 && it != REG_NUM_ESP &&
+                          (!(eaflags & EAF_TIMESTWO) || (ht == EAH_SUMMED))) ||
+                         s == 3 || s == 5 || s == 9) && bt == -1) {
+                        /* convert 3*EAX to EAX+2*EAX */
+                        bt = it, bx = ix, s--;
+                    }
+                    if (it == -1 && (bt & 7) != REG_NUM_ESP &&
+                        (eaflags & EAF_TIMESTWO) &&
+                        (hb == b && ht == EAH_NOTBASE)) {
+                        /*
+                         * convert [NOSPLIT EAX*1]
+                         * to sib format with 0x0 displacement - [EAX*1+0].
+                         */
+                        it = bt, ix = bx, bt = -1, bx = 0, s = 1;
+                    }
+                }
                 if (s == 1 && it == REG_NUM_ESP) {
                     /* swap ESP into base if scale is 1 */
                     t = it, it = bt, bt = t;
@@ -2594,7 +2668,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
                         rm = (bt & 7);
                         if (rm != REG_NUM_EBP && o == 0 &&
                             seg == NO_SEG && !forw_ref &&
-                            !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
+                            !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
                             mod = 0;
                         else if (IS_MOD_01())
                             mod = 1;
@@ -2638,7 +2712,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
                         base = (bt & 7);
                         if (base != REG_NUM_EBP && o == 0 &&
                             seg == NO_SEG && !forw_ref &&
-                            !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
+                            !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
                             mod = 0;
                         else if (IS_MOD_01())
                             mod = 1;
@@ -2723,7 +2797,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
                     goto err;        /* so panic if it does */
 
                 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
-                    !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
+                    !(eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
                     mod = 0;
                 else if (IS_MOD_01())
                     mod = 1;