about summary refs log tree commit diff stats
path: root/036labels.cc
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-12-28 23:20:14 -0800
committerKartik Agaram <vc@akkartik.com>2020-12-28 23:20:14 -0800
commitb15db82f7ce2a4b11e0cfe55b3c31cc8c4a8d89a (patch)
tree4a1be82dab55d2b80eb8b2385a5f621dab29ba07 /036labels.cc
parentd6d8ce22449deab6fc2417dfb8a4ca6642ac47b4 (diff)
downloadmu-b15db82f7ce2a4b11e0cfe55b3c31cc8c4a8d89a.tar.gz
7455
New approach to disambiguating /disp32 arguments: based on opcodes rather
than metadata.

I interpret /disp32 as PC-relative in a short list of instructions. Otherwise
it's absolute if it gets a label.

There should be no reason to pass labels into /disp8 or /disp16.
Diffstat (limited to '036labels.cc')
-rw-r--r--036labels.cc17
1 files changed, 15 insertions, 2 deletions
diff --git a/036labels.cc b/036labels.cc
index c269538a..72d11da5 100644
--- a/036labels.cc
+++ b/036labels.cc
@@ -224,6 +224,7 @@ void replace_labels_with_displacements(segment& code, const map<string, int32_t>
       const word& curr = inst.words.at(j);
       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;
+        int32_t absolute_address = code.start + get(byte_index, curr.data);
         if (has_argument_metadata(curr, "disp8")) {
           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();
@@ -237,9 +238,12 @@ void replace_labels_with_displacements(segment& code, const map<string, int32_t>
             emit_hex_bytes(new_inst, displacement, 2);
         }
         else if (has_argument_metadata(curr, "disp32")) {
-          emit_hex_bytes(new_inst, displacement, 4);
+          if (is_far_jump_or_call(new_inst))
+            emit_hex_bytes(new_inst, displacement, 4);
+          else
+            emit_hex_bytes(new_inst, absolute_address, 4);
         } else if (has_argument_metadata(curr, "imm32")) {
-          emit_hex_bytes(new_inst, code.start + get(byte_index, curr.data), 4);
+          emit_hex_bytes(new_inst, absolute_address, 4);
         }
       }
       else {
@@ -251,6 +255,15 @@ void replace_labels_with_displacements(segment& code, const map<string, int32_t>
   }
 }
 
+bool is_far_jump_or_call(const line& inst) {
+  string first_opcode = inst.words.at(0).data;
+  if (first_opcode == "e8" || first_opcode == "e9") return true;
+  if (SIZE(inst.words) < 2) return false;
+  if (first_opcode != "0f") return false;
+  string second_opcode = inst.words.at(1).data;
+  return starts_with(second_opcode, "8");
+}
+
 string data_to_string(const line& inst) {
   ostringstream out;
   for (int i = 0;  i < SIZE(inst.words);  ++i) {