summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Crayne <chuck@thor.crayne.org>2008-09-11 18:54:06 -0700
committerCharles Crayne <chuck@thor.crayne.org>2008-09-11 18:54:06 -0700
commitc1905c21698642fa94f5887745ecf0336b15ee8c (patch)
treed4fe8d13bfb57458fedb190d42ae75680c90b64f
parent4252823e95bb365e704cdd8ae526d2daf01a6533 (diff)
downloadnasm-c1905c21698642fa94f5887745ecf0336b15ee8c.tar.gz
Halt assembly if addresses are not converging.
Change global_offset_changed from bool to int so that progress of convergence can be monitored. If change count does not decrease from previous pass, increment stall counter. If stall count reaches threshold, terminate assembly with error message.
-rw-r--r--labels.c4
-rw-r--r--nasm.c25
2 files changed, 16 insertions, 13 deletions
diff --git a/labels.c b/labels.c
index 068d758e..b7a1b445 100644
--- a/labels.c
+++ b/labels.c
@@ -77,7 +77,7 @@ struct permts { /* permanent text storage */
char data[PERMTS_SIZE]; /* ... the data block itself */
};
-extern bool global_offset_changed; /* defined in nasm.c */
+extern int64_t global_offset_changed; /* defined in nasm.c */
static struct hash_table ltab; /* labels hash table */
static union label *ldata; /* all label data blocks */
@@ -209,7 +209,7 @@ void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
prevlabel = lptr->defn.label;
}
- global_offset_changed |= (lptr->defn.offset != offset);
+ if (lptr->defn.offset != offset) global_offset_changed++;
lptr->defn.offset = offset;
lptr->defn.segment = segment;
diff --git a/nasm.c b/nasm.c
index 3e4b78e6..4d4ab50b 100644
--- a/nasm.c
+++ b/nasm.c
@@ -73,7 +73,9 @@ int optimizing = -1; /* number of optimization passes to take */
static int sb, cmd_sb = 16; /* by default */
static uint32_t cmd_cpu = IF_PLEVEL; /* highest level by default */
static uint32_t cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */
-bool global_offset_changed; /* referenced in labels.c */
+int64_t global_offset_changed; /* referenced in labels.c */
+int64_t prev_offset_changed;
+int32_t stall_count;
static struct location location;
int in_abs_seg; /* Flag we are in ABSOLUTE seg */
@@ -1166,9 +1168,7 @@ static void assemble_file(char *fname, StrList **depend_ptr)
report_error(ERR_FATAL, "command line: "
"32-bit segment size requires a higher cpu");
- pass_max = 1000; /* Always terminate in a reasonable time */
- /* No real program should need this many passes */
-
+ pass_max = prev_offset_changed = (INT_MAX >> 1) + 2; /* Almost unlimited */
for (passn = 1; pass0 <= 2; passn++) {
int pass1, pass2;
ldfunc def_label;
@@ -1186,7 +1186,7 @@ static void assemble_file(char *fname, StrList **depend_ptr)
nasmlist.init(listname, report_error);
}
in_abs_seg = false;
- global_offset_changed = false; /* set by redefine_label */
+ global_offset_changed = 0; /* set by redefine_label */
location.segment = ofmt->section(NULL, pass2, &sb);
globalbits = sb;
if (passn > 1) {
@@ -1717,7 +1717,6 @@ static void assemble_file(char *fname, StrList **depend_ptr)
nasm_free(line);
location.offset = offs = GET_CURR_OFFS;
} /* end while (line = preproc->getline... */
-
if (pass1 == 2 && global_offset_changed)
report_error(ERR_NONFATAL,
"phase error detected at end of assembly.");
@@ -1732,26 +1731,30 @@ static void assemble_file(char *fname, StrList **depend_ptr)
usage();
exit(1);
}
+
if (passn > 1 && !global_offset_changed)
pass0++;
+ else if (global_offset_changed && global_offset_changed < prev_offset_changed) {
+ prev_offset_changed = global_offset_changed;
+ stall_count = 0;
+ }
+ else stall_count++;
- if(passn >= pass_max)
+ if((stall_count > 997) || (passn >= pass_max))
/* We get here if the labels don't converge
* Example: FOO equ FOO + 1
*/
report_error(ERR_NONFATAL,
"Can't find valid values for all labels "
- "after %d passes, giving up. "
- "Possible cause: recursive equ's.", passn);
+ "after %d passes, giving up.\n"
+ " Possible cause: recursive equ's.", passn);
}
preproc->cleanup(0);
nasmlist.cleanup();
-#if 1
if (opt_verbose_info) /* -On and -Ov switches */
fprintf(stdout,
"info:: assembly required 1+%d+1 passes\n", passn-3);
-#endif
} /* exit from assemble_file (...) */
static enum directives getkw(char **directive, char **value)