Merge pull request #2723 from kugelfuhr/kugelfuhr/fix-2717

Allow multiple passes for da65 to resolve labels
This commit is contained in:
Bob Andrews
2025-06-23 15:14:01 +02:00
committed by GitHub
7 changed files with 113 additions and 15 deletions

View File

@@ -46,14 +46,16 @@ The assembler accepts the following options:
---------------------------------------------------------------------------
Usage: da65 [options] [inputfile]
Short options:
-d Debug mode
-g Add debug info to object file
-h Help (this text)
-i name Specify an info file
-m Run multiple passes to resolve labels
-o name Name the output file
-v Increase verbosity
-F Add formfeeds to the output
-s Accept line markers in the info file
-S addr Set the start/load address
-s Accept line markers in the info file
-V Print the disassembler version
Long options:
@@ -61,6 +63,7 @@ Long options:
--comment-column n Specify comment start column
--comments n Set the comment level for the output
--cpu type Set cpu type
--debug Debug mode
--debug-info Add debug info to object file
--formfeeds Add formfeeds to the output
--help Help (this text)
@@ -68,6 +71,7 @@ Long options:
--info name Specify an info file
--label-break n Add newline if label exceeds length n
--mnemonic-column n Specify mnemonic start column
--multi-pass Run multiple passes to resolve labels
--pagelength n Set the page length for the listing
--start-addr addr Set the start/load address
--sync-lines Accept line markers in the info file
@@ -123,6 +127,12 @@ Here is a description of all the command line options:
</itemize>
<tag><tt>-d, --debug</tt></tag>
Enables debug mode, something that should not be needed for mere
mortals:-)
<label id="option--formfeeds">
<tag><tt>-F, --formfeeds</tt></tag>
@@ -179,6 +189,15 @@ Here is a description of all the command line options:
<tt><ref id="LABELBREAK" name="LABELBREAK"></tt>.
<tag><tt>-m, --multi-pass</tt></tag>
This option causes the disassembler to run multiple passes over the input
binary to find and create all necessary labels. Without this option the
disassembler may detect the necessity for a label in the final pass, when
output was already partially generated. It will output numerical addresses
or program counter relative expressions in this case.
<label id="option--mnemonic-column">
<tag><tt>--mnemonic-column n</tt></tag>

View File

@@ -54,8 +54,8 @@ const char CfgExt[] = ".cfg"; /* Config file extension */
/* Flags and other command line stuff */
unsigned char DebugInfo = 0; /* Add debug info to the object file */
unsigned char FormFeeds = 0; /* Add form feeds to the output? */
unsigned char MultiPass = 0; /* Run several passes to resolve labels */
unsigned char UseHexOffs = 0; /* Use hexadecimal label offsets */
unsigned char PassCount = 2; /* How many passed do we do? */
signed char NewlineAfterJMP = -1; /* Add a newline after a JMP insn? */
signed char NewlineAfterRTS = -1; /* Add a newline after a RTS insn? */
unsigned char HaveStartAddr = 0; /* Flag for start address given */

View File

@@ -59,8 +59,8 @@ extern const char CfgExt[]; /* Config file extension */
/* Flags and other command line stuff */
extern unsigned char DebugInfo; /* Add debug info to the object file */
extern unsigned char FormFeeds; /* Add form feeds to the output? */
extern unsigned char MultiPass; /* Run several passes to resolve labels */
extern unsigned char UseHexOffs; /* Use hexadecimal label offsets */
extern unsigned char PassCount; /* How many passed do we do? */
extern signed char NewlineAfterJMP;/* Add a newline after a JMP insn? */
extern signed char NewlineAfterRTS;/* Add a newline after a RTS insn? */
extern unsigned char HaveStartAddr; /* Flag for start address given */
@@ -70,6 +70,8 @@ extern long InputOffs; /* Offset into input file */
extern long InputSize; /* Number of bytes to read from input */
/* Stuff needed by many routines */
#define PASS_PREP 1 /* Preparation pass */
#define PASS_FINAL 2 /* Final pass generating output */
extern unsigned Pass; /* Disassembler pass */
extern char Now[128]; /* Current time as string */

View File

@@ -74,6 +74,9 @@ struct Label {
#define LABEL_HASH_SIZE 4096u /* Must be power of two */
static Label* LabelTab[LABEL_HASH_SIZE];
/* Total number of labels */
static unsigned long LabelCount = 0;
/*****************************************************************************/
@@ -187,6 +190,9 @@ static void AddLabel (uint32_t Addr, attr_t Attr, const char* Name)
/* Remember the attribute */
MarkAddr (Addr, Attr);
/* Count labels */
++LabelCount;
}
@@ -538,3 +544,11 @@ void DefOutOfRangeLabels (void)
/* Free allocated storage */
DoneCollection (&Labels);
}
unsigned long GetLabelCount (void)
/* Return the total number of labels defined so far */
{
return LabelCount;
}

View File

@@ -100,6 +100,9 @@ void ForwardLabel (unsigned Offs);
void DefOutOfRangeLabels (void);
/* Output any labels that are out of the loaded code range */
unsigned long GetLabelCount (void);
/* Return the total number of labels defined so far */
/* End of labels.h */

View File

@@ -42,8 +42,10 @@
/* common */
#include "abend.h"
#include "check.h"
#include "cmdline.h"
#include "cpu.h"
#include "debugflag.h"
#include "fname.h"
#include "print.h"
#include "version.h"
@@ -79,9 +81,11 @@ static void Usage (void)
{
printf ("Usage: %s [options] [inputfile]\n"
"Short options:\n"
" -d\t\t\tDebug mode\n"
" -g\t\t\tAdd debug info to object file\n"
" -h\t\t\tHelp (this text)\n"
" -i name\t\tSpecify an info file\n"
" -m\t\t\tRun multiple passes to resolve labels\n"
" -o name\t\tName the output file\n"
" -v\t\t\tIncrease verbosity\n"
" -F\t\t\tAdd formfeeds to the output\n"
@@ -94,6 +98,7 @@ static void Usage (void)
" --comment-column n\tSpecify comment start column\n"
" --comments n\t\tSet the comment level for the output\n"
" --cpu type\t\tSet cpu type\n"
" --debug\t\tDebug mode\n"
" --debug-info\t\tAdd debug info to object file\n"
" --formfeeds\t\tAdd formfeeds to the output\n"
" --help\t\tHelp (this text)\n"
@@ -101,6 +106,7 @@ static void Usage (void)
" --info name\t\tSpecify an info file\n"
" --label-break n\tAdd newline if label exceeds length n\n"
" --mnemonic-column n\tSpecify mnemonic start column\n"
" --multi-pass\t\tRun multiple passes to resolve labels\n"
" --pagelength n\tSet the page length for the listing\n"
" --start-addr addr\tSet the start/load address\n"
" --sync-lines\t\tAccept line markers in the info file\n"
@@ -223,6 +229,15 @@ static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
static void OptDebug (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Disassembler debug mode */
{
++Debug;
}
static void OptDebugInfo (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Add debug info to the object file */
@@ -298,6 +313,15 @@ static void OptMnemonicColumn (const char* Opt, const char* Arg)
static void OptMultiPass (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Handle the --multi-pass option */
{
MultiPass = 1;
}
static void OptPageLength (const char* Opt attribute ((unused)), const char* Arg)
/* Handle the --pagelength option */
{
@@ -590,15 +614,37 @@ static void OnePass (void)
static void Disassemble (void)
/* Disassemble the code */
{
/* Pass 1 */
Pass = 1;
/* Preparation pass */
Pass = PASS_PREP;
OnePass ();
/* If the --multi-pass option is given, repeat this pass until we have no
** new labels.
*/
if (MultiPass) {
unsigned long LabelCount = GetLabelCount ();
unsigned Passes = 1;
while (1) {
unsigned long NewLabelCount;
ResetCode ();
OnePass ();
CHECK(++Passes <= 4096); /* Safety measure */
NewLabelCount = GetLabelCount ();
if (NewLabelCount <= LabelCount) {
break;
}
LabelCount = NewLabelCount;
}
if (Debug) {
printf ("Run %u preparation passes to resolve labels\n", Passes);
}
}
Output ("---------------------------");
LineFeed ();
/* Pass 2 */
Pass = 2;
/* Final pass */
Pass = PASS_FINAL;
ResetCode ();
OutputSettings ();
DefOutOfRangeLabels ();
@@ -617,6 +663,7 @@ int main (int argc, char* argv [])
{ "--comment-column", 1, OptCommentColumn },
{ "--comments", 1, OptComments },
{ "--cpu", 1, OptCPU },
{ "--debug", 0, OptDebug },
{ "--debug-info", 0, OptDebugInfo },
{ "--formfeeds", 0, OptFormFeeds },
{ "--help", 0, OptHelp },
@@ -624,6 +671,7 @@ int main (int argc, char* argv [])
{ "--info", 1, OptInfo },
{ "--label-break", 1, OptLabelBreak },
{ "--mnemonic-column", 1, OptMnemonicColumn },
{ "--multi-pass", 0, OptMultiPass },
{ "--pagelength", 1, OptPageLength },
{ "--start-addr", 1, OptStartAddr },
{ "--sync-lines", 0, OptSyncLines },
@@ -653,6 +701,14 @@ int main (int argc, char* argv [])
LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
break;
case 'd':
if (Arg[2] == '\0') {
OptDebug (Arg, 0);
} else {
UnknownOption (Arg);
}
break;
case 'g':
OptDebugInfo (Arg, 0);
break;
@@ -665,6 +721,10 @@ int main (int argc, char* argv [])
OptInfo (Arg, GetArg (&I, 2));
break;
case 'm':
OptMultiPass (Arg, 0);
break;
case 'o':
OutFile = GetArg (&I, 2);
break;

View File

@@ -124,7 +124,7 @@ void CloseOutput (void)
void Output (const char* Format, ...)
/* Write to the output file */
{
if (Pass == PassCount) {
if (Pass == PASS_FINAL) {
va_list ap;
va_start (ap, Format);
Col += vfprintf (F, Format, ap);
@@ -137,7 +137,7 @@ void Output (const char* Format, ...)
void Indent (unsigned N)
/* Make sure the current line column is at position N (zero based) */
{
if (Pass == PassCount) {
if (Pass == PASS_FINAL) {
while (Col < N) {
fputc (' ', F);
++Col;
@@ -150,7 +150,7 @@ void Indent (unsigned N)
void LineFeed (void)
/* Add a linefeed to the output file */
{
if (Pass == PassCount) {
if (Pass == PASS_FINAL) {
fputc ('\n', F);
if (PageLength > 0 && ++Line >= PageLength) {
if (FormFeeds) {
@@ -185,7 +185,7 @@ void DefForward (const char* Name, const char* Comment, unsigned Offs)
** current PC.
*/
{
if (Pass == PassCount) {
if (Pass == PASS_FINAL) {
/* Flush existing output if necessary */
if (Col > 1) {
LineFeed ();
@@ -212,7 +212,7 @@ void DefForward (const char* Name, const char* Comment, unsigned Offs)
void DefConst (const char* Name, const char* Comment, uint32_t Addr)
/* Define an address constant */
{
if (Pass == PassCount) {
if (Pass == PASS_FINAL) {
Output ("%s", Name);
Indent (ACol);
Output (":= $%04" PRIX32, Addr);
@@ -313,7 +313,7 @@ void DataDWordLine (uint32_t ByteCount)
void SeparatorLine (void)
/* Print a separator line */
{
if (Pass == PassCount && Comments >= 1) {
if (Pass == PASS_FINAL && Comments >= 1) {
Output ("; ----------------------------------------------------------------------------");
LineFeed ();
}
@@ -324,7 +324,7 @@ void SeparatorLine (void)
void StartSegment (const char* Name, unsigned AddrSize)
/* Start a segment */
{
if (Pass == PassCount) {
if (Pass == PASS_FINAL) {
LineFeed ();
Output (".segment");
Indent (ACol);
@@ -368,7 +368,7 @@ void LineComment (unsigned PC, unsigned Count)
{
unsigned I;
if (Pass == PassCount && Comments >= 2) {
if (Pass == PASS_FINAL && Comments >= 2) {
Indent (CCol);
Output ("; %04X", PC);
if (Comments >= 3) {