From 472a7c1d17e0212b3cbf5302a9f5cdb358be4425 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 31 Oct 2016 08:44:25 -0700 Subject: [PATCH] Allow relative references to external symbols in data Allow constructs like: dd foo - $ ... where foo is an external symbol. Currently this is only implemented for extops, i.e. dx opcodes. Signed-off-by: H. Peter Anvin --- asm/assemble.c | 8 +++--- asm/parser.c | 72 +++++++++++++++++++++++++++++++++++++++---------- include/nasm.h | 12 +++++---- test/imm.asm | 11 ++++++++ test/reldef.asm | 9 +++++++ 5 files changed, 90 insertions(+), 22 deletions(-) create mode 100644 test/imm.asm create mode 100644 test/reldef.asm diff --git a/asm/assemble.c b/asm/assemble.c index 78dbb609..a4f8c883 100644 --- a/asm/assemble.c +++ b/asm/assemble.c @@ -322,12 +322,15 @@ static void out(struct out_data *data) if (!data->size) return; /* Nothing to do */ + /* + * Convert addresses to RAWDATA if possible + * XXX: not all backends want this for global symbols!!!! + */ switch (data->type) { case OUT_ADDRESS: asize = data->size; nasm_assert(asize <= 8); if (data->tsegment == NO_SEG && data->twrt == NO_SEG) { - /* Convert to RAWDATA */ /* XXX: check for overflow */ uint8_t *q = xdata.b; @@ -342,7 +345,6 @@ static void out(struct out_data *data) asize = data->size; nasm_assert(asize <= 8); if (data->tsegment == data->segment && data->twrt == NO_SEG) { - /* Convert to RAWDATA */ uint8_t *q = xdata.b; int64_t delta = data->toffset - data->offset - (data->inslen - data->insoffs); @@ -535,7 +537,7 @@ int64_t assemble(int32_t segment, int64_t start, int bits, iflag_t cp, " instruction"); } else { data.insoffs = 0; - data.type = OUT_ADDRESS; + data.type = e->relative ? OUT_RELADDR : OUT_ADDRESS; data.inslen = data.size = wsize; data.toffset = e->offset; data.tsegment = e->segment; diff --git a/asm/parser.c b/asm/parser.c index 6210cc69..a20ef943 100644 --- a/asm/parser.c +++ b/asm/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. * @@ -254,7 +254,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++; } @@ -375,6 +375,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; @@ -652,19 +705,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/include/nasm.h b/include/nasm.h index 67204362..d1b13e13 100644 --- a/include/nasm.h +++ b/include/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 */ @@ -575,6 +575,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 {...} */ @@ -582,7 +583,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) */ @@ -593,6 +594,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; @@ -707,7 +709,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/test/imm.asm b/test/imm.asm new file mode 100644 index 00000000..39a7d315 --- /dev/null +++ b/test/imm.asm @@ -0,0 +1,11 @@ + bits 64 + + mov eax,1 + mov eax,-1 + mov eax,0x11111111 + mov ecx,2 + add ecx,-6 + add ecx,strict dword -6 + add ecx,4 + add ecx,strict dword 4 + add ecx,10000 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 - $