From 80cc2029d31f4a7f1cd4334b9cfaf9556f0163ce Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 4 Oct 2016 06:29:25 -0700 Subject: Make it possible to generate PC-relative relocations in data 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 --- assemble.c | 175 ++++++++++++++++++++++++++++++++++++-------------------- nasm.h | 12 ++-- parser.c | 72 ++++++++++++++++++----- test/reldef.asm | 9 +++ 4 files changed, 188 insertions(+), 80 deletions(-) create mode 100644 test/reldef.asm 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 - $ -- cgit v1.2.1