From: Victor v. d. E. <vic...@gm...> - 2010-01-24 20:32:56
|
http://sourceforge.net/tracker/?func=detail&aid=2496848&group_id=6208&atid=106208 This old bug can wait till 2.09, I'd just like to get this patch out in the open and hear what you think about it. Getting all cases right is a bit tricky, e.g. [byte eax + 0xffffffff], but I think this is right. --- >From a24a43754892c5e5dc2ecaa5540e0f2715dbfd9d Mon Sep 17 00:00:00 2001 From: Victor van den Elzen <vic...@gm...> Date: Sun, 24 Jan 2010 21:24:57 +0100 Subject: [PATCH] BR 2496848: Tighten ea checks Check if the offset and the representation are equivalent. Disallow REL on absolute addresses. I'm not sure what that would mean and the output formats don't support it. Warn about ignored displacement size modifiers. --- assemble.c | 42 +++++++++++++++++++++++++++++++++++++----- test/br2496848.asm | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 test/br2496848.asm diff --git a/assemble.c b/assemble.c index 81476db..8f885b3 100644 --- a/assemble.c +++ b/assemble.c @@ -254,12 +254,22 @@ static void warn_overflow_const(int64_t data, int size) static void warn_overflow_opd(const struct operand *o, int size) { - if (size < 8 && o->wrt == NO_SEG && o->segment == NO_SEG) { + if (o->wrt == NO_SEG && o->segment == NO_SEG) { if (overflow_general(o->offset, size)) warn_overflow(ERR_PASS2, size); } } +static inline int64_t signed_bits(int64_t value, int bits) +{ + if (bits < 64) { + value &= ((int64_t)1 << bits) - 1; + if (value & (int64_t)1 << (bits - 1)) + value |= (int64_t)-1 << bits; + } + return value; +} + /* * This routine wrappers the real output format's output routine, * in order to pass a copy of the data off to the listing file @@ -722,7 +732,7 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp, int64_t isize; const uint8_t *codes = temp->code; int j; - + isize = calcsize(segment, offset, bits, instruction, codes); if (isize < 0) return -1; @@ -1858,18 +1868,25 @@ static void gencode(int32_t segment, int64_t offset, int bits, case 4: case 8: data = opy->offset; - warn_overflow_opd(opy, ea_data.bytes); s += ea_data.bytes; if (ea_data.rip) { if (opy->segment == segment) { data -= insn_end; + 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); } else { + /* overflow check in output/linker? */ out(offset, segment, &data, OUT_REL4ADR, insn_end - offset, opy->segment, opy->wrt); } } else { + if (overflow_general(opy->offset, ins->addr_size >> 3) || + signed_bits(opy->offset, ins->addr_size) != + signed_bits(opy->offset, ea_data.bytes * 8)) + warn_overflow(ERR_PASS2, ea_data.bytes); + type = OUT_ADDRESS; out(offset, segment, &data, OUT_ADDRESS, ea_data.bytes, opy->segment, opy->wrt); @@ -2232,6 +2249,20 @@ static ea *process_ea(operand * input, ea * output, int bits, if (input->basereg == -1 && (input->indexreg == -1 || input->scale == 0)) { /* 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 (input->eaflags & EAF_BYTEOFFS || + (input->eaflags & EAF_WORDOFFS && + input->disp_size != (addrbits != 16 ? 32 : 16))) { + nasm_error(ERR_WARNING | ERR_PASS1, "displacement size ignored on absolute address"); + } + if (bits == 64 && (~input->type & IP_REL)) { int scale, index, base; output->sib_present = true; @@ -2250,7 +2281,7 @@ static ea *process_ea(operand * input, ea * output, int bits, } } else { /* it's an indirection */ int i = input->indexreg, b = input->basereg, s = input->scale; - int32_t o = input->offset, seg = input->segment; + int32_t seg = input->segment; int hb = input->hintbase, ht = input->hinttype; int t, it, bt; /* register numbers */ opflags_t x, ix, bx; /* register flags */ @@ -2278,7 +2309,7 @@ static ea *process_ea(operand * input, ea * output, int bits, if ((ix|bx) & (BITS32|BITS64)) { /* it must be a 32/64-bit memory reference. Firstly we have * to check that all registers involved are type E/Rxx. */ - int32_t sok = BITS32|BITS64; + int32_t sok = BITS32|BITS64, o = input->offset; if (it != -1) { if (!(REG64 & ~ix) || !(REG32 & ~ix)) @@ -2417,6 +2448,7 @@ static ea *process_ea(operand * input, ea * output, int bits, } } else { /* it's 16-bit */ int mod, rm; + int16_t o = input->offset; /* check for 64-bit long mode */ if (addrbits == 64) diff --git a/test/br2496848.asm b/test/br2496848.asm new file mode 100644 index 0000000..a60b7c9 --- /dev/null +++ b/test/br2496848.asm @@ -0,0 +1,42 @@ +;Testname=unoptimized; Arguments=-O0 -fbin -o br2496848.bin; Files=stdout stderr br2496848.bin +;Testname=optimized; Arguments=-Ox -fbin -o br2496848.bin; Files=stdout stderr br2496848.bin + +bits 64 + +foo: + +default abs + +mov al, [qword 0xffffffffffffffff] +mov al, [qword 0x1ffffffffffffffff] + +mov cl, [byte 0x12345678] + +default rel + +mov cl, [foo] +mov cl, [foo + 0x10000000] +mov cl, [foo + 0x100000000] + +mov cl, [0x100] +mov cl, [$$ + 0x100] + +mov cl, [rax - 1] +mov cl, [rax + 0xffffffff] +mov cl, [rax + 0x1ffffffff] + +bits 32 +mov cl, [eax - 1] +mov cl, [eax + 0xffffffff] +mov cl, [eax + 0x1ffffffff] +mov cl, [byte eax + 0xffffffff] +mov cl, [byte eax + 0x1ffffffff] +mov cl, [byte eax + 0x1000ffff] + +bits 16 +mov cl, [di - 1] +mov cl, [di + 0xffff] +mov cl, [di + 0x1ffff] +mov cl, [byte di + 0xffff] +mov cl, [byte di + 0x1ffff] +mov cl, [byte di + 0x10ff] -- 1.6.6.1 |