summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2016-10-04 06:29:25 -0700
committerH. Peter Anvin <hpa@zytor.com>2016-10-04 06:29:25 -0700
commit80cc2029d31f4a7f1cd4334b9cfaf9556f0163ce (patch)
treeb88e4a600398ab7d2c8763ff288d01a43fb26036
parent439875c1d9773df06cabbe9611f7a67c88f58847 (diff)
downloadnasm-reldef.tar.gz
Make it possible to generate PC-relative relocations in datareldef
Allow expressions such as: dd bar - $ ... where "bar" is a symbol external to the segment. Currently this is only supported for the Dx instructions; extending it to inline immediates requires additional changes to the parser. This may, however, be sufficient for the needs of some users. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--assemble.c175
-rw-r--r--nasm.h12
-rw-r--r--parser.c72
-rw-r--r--test/reldef.asm9
4 files changed, 188 insertions, 80 deletions
diff --git a/assemble.c b/assemble.c
index 0971fa3a..028d61cc 100644
--- a/assemble.c
+++ b/assemble.c
@@ -332,21 +332,46 @@ static int addrsize(enum out_type type, uint64_t size)
*/
static void out(int64_t offset, int32_t segto, const void *data,
enum out_type type, uint64_t size,
- int32_t segment, int32_t wrt)
+ int32_t segment, int32_t wrt, bool relative)
{
static int32_t lineno = 0; /* static!!! */
static const char *lnfname = NULL;
uint8_t p[8];
- int asize = addrsize(type, size); /* Address size in bytes */
+ int asize = addrsize(type, size); /* Address size in bytes */
const int amax = ofmt->maxbits >> 3; /* Maximum address size in bytes */
+ if (unlikely(relative)) {
+ if (type == OUT_ADDRESS) {
+ switch (asize) {
+ case 1:
+ type = OUT_REL1ADR;
+ break;
+ case 2:
+ type = OUT_REL2ADR;
+ break;
+ case 4:
+ type = OUT_REL4ADR;
+ break;
+ case 8:
+ type = OUT_REL8ADR;
+ break;
+ default:
+ panic();
+ }
+
+ size = 0;
+ } else {
+ nasm_error(ERR_NONFATAL, "expression cannot be converted to relative");
+ }
+ }
+
if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
/*
* This is a non-relocated address, and we're going to
* convert it into RAWDATA format.
*/
uint8_t *q = p;
-
+
if (asize > 8) {
nasm_panic(0, "OUT_ADDRESS with size > 8");
return;
@@ -399,10 +424,11 @@ static void out_imm8(int64_t offset, int32_t segment,
{
if (opx->segment != NO_SEG) {
uint64_t data = opx->offset;
- out(offset, segment, &data, OUT_ADDRESS, asize, opx->segment, opx->wrt);
+ out(offset, segment, &data, OUT_ADDRESS, asize, opx->segment, opx->wrt,
+ opx->relative);
} else {
uint8_t byte = opx->offset;
- out(offset, segment, &byte, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, &byte, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
}
}
@@ -475,7 +501,8 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp,
" instruction");
} else {
out(offset, segment, &e->offset,
- OUT_ADDRESS, wsize, e->segment, e->wrt);
+ OUT_ADDRESS, wsize, e->segment, e->wrt,
+ e->relative);
offset += wsize;
}
} else if (e->type == EOT_DB_STRING ||
@@ -483,13 +510,13 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp,
int align;
out(offset, segment, e->stringval,
- OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
+ OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG, false);
align = e->stringlen % wsize;
if (align) {
align = wsize - align;
out(offset, segment, zero_buffer,
- OUT_RAWDATA, align, NO_SEG, NO_SEG);
+ OUT_RAWDATA, align, NO_SEG, NO_SEG, false);
}
offset += e->stringlen + align;
}
@@ -561,7 +588,7 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp,
break;
}
out(offset, segment, buf, OUT_RAWDATA, m,
- NO_SEG, NO_SEG);
+ NO_SEG, NO_SEG, false);
l -= m;
}
}
@@ -701,7 +728,7 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, iflag_t cp,
}
if (c != 0) {
out(offset, segment, &c, OUT_RAWDATA, 1,
- NO_SEG, NO_SEG);
+ NO_SEG, NO_SEG, false);
offset++;
}
}
@@ -918,6 +945,12 @@ static void bad_hle_warn(const insn * ins, uint8_t hleok)
}
}
+static void fail_if_relative(const struct operand *op)
+{
+ if (op->relative)
+ nasm_error(ERR_NONFATAL, "invalid use of self-relative operand");
+}
+
/* Common construct */
#define case3(x) case (x): case (x)+1: case (x)+2
#define case4(x) case3(x): case (x)+3
@@ -1416,7 +1449,7 @@ static inline unsigned int emit_rex(insn *ins, int32_t segment, int64_t offset,
!(ins->rex & (REX_V | REX_EV)) &&
!ins->rex_done) {
int rex = (ins->rex & REX_MASK) | REX_P;
- out(offset, segment, &rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, &rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
ins->rex_done = true;
return 1;
}
@@ -1455,7 +1488,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 03:
case 04:
offset += emit_rex(ins, segment, offset, bits);
- out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
+ out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG, false);
codes += c;
offset += c;
break;
@@ -1469,7 +1502,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case4(010):
offset += emit_rex(ins, segment, offset, bits);
bytes[0] = *codes++ + (regval(opx) & 7);
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
break;
@@ -1497,7 +1530,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
warn_overflow_opd(opx, 2);
data = opx->offset;
out(offset, segment, &data, OUT_ADDRESS, 2,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, opx->relative);
offset += 2;
break;
@@ -1509,7 +1542,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
warn_overflow_opd(opx, size);
data = opx->offset;
out(offset, segment, &data, OUT_ADDRESS, size,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, opx->relative);
offset += size;
break;
@@ -1517,7 +1550,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
warn_overflow_opd(opx, 4);
data = opx->offset;
out(offset, segment, &data, OUT_ADDRESS, 4,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, opx->relative);
offset += 4;
break;
@@ -1526,22 +1559,23 @@ static void gencode(int32_t segment, int64_t offset, int bits,
size = ins->addr_size >> 3;
warn_overflow_opd(opx, size);
out(offset, segment, &data, OUT_ADDRESS, size,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, opx->relative);
offset += size;
break;
case4(050):
+ fail_if_relative(opx);
if (opx->segment != segment) {
data = opx->offset;
out(offset, segment, &data,
OUT_REL1ADR, insn_end - offset,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, false);
} else {
data = opx->offset - insn_end;
if (data > 127 || data < -128)
nasm_error(ERR_NONFATAL, "short jump is out of range");
out(offset, segment, &data,
- OUT_ADDRESS, 1, NO_SEG, NO_SEG);
+ OUT_ADDRESS, 1, NO_SEG, NO_SEG, false);
}
offset += 1;
break;
@@ -1549,25 +1583,27 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case4(054):
data = (int64_t)opx->offset;
out(offset, segment, &data, OUT_ADDRESS, 8,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, opx->relative);
offset += 8;
break;
case4(060):
+ fail_if_relative(opx);
if (opx->segment != segment) {
data = opx->offset;
out(offset, segment, &data,
OUT_REL2ADR, insn_end - offset,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, false);
} else {
data = opx->offset - insn_end;
out(offset, segment, &data,
- OUT_ADDRESS, 2, NO_SEG, NO_SEG);
+ OUT_ADDRESS, 2, NO_SEG, NO_SEG, false);
}
offset += 2;
break;
case4(064):
+ fail_if_relative(opx);
if (opx->type & (BITS16 | BITS32 | BITS64))
size = (opx->type & BITS16) ? 2 : 4;
else
@@ -1576,25 +1612,26 @@ static void gencode(int32_t segment, int64_t offset, int bits,
data = opx->offset;
out(offset, segment, &data,
size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
- insn_end - offset, opx->segment, opx->wrt);
+ insn_end - offset, opx->segment, opx->wrt, false);
} else {
data = opx->offset - insn_end;
out(offset, segment, &data,
- OUT_ADDRESS, size, NO_SEG, NO_SEG);
+ OUT_ADDRESS, size, NO_SEG, NO_SEG, false);
}
offset += size;
break;
case4(070):
+ fail_if_relative(opx);
if (opx->segment != segment) {
data = opx->offset;
out(offset, segment, &data,
OUT_REL4ADR, insn_end - offset,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, false);
} else {
data = opx->offset - insn_end;
out(offset, segment, &data,
- OUT_ADDRESS, 4, NO_SEG, NO_SEG);
+ OUT_ADDRESS, 4, NO_SEG, NO_SEG, false);
}
offset += 4;
break;
@@ -1606,7 +1643,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
data = 0;
out(offset, segment, &data, OUT_ADDRESS, 2,
ofmt->segbase(1 + opx->segment),
- opx->wrt);
+ opx->wrt, opx->relative);
offset += 2;
break;
@@ -1641,7 +1678,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
emit_is4:
r = nasm_regvals[opx->basereg];
bytes[0] = (r << 4) | ((r & 0x10) >> 1) | c;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset++;
break;
@@ -1653,7 +1690,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
"signed dword immediate exceeds bounds");
}
out(offset, segment, &data, OUT_ADDRESS, -4,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, opx->relative);
offset += 4;
break;
@@ -1672,7 +1709,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
((~ins->vexreg & 15) << 3) |
(1 << 2) | (ins->vex_wlp & 3);
bytes[3] = ins->evex_p[2];
- out(offset, segment, &bytes, OUT_RAWDATA, 4, NO_SEG, NO_SEG);
+ out(offset, segment, &bytes, OUT_RAWDATA, 4, NO_SEG, NO_SEG, false);
offset += 4;
break;
@@ -1685,13 +1722,13 @@ static void gencode(int32_t segment, int64_t offset, int bits,
bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
bytes[2] = ((ins->rex & REX_W) << (7-3)) |
((~ins->vexreg & 15)<< 3) | (ins->vex_wlp & 07);
- out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
+ out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG, false);
offset += 3;
} else {
bytes[0] = 0xc5;
bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
((~ins->vexreg & 15) << 3) | (ins->vex_wlp & 07);
- out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
+ out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG, false);
offset += 2;
}
break;
@@ -1733,11 +1770,11 @@ static void gencode(int32_t segment, int64_t offset, int bits,
if (opx->segment != NO_SEG) {
data = uv;
out(offset, segment, &data, OUT_ADDRESS, 1,
- opx->segment, opx->wrt);
+ opx->segment, opx->wrt, opx->relative);
} else {
bytes[0] = uv;
out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
- NO_SEG);
+ NO_SEG, false);
}
offset += 1;
break;
@@ -1749,7 +1786,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 0310:
if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
*bytes = 0x67;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
} else
offset += 0;
@@ -1758,7 +1795,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 0311:
if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
*bytes = 0x67;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
} else
offset += 0;
@@ -1794,7 +1831,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 0330:
*bytes = *codes++ ^ get_cond_opcode(ins->condition);
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
break;
@@ -1804,14 +1841,14 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 0332:
case 0333:
*bytes = c - 0332 + 0xF2;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
break;
case 0334:
if (ins->rex & REX_R) {
*bytes = 0xF0;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
}
ins->rex &= ~(REX_L|REX_R);
@@ -1831,7 +1868,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
int64_t size = ins->oprs[0].offset;
if (size > 0)
out(offset, segment, NULL,
- OUT_RESERVE, size, NO_SEG, NO_SEG);
+ OUT_RESERVE, size, NO_SEG, NO_SEG, false);
offset += size;
}
break;
@@ -1844,7 +1881,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 0361:
bytes[0] = 0x66;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
break;
@@ -1855,7 +1892,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 0366:
case 0367:
*bytes = c - 0366 + 0x66;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
break;
@@ -1864,7 +1901,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
case 0373:
*bytes = bits == 16 ? 3 : 5;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG, false);
offset += 1;
break;
@@ -1920,7 +1957,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
*p++ = ea_data.sib;
s = p - bytes;
- out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
+ out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG, false);
/*
* Make sure the address gets the right offset in case
@@ -1939,11 +1976,16 @@ static void gencode(int32_t segment, int64_t offset, int bits,
if (overflow_signed(data, ea_data.bytes))
warn_overflow(ERR_PASS2, ea_data.bytes);
out(offset, segment, &data, OUT_ADDRESS,
- ea_data.bytes, NO_SEG, NO_SEG);
+ ea_data.bytes, NO_SEG, NO_SEG, false);
} else {
/* overflow check in output/linker? */
- out(offset, segment, &data, OUT_REL4ADR,
- insn_end - offset, opy->segment, opy->wrt);
+ out(offset, segment, &data,
+ ea_data.bytes == 1 ? OUT_REL1ADR :
+ ea_data.bytes == 2 ? OUT_REL2ADR :
+ ea_data.bytes == 4 ? OUT_REL4ADR :
+ OUT_REL8ADR,
+ insn_end - offset, opy->segment, opy->wrt,
+ false);
}
} else {
int asize = ins->addr_size >> 3;
@@ -1963,7 +2005,7 @@ static void gencode(int32_t segment, int64_t offset, int bits,
}
out(offset, segment, &data, OUT_ADDRESS,
- atype, opy->segment, opy->wrt);
+ atype, opy->segment, opy->wrt, false);
}
}
offset += s;
@@ -2490,17 +2532,26 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
/*
* It's a pure offset.
*/
- if (bits == 64 && ((input->type & IP_REL) == IP_REL) &&
- input->segment == NO_SEG) {
- nasm_error(ERR_WARNING | ERR_PASS1, "absolute address can not be RIP-relative");
- input->type &= ~IP_REL;
- input->type |= MEMORY;
- }
+ if (bits == 64 && !(IP_REL & ~input->type)) {
+ if (input->segment == NO_SEG) {
+ nasm_error(ERR_WARNING | ERR_PASS1,
+ "absolute address can not be RIP-relative");
+ input->type &= ~IP_REL;
+ input->type |= MEMORY;
+ }
+
+ if (input->relative) {
+ nasm_error(ERR_WARNING | ERR_PASS1,
+ "double relative address; ignoring REL");
+ input->type &= ~IP_REL;
+ input->type |= MEMORY;
+ }
+
+ if (eaflags & EAF_MIB) {
+ nasm_error(ERR_NONFATAL, "RIP-relative addressing is prohibited for mib.");
+ return -1;
+ }
- 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 ||
@@ -2514,12 +2565,12 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
output->sib = GEN_SIB(0, 4, 5);
output->bytes = 4;
output->modrm = GEN_MODRM(0, rfield, 4);
- output->rip = false;
+ output->rip = input->relative;
} else {
output->sib_present = false;
output->bytes = (addrbits != 16 ? 4 : 2);
output->modrm = GEN_MODRM(0, rfield, (addrbits != 16 ? 5 : 6));
- output->rip = bits == 64;
+ output->rip = (bits == 64) || input->relative;
}
} else {
/*
@@ -2531,6 +2582,8 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
int t, it, bt; /* register numbers */
opflags_t x, ix, bx; /* register flags */
+ output->rip = input->relative;
+
if (s == 0)
i = -1; /* make this easy, at least */
@@ -2617,7 +2670,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
default: /* then what the smeg is it? */
goto err; /* panic */
}
-
+
if (bt == -1) {
base = 5;
mod = 0;
diff --git a/nasm.h b/nasm.h
index 663cc21e..0c6478f5 100644
--- a/nasm.h
+++ b/nasm.h
@@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------- *
- *
+ *
* Copyright 1996-2016 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
@@ -14,7 +14,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@@ -31,7 +31,7 @@
*
* ----------------------------------------------------------------------- */
-/*
+/*
* nasm.h main header file for the Netwide Assembler: inter-module interface
*/
@@ -546,6 +546,7 @@ typedef struct operand { /* operand to an instruction */
int32_t segment; /* immediate segment, if needed */
int64_t offset; /* any immediate number */
int32_t wrt; /* segment base it's relative to */
+ bool relative; /* self-relative expression */
int eaflags; /* special EA flags */
int opflags; /* see OPFLAG_* defines below */
decoflags_t decoflags; /* decorator flags such as {...} */
@@ -553,7 +554,7 @@ typedef struct operand { /* operand to an instruction */
#define OPFLAG_FORWARD 1 /* operand is a forward reference */
#define OPFLAG_EXTERN 2 /* operand is an external reference */
-#define OPFLAG_UNKNOWN 4 /* operand is an unknown reference
+#define OPFLAG_UNKNOWN 4 /* operand is an unknown reference
* (always a forward reference also)
*/
@@ -564,6 +565,7 @@ typedef struct extop { /* extended operand */
int64_t offset; /* ... it's given here ... */
int32_t segment; /* if it's a number/address, then... */
int32_t wrt; /* ... and here */
+ bool relative; /* self-relative expression */
enum extop_type type; /* defined above */
} extop;
@@ -678,7 +680,7 @@ struct ofmt {
/*
* Output format flags.
*/
-#define OFMT_TEXT 1 /* Text file format */
+#define OFMT_TEXT 1 /* Text file format */
unsigned int flags;
int maxbits; /* Maximum segment bits supported */
diff --git a/parser.c b/parser.c
index 5107860e..23eb09e7 100644
--- a/parser.c
+++ b/parser.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2013 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2016 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -261,7 +261,7 @@ static int parse_mref(operand *op, const expr *e)
if (is_gpr && e->value == 1)
b = e->type; /* It can be basereg */
- else /* No, it has to be indexreg */
+ else /* No, it has to be indexreg */
i = e->type, s = e->value;
e++;
}
@@ -382,6 +382,59 @@ static void mref_set_optype(operand *op)
}
}
+/*
+ * Convert an expression vector returned from evaluate() into an
+ * extop structure. Return zero on success.
+ */
+static int value_to_extop(expr * vect, extop *eop, int32_t myseg)
+{
+ eop->type = EOT_DB_NUMBER;
+ eop->offset = 0;
+ eop->segment = eop->wrt = NO_SEG;
+ eop->relative = false;
+
+ for (; vect->type; vect++) {
+ if (!vect->value) /* zero term, safe to ignore */
+ continue;
+
+ if (vect->type < EXPR_SIMPLE) /* false if a register is present */
+ return -1;
+
+ if (vect->type == EXPR_UNKNOWN) /* something we can't resolve yet */
+ return 0;
+
+ if (vect->type == EXPR_SIMPLE) {
+ /* Simple number expression */
+ eop->offset += vect->value;
+ continue;
+ }
+ if (eop->wrt == NO_SEG && !eop->relative && vect->type == EXPR_WRT) {
+ /* WRT term */
+ eop->wrt = vect->value;
+ continue;
+ }
+
+ if (eop->wrt == NO_SEG && !eop->relative &&
+ vect->type == EXPR_SEGBASE + myseg && vect->value == -1) {
+ /* Expression of the form: foo - $ */
+ eop->relative = true;
+ continue;
+ }
+
+ if (eop->segment == NO_SEG && vect->type >= EXPR_SEGBASE &&
+ vect->value == 1) {
+ eop->segment = vect->type - EXPR_SEGBASE;
+ continue;
+ }
+
+ /* Otherwise, badness */
+ return -1;
+ }
+
+ /* We got to the end and it was all okay */
+ return 0;
+}
+
insn *parse_line(int pass, char *buffer, insn *result, ldfunc ldef)
{
bool insn_is_label = false;
@@ -659,19 +712,10 @@ is_expression:
i = tokval.t_type;
if (!value) /* Error in evaluator */
goto fail;
- if (is_unknown(value)) {
- eop->type = EOT_DB_NUMBER;
- eop->offset = 0; /* doesn't matter what we put */
- eop->segment = eop->wrt = NO_SEG; /* likewise */
- } else if (is_reloc(value)) {
- eop->type = EOT_DB_NUMBER;
- eop->offset = reloc_value(value);
- eop->segment = reloc_seg(value);
- eop->wrt = reloc_wrt(value);
- } else {
+ if (value_to_extop(value, eop, location->segment)) {
nasm_error(ERR_NONFATAL,
- "operand %d: expression is not simple"
- " or relocatable", oper_num);
+ "operand %d: expression is not simple or relocatable",
+ oper_num);
}
}
diff --git a/test/reldef.asm b/test/reldef.asm
new file mode 100644
index 00000000..17186c57
--- /dev/null
+++ b/test/reldef.asm
@@ -0,0 +1,9 @@
+ bits 64
+
+ extern bar
+
+ section .data
+foo: dd bar
+ dd foo - $
+; dd foo*2
+ dd bar - $