summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Crayne <chuck@thor.crayne.org>2008-09-10 19:21:52 -0700
committerCharles Crayne <chuck@thor.crayne.org>2008-09-10 19:21:52 -0700
commit2581c869b1ceabdc243f88b9b72d81554bc6a35a (patch)
treef5aeb05f87a70273fb2158361f7dfa89f43da02e
parent325a4bff508e5cdf8804c6ea3ce6b8eb08110625 (diff)
downloadnasm-2581c869b1ceabdc243f88b9b72d81554bc6a35a.tar.gz
Decouple forward references from optimization
Users who wish to control the level of optimization can continue to specify -O0, -O1, or -Ox, where x can be the letter itself, or any number > 1. However, even with optimization turned off, NASM will always make enough passes to resolve forward references. As a result, INCBIN is now the only item left in the critical expressions list, although TIMES still has its own constant value check.
-rw-r--r--assemble.c11
-rw-r--r--doc/nasmdoc.src89
-rw-r--r--nasm.c11
-rw-r--r--parser.c14
4 files changed, 29 insertions, 96 deletions
diff --git a/assemble.c b/assemble.c
index 70228ac1..16c88615 100644
--- a/assemble.c
+++ b/assemble.c
@@ -249,13 +249,10 @@ static int jmp_match(int32_t segment, int64_t offset, int bits,
if (c != 0370 && c != 0371)
return 0;
- if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
- if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
- && c == 0370)
- return 1;
- else
- return (pass0 == 0); /* match a forward reference */
- }
+ if ((optimizing <= 0 || (ins->oprs[0].type & STRICT)))
+ {
+ return 0;
+ }
isize = calcsize(segment, offset, bits, ins, code);
if (ins->oprs[0].segment != segment)
return 0;
diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index 66856064..068d5d83 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -783,33 +783,26 @@ with a \i{stub preprocessor} which does nothing.
\S{opt-On} The \i\c{-On} Option: Specifying \i{Multipass Optimization}.
-NASM defaults to being a two pass assembler. This means that if you
-have a complex source file which needs more than 2 passes to assemble
-optimally, you have to enable extra passes.
-
-Using the \c{-O} option, you can tell NASM to carry out multiple passes.
+NASM defaults to not optimizing operands which can fit into a signed byte.
+This means that if you want the shortest possible object code,
+you have to enable optimization.
+
+Using the \c{-O} option, you can tell NASM to carry out different levels of optimization.
The syntax is:
-\b \c{-O0} strict two-pass assembly, JMP and Jcc are handled more
- like v0.98, except that backward JMPs are short, if possible.
- Immediate operands take their long forms if a short form is
- not specified.
+\b \c{-O0} No optimization. All operands take their long forms,
+ if a short form is not specified.
-\b \c{-O1} strict two-pass assembly, but forward branches are assembled
- with code guaranteed to reach; may produce larger code than
- -O0, but will produce successful assembly more often if
- branch offset sizes are not specified.
- Additionally, immediate operands which will fit in a signed byte
- are optimized, unless the long form is specified.
+\b \c{-O1} Minimal optimization. As above, but immediate operands
+ which will fit in a signed byte are optimized,
+ unless the long form is specified.
-\b \c{-On} multi-pass optimization, minimize branch offsets; also will
+\b \c{-Ox} where \c{x} is the actual letter \c{x} Multi-pass optimization,
+ minimize branch offsets; also will
minimize signed immediate bytes, overriding size specification
unless the \c{strict} keyword has been used (see \k{strict}).
- The number specifies the maximum number of passes. The more
- passes, the better the code, but the slower is the assembly.
-
-\b \c{-Ox} where \c{x} is the actual letter \c{x}, indicates to NASM
- to do unlimited passes.
+ For compatability with earlier releases, the letter \c{x} may also be any
+ number greater than one. This number has no effect on the actual number of passes.
Note that this is a capital \c{O}, and is different from a small \c{o}, which
is used to specify the output file name. See \k{opt-o}.
@@ -1275,9 +1268,7 @@ redefined later. This is not a \i{preprocessor} definition either:
the value of \c{msglen} is evaluated \e{once}, using the value of
\c{$} (see \k{expr} for an explanation of \c{$}) at the point of
definition, rather than being evaluated wherever it is referenced
-and using the value of \c{$} at the point of reference. Note that
-the operand to an \c{EQU} is also a \i{critical expression}
-(\k{crit}).
+and using the value of \c{$} at the point of reference.
\S{times} \i\c{TIMES}: \i{Repeating} Instructions or Data
@@ -1306,8 +1297,7 @@ Note that there is no effective difference between \c{times 100 resb
1} and \c{resb 100}, except that the latter will be assembled about
100 times faster due to the internal structure of the assembler.
-The operand to \c{TIMES}, like that of \c{EQU} and those of \c{RESB}
-and friends, is a critical expression (\k{crit}).
+The operand to \c{TIMES} is a critical expression (\k{crit}).
Note also that \c{TIMES} can't be applied to \i{macros}: the reason
for this is that \c{TIMES} is processed after the macro phase, which
@@ -1813,52 +1803,7 @@ NASM rejects these examples by means of a concept called a
\e{critical expression}, which is defined to be an expression whose
value is required to be computable in the first pass, and which must
therefore depend only on symbols defined before it. The argument to
-the \c{TIMES} prefix is a critical expression; for the same reason,
-the arguments to the \i\c{RESB} family of pseudo-instructions are
-also critical expressions.
-
-Critical expressions can crop up in other contexts as well: consider
-the following code.
-
-\c mov ax,symbol1
-\c symbol1 equ symbol2
-\c symbol2:
-
-On the first pass, NASM cannot determine the value of \c{symbol1},
-because \c{symbol1} is defined to be equal to \c{symbol2} which NASM
-hasn't seen yet. On the second pass, therefore, when it encounters
-the line \c{mov ax,symbol1}, it is unable to generate the code for
-it because it still doesn't know the value of \c{symbol1}. On the
-next line, it would see the \i\c{EQU} again and be able to determine
-the value of \c{symbol1}, but by then it would be too late.
-
-NASM avoids this problem by defining the right-hand side of an
-\c{EQU} statement to be a critical expression, so the definition of
-\c{symbol1} would be rejected in the first pass.
-
-There is a related issue involving \i{forward references}: consider
-this code fragment.
-
-\c mov eax,[ebx+offset]
-\c offset equ 10
-
-NASM, on pass one, must calculate the size of the instruction \c{mov
-eax,[ebx+offset]} without knowing the value of \c{offset}. It has no
-way of knowing that \c{offset} is small enough to fit into a
-one-byte offset field and that it could therefore get away with
-generating a shorter form of the \i{effective-address} encoding; for
-all it knows, in pass one, \c{offset} could be a symbol in the code
-segment, and it might need the full four-byte form. So it is forced
-to compute the size of the instruction to accommodate a four-byte
-address part. In pass two, having made this decision, it is now
-forced to honour it and keep the instruction large, so the code
-generated in this case is not as small as it could have been. This
-problem can be solved by defining \c{offset} before using it, or by
-forcing byte size in the effective address by coding \c{[byte
-ebx+offset]}.
-
-Note that use of the \c{-On} switch (with n>=2) makes some of the above
-no longer true (see \k{opt-On}).
+the \c{TIMES} prefix is a critical expression.
\H{locallab} \i{Local Labels}
diff --git a/nasm.c b/nasm.c
index 6208a728..198d4bb6 100644
--- a/nasm.c
+++ b/nasm.c
@@ -294,7 +294,7 @@ int main(int argc, char **argv)
time(&official_compile_time);
- pass0 = 1;
+ pass0 = 0;
want_usage = terminate_after_phase = false;
report_error = report_error_gnu;
@@ -1166,8 +1166,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 = (optimizing > 0 ? optimizing : 0) + 2; /* passes 1, optimizing, then 2 */
- pass0 = !(optimizing > 0); /* start at 1 if not optimizing */
+ pass_max = (INT_MAX >> 1) + 2; /* Almost unlimited */
for (passn = 1; pass0 <= 2; passn++) {
int pass1, pass2;
ldfunc def_label;
@@ -1500,7 +1499,7 @@ static void assemble_file(char *fname, StrList **depend_ptr)
parse_line(pass1, line, &output_ins,
report_error, evaluate, def_label);
- if (!(optimizing > 0) && pass0 == 2) {
+ if (optimizing > 0) {
if (forwref != NULL && globallineno == forwref->lineno) {
output_ins.forw_ref = true;
do {
@@ -1513,7 +1512,7 @@ static void assemble_file(char *fname, StrList **depend_ptr)
output_ins.forw_ref = false;
}
- if (!(optimizing > 0) && output_ins.forw_ref) {
+ if (optimizing > 0) {
if (passn == 1) {
for (i = 0; i < output_ins.operands; i++) {
if (output_ins.oprs[i].
@@ -1768,7 +1767,7 @@ static void assemble_file(char *fname, StrList **depend_ptr)
preproc->cleanup(0);
nasmlist.cleanup();
#if 1
- if (optimizing > 0 && opt_verbose_info) /* -On and -Ov switches */
+ if (opt_verbose_info) /* -On and -Ov switches */
fprintf(stdout,
"info:: assembly required 1+%d+1 passes\n", passn-3);
#endif
diff --git a/parser.c b/parser.c
index a88e8837..7e5c9a32 100644
--- a/parser.c
+++ b/parser.c
@@ -308,21 +308,13 @@ restart_parse:
result->condition = tokval.t_inttwo;
/*
- * RESB, RESW and RESD cannot be satisfied with incorrectly
+ * INCBIN cannot be satisfied with incorrectly
* evaluated operands, since the correct values _must_ be known
* on the first pass. Hence, even in pass one, we set the
* `critical' flag on calling evaluate(), so that it will bomb
- * out on undefined symbols. Nasty, but there's nothing we can
- * do about it.
- *
- * For the moment, EQU has the same difficulty, so we'll
- * include that.
+ * out on undefined symbols.
*/
- if (result->opcode == I_RESB || result->opcode == I_RESW ||
- result->opcode == I_RESD || result->opcode == I_RESQ ||
- result->opcode == I_REST || result->opcode == I_RESO ||
- result->opcode == I_RESY ||
- result->opcode == I_INCBIN) {
+ if (result->opcode == I_INCBIN) {
critical = (pass0 < 2 ? 1 : 2);
} else