This chapter describes some of the common problems that users have been known to encounter with NASM, and answers them. If you think you have found a bug in NASM, please see section E.2.
We sometimes get `bug' reports about NASM generating inefficient, or
even `wrong', code on instructions such as ADD ESP,8
. This is
a deliberate design feature, connected to predictability of output: NASM,
on seeing ADD ESP,8
, will generate the form of the instruction
which leaves room for a 32-bit offset. You need to code
ADD ESP,BYTE 8
if you want the space-efficient form of the
instruction. This isn't a bug, it's user error: if you prefer to have NASM
produce the more efficient code automatically enable optimization with the
-O
option (see section
2.1.23).
Similarly, people complain that when they issue conditional jumps (which
are SHORT
by default) that try to jump too far, NASM reports
`short jump out of range' instead of making the jumps longer.
This, again, is partly a predictability issue, but in fact has a more
practical reason as well. NASM has no means of being told what type of
processor the code it is generating will be run on; so it cannot decide for
itself that it should generate Jcc NEAR
type instructions,
because it doesn't know that it's working for a 386 or above.
Alternatively, it could replace the out-of-range short JNE
instruction with a very short JE
instruction that jumps over a
JMP NEAR
; this is a sensible solution for processors below a
386, but hardly efficient on processors which have good branch prediction
and could have used JNE NEAR
instead. So, once again,
it's up to the user, not the assembler, to decide what instructions should
be generated. See section
2.1.23.
ORG
Doesn't WorkPeople writing boot sector programs in the bin
format often
complain that ORG
doesn't work the way they'd like: in order
to place the 0xAA55
signature word at the end of a 512-byte
boot sector, people who are used to MASM tend to code
ORG 0 ; some boot sector code ORG 510 DW 0xAA55
This is not the intended use of the ORG
directive in NASM,
and will not work. The correct way to solve this problem in NASM is to use
the TIMES
directive, like this:
ORG 0 ; some boot sector code TIMES 510-($-$$) DB 0 DW 0xAA55
The TIMES
directive will insert exactly enough zero bytes
into the output to move the assembly point up to 510. This method also has
the advantage that if you accidentally fill your boot sector too full, NASM
will catch the problem at assembly time and report it, so you won't end up
with a boot sector that you have to disassemble to find out what's wrong
with it.
TIMES
Doesn't WorkThe other common problem with the above code is people who write the
TIMES
line as
TIMES 510-$ DB 0
by reasoning that $
should be a pure number, just like 510,
so the difference between them is also a pure number and can happily be fed
to TIMES
.
NASM is a modular assembler: the various component parts are
designed to be easily separable for re-use, so they don't exchange
information unnecessarily. In consequence, the bin
output
format, even though it has been told by the ORG
directive that
the .text
section should start at 0, does not pass that
information back to the expression evaluator. So from the evaluator's point
of view, $
isn't a pure number: it's an offset from a section
base. Therefore the difference between $
and 510 is also not a
pure number, but involves a section base. Values involving section bases
cannot be passed as arguments to TIMES
.
The solution, as in the previous section, is to code the
TIMES
line in the form
TIMES 510-($-$$) DB 0
in which $
and $$
are offsets from the same
section base, and so their difference is a pure number. This will solve the
problem and generate sensible code.