Cc65: [da65] 6502 Relative address opcodes write 16-bit operand if unable to generate label

Created on 21 Jul 2020  路  3Comments  路  Source: cc65/cc65

Ran into an issue when trying to assemble some disassembled 6502 code. Took a bit to track down, but eventually found this at line 155 in src/da65/handler.c:

/* THIS CODE IS A MESS AND WILL FAIL ON SEVERAL CONDITIONS! ### */

And sure enough, that was what I was hitting. It's possible to get through the following block of code without assigning a label due to the conditions for label generation not being met. When this happens, 6502 opcodes using relative addressing (the _B**_ branching opcodes) print the 16-bit absolute address as the operand, which then cannot be reassembled by ca65. I don't have a proper C debugging environment set up at the moment to figure out what condition is causing the label generation to fail, so I slapped a temporary bandaid on it that just tells the OH_Relative function when label generation didn't happen, so it can fall back on printing the relative offset instead:
````diff
diff --git a/src/da65/handler.c b/src/da65/handler.c
index f8a778b2..4280379e 100644
--- a/src/da65/handler.c
+++ b/src/da65/handler.c
@@ -34,6 +34,7 @@

#include
+#include

/* common /
#include "xmalloc.h"
@@ -130,7 +131,7 @@ static const char
GetAddrArg (unsigned Flags, unsigned Addr)

-static void GenerateLabel (unsigned Flags, unsigned Addr)
+static bool GenerateLabel (unsigned Flags, unsigned Addr)
/* Generate a label in pass one if requested /
{
/
Generate labels in pass #1, and only if we don't have a label already */
@@ -188,6 +189,10 @@ static void GenerateLabel (unsigned Flags, unsigned Addr)
AddDepLabel (Addr, atIntLabel, GetLabelName (LabelAddr), Offs);
}
}

  • return true;
  • }
  • else {
  • return false;
    }
    }

@@ -343,10 +348,14 @@ void OH_Relative (const OpcDesc* D)
unsigned Addr = (((int) PC+2) + Offs) & 0xFFFF;

 /* Generate a label in pass 1 */

- GenerateLabel (D->Flags, Addr);
+ bool LabelGenerated = GenerateLabel (D->Flags, Addr);

 /* Output the line */

- OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
+ if (LabelGenerated == true) {
+ OneLine (D, "%s", GetAddrArg (D->Flags, Addr));
+ } else {
+ OneLine (D, "$%02X", GetCodeByte (PC+1));
+ }
}
````
This does compile, and makes the relative addressing opcodes generate an 8-bit relative offset operand instead of the 16-bit absolute address, but I'm not going to make a pull request for this unless you want one. I'm guessing this isn't the solution you want (I only spent a couple hours messing with this, and definitely won't claim that I know the standards of the project), although chances are that falling back to just replicating the code bytes is a decent solution for most operands that can't resolve to labels.

Let me know if you could use any more information.

bug

All 3 comments

Please use the four backticks markdown next time.

Yeah, did some more messing with this and I'm guessing it will probably need a real solution. The resulting disassemblies I'm getting with the change I diff'ed above seem to have nearly every branch relative opcode only getting the offset, never a label. Definitely room for improvement. (This output is at least re-assemble-able with ca65, though)

  • Your GenerateLabel() returned true only when it made a _new_ label.
  • In ca65, branch operands must be addresses, not offsets. Therefore, offsets must be embedded in expressions that are relative to the current Program Counter.

Commit 44c82eb1c3f0360aa70d1ce77a16989e5567b59b should fix the problem.

Was this page helpful?
0 / 5 - 0 ratings