Implement REL/ABS modifiers

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.
This commit is contained in:
H. Peter Anvin 2007-08-28 23:06:00 +00:00
parent 352170d5eb
commit 99c4ecd18f
7 changed files with 75 additions and 64 deletions

View 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;

View File

@ -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 {

1
nasm.c
View File

@ -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];

34
nasm.h
View File

@ -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

View File

@ -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[] = {

View File

@ -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;

View File

@ -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