From 938185b33ccf30aa8aa20bf8cc22073e140697bf Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 17 Mar 2019 22:57:42 -0700 Subject: 5008 --- subx/030---operands.cc | 1 + subx/032check_operand_bounds.cc | 88 ++++++++++++++++++++++++++++++++++++++++- subx/035labels.cc | 8 ++-- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/subx/030---operands.cc b/subx/030---operands.cc index c8e2942d..1a4ec563 100644 --- a/subx/030---operands.cc +++ b/subx/030---operands.cc @@ -138,6 +138,7 @@ void init_operand_type_help() { ); put(Help, "disp16", "16-bit value to be added in many instructions.\n" + "Currently not used in any SubX instructions.\n" ); put(Help, "disp32", "32-bit value to be added in many instructions.\n" diff --git a/subx/032check_operand_bounds.cc b/subx/032check_operand_bounds.cc index ca114e22..0aae0f67 100644 --- a/subx/032check_operand_bounds.cc +++ b/subx/032check_operand_bounds.cc @@ -47,8 +47,14 @@ void check_operand_bounds(const word& w) { if (!looks_like_hex_int(w.data)) continue; // later transforms are on their own to do their own bounds checking int32_t x = parse_int(w.data); if (x >= 0) { - if (static_cast(x) >= p->second) - raise << "'" << w.original << "' too large to fit in bitfield " << p->first << '\n' << end(); + if (p->first == "disp8" || p->first == "disp16") { + if (static_cast(x) >= p->second/2) + raise << "'" << w.original << "' too large to fit in signed bitfield " << p->first << '\n' << end(); + } + else { + if (static_cast(x) >= p->second) + raise << "'" << w.original << "' too large to fit in bitfield " << p->first << '\n' << end(); + } } else { // hacky? assuming bound is a power of 2 @@ -57,3 +63,81 @@ void check_operand_bounds(const word& w) { } } } + +void test_check_bitfield_sizes_for_imm8() { + run( + "== 0x1\n" // code segment + "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX 0xff/imm8" // shift EBX left + ); + CHECK(!trace_contains_errors()); +} + +void test_check_bitfield_sizes_for_imm8_error() { + Hide_errors = true; + run( + "== 0x1\n" // code segment + "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX 0x100/imm8" // shift EBX left + ); + CHECK_TRACE_CONTENTS( + "error: '0x100/imm8' too large to fit in bitfield imm8\n" + ); +} + +void test_check_bitfield_sizes_for_negative_imm8() { + run( + "== 0x1\n" // code segment + "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX -0x80/imm8" // shift EBX left + ); + CHECK(!trace_contains_errors()); +} + +void test_check_bitfield_sizes_for_negative_imm8_error() { + Hide_errors = true; + run( + "== 0x1\n" // code segment + "c1/shift 4/subop/left 3/mod/direct 1/rm32/ECX -0x81/imm8" // shift EBX left + ); + CHECK_TRACE_CONTENTS( + "error: '-0x81/imm8' too large to fit in bitfield imm8\n" + ); +} + +void test_check_bitfield_sizes_for_disp8() { + // not bothering to run + transform( + "== 0x1\n" // code segment + "01/add 1/mod/*+disp8 3/rm32 1/r32 0x7f/disp8\n" // add ECX to *(EBX+0x7f) + ); + CHECK(!trace_contains_errors()); +} + +void test_check_bitfield_sizes_for_disp8_error() { + Hide_errors = true; + run( + "== 0x1\n" // code segment + "01/add 1/mod/*+disp8 3/rm32 1/r32 0x80/disp8\n" // add ECX to *(EBX+0x80) + ); + CHECK_TRACE_CONTENTS( + "error: '0x80/disp8' too large to fit in signed bitfield disp8\n" + ); +} + +void test_check_bitfield_sizes_for_negative_disp8() { + // not bothering to run + transform( + "== 0x1\n" // code segment + "01/add 1/mod/*+disp8 3/rm32 1/r32 -0x80/disp8\n" // add ECX to *(EBX-0x80) + ); + CHECK(!trace_contains_errors()); +} + +void test_check_bitfield_sizes_for_negative_disp8_error() { + Hide_errors = true; + run( + "== 0x1\n" // code segment + "01/add 1/mod/*+disp8 3/rm32 1/r32 -0x81/disp8\n" // add ECX to *(EBX-0x81) + ); + CHECK_TRACE_CONTENTS( + "error: '-0x81/disp8' too large to fit in bitfield disp8\n" + ); +} diff --git a/subx/035labels.cc b/subx/035labels.cc index 322d1952..575bcec2 100644 --- a/subx/035labels.cc +++ b/subx/035labels.cc @@ -222,14 +222,14 @@ void replace_labels_with_displacements(segment& code, const map if (contains_key(byte_index, curr.data)) { int32_t displacement = static_cast(get(byte_index, curr.data)) - byte_index_next_instruction_starts_at; if (has_operand_metadata(curr, "disp8")) { - if (displacement > 0xff || displacement < -0x7f) - raise << "'" << to_string(inst) << "': label too far away for displacement " << std::hex << displacement << " to fit in 8 bits\n" << end(); + if (displacement > 0x7f || displacement < -0x7f) + raise << "'" << to_string(inst) << "': label too far away for displacement " << std::hex << displacement << " to fit in 8 signed bits\n" << end(); else emit_hex_bytes(new_inst, displacement, 1); } else if (has_operand_metadata(curr, "disp16")) { - if (displacement > 0xffff || displacement < -0x7fff) - raise << "'" << to_string(inst) << "': label too far away for displacement " << std::hex << displacement << " to fit in 16 bits\n" << end(); + if (displacement > 0x7fff || displacement < -0x7fff) + raise << "'" << to_string(inst) << "': label too far away for displacement " << std::hex << displacement << " to fit in 16 signed bits\n" << end(); else emit_hex_bytes(new_inst, displacement, 2); } -- cgit 1.4.1-2-gfad0