about summary refs log tree commit diff stats
path: root/subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-03-17 22:57:42 -0700
committerKartik Agaram <vc@akkartik.com>2019-03-17 22:57:42 -0700
commit938185b33ccf30aa8aa20bf8cc22073e140697bf (patch)
tree4e65589bca1a5145ec8056afba49aae8d9499f75 /subx
parentba80524a9f38667f9d82990067192103b490dd73 (diff)
downloadmu-938185b33ccf30aa8aa20bf8cc22073e140697bf.tar.gz
5008
Diffstat (limited to 'subx')
-rw-r--r--subx/030---operands.cc1
-rw-r--r--subx/032check_operand_bounds.cc88
-rw-r--r--subx/035labels.cc8
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<uint32_t>(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<uint32_t>(x) >= p->second/2)
+          raise << "'" << w.original << "' too large to fit in signed bitfield " << p->first << '\n' << end();
+      }
+      else {
+        if (static_cast<uint32_t>(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<string, int32_t>
       if (contains_key(byte_index, curr.data)) {
         int32_t displacement = static_cast<int32_t>(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);
         }