mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-03-19 18:00:23 +08:00
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:
parent
352170d5eb
commit
99c4ecd18f
38
assemble.c
38
assemble.c
@ -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;
|
||||
|
||||
|
23
disasm.c
23
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 {
|
||||
|
1
nasm.c
1
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];
|
||||
|
34
nasm.h
34
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
|
||||
|
@ -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[] = {
|
||||
|
36
parser.c
36
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user