Implement REL/ABS modifiers
authorH. Peter Anvin <hpa@zytor.com>
Tue, 28 Aug 2007 23:06:00 +0000 (23:06 +0000)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 28 Aug 2007 23:06:00 +0000 (23:06 +0000)
Implement "REL" and "ABS" modifiers for offsets in 64-bit mode.  This
replaces "rip+XXX" type addressing.  The infrastructure to set the default
mode is there, but there is nothing to throw the switch just yet.

assemble.c
disasm.c
nasm.c
nasm.h
nasmlib.c
parser.c
regs.dat

index d9471b5..575103a 100644 (file)
@@ -1646,10 +1646,8 @@ static int matches(struct itemplate *itemp, insn * instruction, int bits)
 static ea *process_ea(operand * input, ea * output, int addrbits,
                       int rfield, int32_t rflags, int forw_ref)
 {
-                      
-    int rip = FALSE;              /* Used for RIP-relative addressing */
-    output->rip = 0;
-  
+    output->rip = FALSE;
+
     /* REX flags for the rfield operand */
     output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
 
@@ -1672,13 +1670,13 @@ static ea *process_ea(operand * input, ea * output, int addrbits,
         output->bytes = 0;  /* no offset necessary either */
         output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
     } else {                    /* it's a memory reference */
-        
         if (input->basereg == -1
             && (input->indexreg == -1 || input->scale == 0)) {
             /* it's a pure offset */
             if (input->addr_size)
                 addrbits = input->addr_size;
-            if (addrbits == 64) {
+
+            if (globalbits == 64 && (~input->type & IP_REL)) {
               int scale, index, base;
               output->sib_present = TRUE;
               scale = 0;
@@ -1687,10 +1685,12 @@ static ea *process_ea(operand * input, ea * output, int addrbits,
               output->sib = (scale << 6) | (index << 3) | base;
               output->bytes = 4;
               output->modrm = 4 | ((rfield & 7) << 3);
+             output->rip = FALSE;
             } else {
               output->sib_present = FALSE;
               output->bytes = (addrbits != 16 ? 4 : 2);
               output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
+             output->rip = globalbits == 64;
             }
         } else {                /* it's an indirection */
             int i = input->indexreg, b = input->basereg, s = input->scale;
@@ -1733,15 +1733,11 @@ static ea *process_ea(operand * input, ea * output, int addrbits,
                }
 
                if (bt != -1) {
-                   if ((REG_GPR & ~bx) && (IP_REG & ~bx))
+                   if (REG_GPR & ~bx)
                        return NULL; /* Invalid register */
                    if (~sok & bx & SIZE_MASK)
                        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. */
@@ -1860,26 +1856,6 @@ 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;
                 
index adf3a37..8c02db1 100644 (file)
--- a/disasm.c
+++ b/disasm.c
@@ -166,6 +166,7 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
     }
 
     op->addr_size = 0;
+    op->eaflags = 0;
 
     if (asize == 16) {
         /*
@@ -250,15 +251,16 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
 
         if (rm == 5 && mod == 0) {
            if (segsize == 64) {
-               op->basereg = R_RIP;
+               op->eaflags |= EAF_REL;
                op->segment |= SEG_RELATIVE;
                mod = 2;        /* fake disp32 */
-           } else {
-               op->basereg = -1;
-               if (segsize != 32)
-                   op->addr_size = 32;
-               mod = 2;            /* fake disp32 */
            }
+
+           if (asize != 64)
+               op->addr_size = asize;
+
+           op->basereg = -1;
+           mod = 2;            /* fake disp32 */
         }
 
         if (rm == 4) {          /* process SIB */
@@ -283,6 +285,9 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
                op->basereg = rd_reg64[base | ((rex & REX_B) ? 8 : 0)];
            else
                op->basereg = rd_reg32[base | ((rex & REX_B) ? 8 : 0)];
+
+           if (segsize != 32)
+               op->addr_size = 32;
         }
 
         switch (mod) {
@@ -839,6 +844,8 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
                                  ins.oprs[i].addr_size == 32 ? "dword " :
                                   ins.oprs[i].addr_size == 16 ? "word " :
                                  ""));
+           if (ins.oprs[i].eaflags & EAF_REL)
+               slen += snprintf(output + slen, outbufsize - slen, "rel ");
             if (segover) {
                 slen +=
                     snprintf(output + slen, outbufsize - slen, "%s:",
@@ -886,9 +893,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             } else if (ins.oprs[i].segment & SEG_DISP32) {
                    char *prefix = "";
                    int32_t offset = ins.oprs[i].offset;
-                   if (ins.oprs[i].basereg == R_RIP) {
-                       prefix = ":";
-                   } else if (offset < 0) {
+                   if (offset < 0) {
                        offset = -offset;
                        prefix = "-";
                    } else {
diff --git a/nasm.c b/nasm.c
index 5949992..0dfad2a 100644 (file)
--- a/nasm.c
+++ b/nasm.c
@@ -47,6 +47,7 @@ static int using_debug_info, opt_verbose_info;
 int tasm_compatible_mode = FALSE;
 int pass0;
 int maxbits = 0;
+int globalrel = 0;
 
 static char inname[FILENAME_MAX];
 static char outname[FILENAME_MAX];
diff --git a/nasm.h b/nasm.h
index f2672a4..4a0a6af 100644 (file)
--- a/nasm.h
+++ b/nasm.h
@@ -385,7 +385,7 @@ enum {
  *  6: NEAR
  *  7: SHORT
  *
- * Bits 8-11: modifiers
+ * Bits 8-11 modifiers
  *  8: TO
  *  9: COLON
  * 10: STRICT
@@ -420,6 +420,7 @@ enum {
  *
  * With MEMORY:
  * 16: MEM_OFFS (this is a simple offset)
+ * 17: IP_REL (IP-relative offset)
  *
  * With IMMEDIATE:
  * 16: UNITY (1)
@@ -429,7 +430,7 @@ enum {
  * 20: REG_CDT (CRx, DRx, TRx)
  * 21: REG_GPR (integer register)
  * 22: REG_SREG
- * 23: IP_REG (RIP or EIP)
+ * 23: IP_REG (RIP or EIP) [unused]
  * 24: FPUREG
  * 25: MMXREG
  * 26: XMMREG
@@ -508,8 +509,9 @@ enum {
 #define REG_RDX                0x00249008L
 #define REG_HIGH       0x00289001L   /* high regs: AH, CH, DH, BH */
 
-/* special type of EA */
-#define MEM_OFFS       0x00214000L   /* simple [address] offset */
+/* special types of EAs */
+#define MEM_OFFS       0x00214000L   /* simple [address] offset - absolute! */
+#define IP_REL         0x00224000L   /* IP-relative offset */
 
 /* special type of immediate operand */
 #define UNITY          0x00012000L   /* for shift/rotate instructions */
@@ -552,9 +554,12 @@ enum {                          /* extended operand types */
 };
 
 enum {                          /* special EA flags */
-    EAF_BYTEOFFS = 1,           /* force offset part to byte size */
-    EAF_WORDOFFS = 2,           /* force offset part to [d]word size */
-    EAF_TIMESTWO = 4            /* really do EAX*2 not EAX+EAX */
+    EAF_BYTEOFFS =  1,          /* force offset part to byte size */
+    EAF_WORDOFFS =  2,          /* force offset part to [d]word size */
+    EAF_TIMESTWO =  4,          /* really do EAX*2 not EAX+EAX */
+    EAF_REL     =  8,          /* IP-relative addressing */
+    EAF_ABS      = 16,         /* non-IP-relative addressing */
+    EAF_SEGOVER  = 32          /* segment override present */
 };
 
 enum {                          /* values for `hinttype' */
@@ -932,7 +937,11 @@ struct dfmt {
 
 #define elements(x)     ( sizeof(x) / sizeof(*(x)) )
 
-extern int tasm_compatible_mode;
+/*
+ * -----
+ * Global modes
+ * -----
+ */
 
 /*
  * This declaration passes the "pass" number to all other modules
@@ -942,9 +951,12 @@ extern int tasm_compatible_mode;
  *       2 = pass 2
  */
 
-extern int pass0;               /* this is globally known */
+extern int pass0;
+
+extern int tasm_compatible_mode;
 extern int optimizing;
-extern int globalbits;          /* this is globally known */
-extern int maxbits;             /* this is globally known */
+extern int globalbits;          /* 16, 32 or 64-bit mode */
+extern int globalrel;          /* default to relative addressing? */
+extern int maxbits;            /* max bits supported by output */
 
 #endif
index 20535c8..e380542 100644 (file)
--- a/nasmlib.c
+++ b/nasmlib.c
@@ -17,7 +17,6 @@
 #include "insns.h"              /* For MAX_KEYWORD */
 
 int globalbits = 0;    /* defined in nasm.h, works better here for ASM+DISASM */
-
 static efunc nasm_malloc_error;
 
 #ifdef LOGALLOC
@@ -692,7 +691,7 @@ void saa_fpwrite(struct SAA *s, FILE * fp)
  */
 #include "names.c"
 static const char *special_names[] = {
-    "byte", "dword", "far", "long", "near", "nosplit", "qword",
+    "abs", "byte", "dword", "far", "long", "near", "nosplit", "qword", "rel",
     "short", "strict", "to", "tword", "word"
 };
 static const char *prefix_names[] = {
index 54e1737..e668055 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -28,7 +28,7 @@ extern int32_t abs_offset;         /* ABSOLUTE segment offset */
 #include "regflags.c"           /* List of register flags */
 
 enum {                          /* special tokens */
-    S_BYTE, S_DWORD, S_FAR, S_LONG, S_NEAR, S_NOSPLIT, S_QWORD,
+    S_ABS, S_BYTE, S_DWORD, S_FAR, S_LONG, S_NEAR, S_NOSPLIT, S_QWORD, S_REL,
     S_SHORT, S_STRICT, S_TO, S_TWORD, S_WORD
 };
 
@@ -412,8 +412,8 @@ insn *parse_line(int pass, char *buffer, insn * result,
         if (i == '[' || i == '&') {     /* memory reference */
             mref = TRUE;
             bracket = (i == '[');
-            i = stdscan(NULL, &tokval);
-            if (i == TOKEN_SPECIAL) {   /* check for address size override */
+            while ((i = stdscan(NULL, &tokval)) == TOKEN_SPECIAL) {
+               /* check for address directives */
                 if (tasm_compatible_mode) {
                     switch ((int)tokval.t_integer) {
                         /* For TASM compatibility a size override inside the
@@ -454,6 +454,12 @@ insn *parse_line(int pass, char *buffer, insn * result,
                     case S_NOSPLIT:
                         result->oprs[operand].eaflags |= EAF_TIMESTWO;
                         break;
+                   case S_REL:
+                        result->oprs[operand].eaflags |= EAF_REL;
+                       break;
+                   case S_ABS:
+                        result->oprs[operand].eaflags |= EAF_ABS;
+                       break;
                     case S_BYTE:
                         result->oprs[operand].eaflags |= EAF_BYTEOFFS;
                         break;
@@ -466,12 +472,15 @@ insn *parse_line(int pass, char *buffer, insn * result,
                         result->oprs[operand].addr_size = 32;
                         result->oprs[operand].eaflags |= EAF_WORDOFFS;
                         break;
+                   case S_QWORD:
+                        result->oprs[operand].addr_size = 64;
+                        result->oprs[operand].eaflags |= EAF_WORDOFFS;
+                        break;
                     default:
                         error(ERR_NONFATAL, "invalid size specification in"
                               " effective address");
                     }
                 }
-                i = stdscan(NULL, &tokval);
             }
         } else {                /* immediate operand, or register */
             mref = FALSE;
@@ -504,8 +513,10 @@ insn *parse_line(int pass, char *buffer, insn * result,
             else if (result->nprefix == MAXPREFIX)
                 error(ERR_NONFATAL,
                       "instruction has more than %d prefixes", MAXPREFIX);
-            else
+            else {
                 result->prefixes[result->nprefix++] = value->type;
+               result->oprs[operand].eaflags |= EAF_SEGOVER;
+           }
 
             i = stdscan(NULL, &tokval); /* then skip the colon */
             if (i == TOKEN_SPECIAL) {   /* another check for size override */
@@ -517,6 +528,9 @@ insn *parse_line(int pass, char *buffer, insn * result,
                 case S_LONG:
                     result->oprs[operand].addr_size = 32;
                     break;
+               case S_QWORD:
+                   result->oprs[operand].addr_size = 64;
+                   break;
                 default:
                     error(ERR_NONFATAL, "invalid size specification in"
                           " effective address");
@@ -657,8 +671,16 @@ insn *parse_line(int pass, char *buffer, insn * result,
             }
 
             result->oprs[operand].type |= MEMORY;
-            if (b == -1 && (i == -1 || s == 0))
-                result->oprs[operand].type |= MEM_OFFS;
+
+           if (b == -1 && (i == -1 || s == 0)) {
+               int is_rel = globalbits == 64 &&
+                   !(result->oprs[operand].eaflags & EAF_ABS) &&
+                   ((globalrel &&
+                     !(result->oprs[operand].eaflags & EAF_SEGOVER)) ||
+                    (result->oprs[operand].eaflags & EAF_REL));
+
+                result->oprs[operand].type |= is_rel ? IP_REL : MEM_OFFS;
+           }
             result->oprs[operand].basereg = b;
             result->oprs[operand].indexreg = i;
             result->oprs[operand].scale = s;
index 79146f4..d51592f 100644 (file)
--- a/regs.dat
+++ b/regs.dat
@@ -80,7 +80,3 @@ mm0-7 MMXREG          mmxreg          0
 
 # SSE registers
 xmm0-15        XMMREG          xmmreg          0
-
-# Special registers
-eip    REG_EIP         eipreg          0
-rip    REG_RIP         ripreg          0