From 0d268fb78cc17360d4b20c6bdd4b54c8c996fc63 Mon Sep 17 00:00:00 2001 From: Victor van den Elzen 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 | 32 +++++++++++++++++++++++++++----- nasmlib.h | 10 ++++++++++ test/br2496848.asm | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 test/br2496848.asm diff --git a/assemble.c b/assemble.c index 81476db0..ca6f18f1 100644 --- a/assemble.c +++ b/assemble.c @@ -254,7 +254,7 @@ 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); } @@ -722,7 +722,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 +1858,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 +2239,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 +2271,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 +2299,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 +2438,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/nasmlib.h b/nasmlib.h index 793fccd9..b0349471 100644 --- a/nasmlib.h +++ b/nasmlib.h @@ -445,6 +445,16 @@ static inline bool overflow_unsigned(int64_t value, int bytes) return value < vmin || value > vmax; } +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; +} + int idata_bytes(int opcode); /* check if value is power of 2 */ diff --git a/test/br2496848.asm b/test/br2496848.asm new file mode 100644 index 00000000..a60b7c9e --- /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] -- 2.11.4.GIT