Merge pull request #2723 from kugelfuhr/kugelfuhr/fix-2717
Allow multiple passes for da65 to resolve labels
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user