Next Chapter | Previous Chapter | Contents | Index
NASM, though it attempts to avoid the bureaucracy of assemblers like MASM and TASM, is nevertheless forced to support a few directives. These are described in this chapter.
NASM's directives come in two types: user-level directives and primitive directives. Typically, each directive has a user-level form and a primitive form. In almost all cases, we recommend that users use the user-level forms of the directives, which are implemented as macros which call the primitive forms.
Primitive directives are enclosed in square brackets; user-level directives are not.
In addition to the universal directives described in this chapter, each object file format can optionally supply extra directives in order to control particular features of that file format. These format-specific directives are documented along with the formats that implement them, in chapter 7.
BITS : Specifying Target Processor ModeThe  directive specifies whether NASM
should generate code designed to run on a processor operating in 16-bit
mode, 32-bit mode or 64-bit mode. The syntax is
, where XX is 16, 32 or 64.
In most cases, you should not need to use 
explicitly. The ,
, ,
,  and
 object formats, which are designed for use
in 32-bit or 64-bit operating systems, all cause NASM to select 32-bit or
64-bit mode, respectively, by default. The 
object format allows you to specify each segment you define as either
 or , and
NASM will set its operating mode accordingly, so the use of the
 directive is once again unnecessary.
The most likely reason for using the 
directive is to write 32-bit or 64-bit code in a flat binary file; this is
because the  output format defaults to 16-bit
mode in anticipation of it being used most frequently to write DOS
 programs, DOS 
device drivers and boot loader software.
You do not need to specify 
merely in order to use 32-bit instructions in a 16-bit DOS program; if you
do, the assembler will generate incorrect code because it will be writing
code targeted at a 32-bit platform, to be run on a 16-bit one.
When NASM is in  mode, instructions
which use 32-bit data are prefixed with an 0x66 byte, and those referring
to 32-bit addresses have an 0x67 prefix. In
 mode, the reverse is true: 32-bit
instructions require no prefixes, whereas instructions using 16-bit data
need an 0x66 and those working on 16-bit addresses need an 0x67.
When NASM is in  mode, most
instructions operate the same as they do for
 mode. However, there are 8 more general
and SSE registers, and 16-bit addressing is no longer supported.
The default address size is 64 bits; 32-bit addressing can be selected
with the 0x67 prefix. The default operand size is still 32 bits, however,
and the 0x66 prefix selects 16-bit operand size. The
 prefix is used both to select 64-bit operand
size, and to access the new registers. NASM automatically inserts REX
prefixes when necessary.
When the  prefix is used, the processor
does not know how to address the AH, BH, CH or DH (high 8-bit legacy)
registers. Instead, it is possible to access the the low 8-bits of the SP,
BP SI and DI registers as SPL, BPL, SIL and DIL, respectively; but only
when the REX prefix is used.
The  directive has an exactly equivalent
primitive form, ,
 and
. The user-level form is a macro which
has no function other than to call the primitive form.
Note that the space is neccessary, e.g. 
will not work!
USE16  & USE32 : Aliases for BITSThe `' and
`' directives can be used in place of
`' and
`', for compatibility with other
assemblers.
DEFAULT : Change the assembler defaultsThe  directive changes the assembler
defaults. Normally, NASM defaults to a mode where the programmer is
expected to explicitly specify most features directly. However, this is
occationally obnoxious, as the explicit form is pretty much the only one
one wishes to use.
Currently, the only  that is settable
is whether or not registerless instructions in 64-bit mode are
-relative or not. By default, they are
absolute unless overridden with the  specifier
(see section 3.3). However, if
 is specified,
 is default, unless overridden with the
 specifier, except when used with an FS or
GS segment override.
The special handling of  and
 overrides are due to the fact that these
registers are generally used as thread pointers or other special functions
in 64-bit mode, and generating -relative
addresses would be extremely confusing.
 is disabled with
.
SECTION  or SEGMENT : Changing and Defining SectionsThe  directive
( is an exactly equivalent synonym)
changes which section of the output file the code you write will be
assembled into. In some object file formats, the number and names of
sections are fixed; in others, the user may make up as many as they wish.
Hence  may sometimes give an error
message, or may define a new section, if you try to switch to a section
that does not (yet) exist.
The Unix object formats, and the  object
format (but see section 7.1.3,
all support the standardized section names ,
 and  for the
code, data and uninitialized-data sections. The
 format, by contrast, does not recognize these
section names as being special, and indeed will strip off the leading
period of any section name that has one.
__SECT__  MacroThe  directive is unusual in that its
user-level form functions differently from its primitive form. The
primitive form, , simply switches
the current target section to the one given. The user-level form,
, however, first defines the
single-line macro  to be the primitive
 directive which it is about to issue,
and then issues it. So the user-level directive
        SECTION .text
expands to the two lines
%define __SECT__        [SECTION .text] 
        [SECTION .text]
Users may find it useful to make use of this in their own macros. For
example, the  macro defined in
section 4.3.3 can be usefully
rewritten in the following more sophisticated form:
%macro  writefile 2+ 
        [section .data] 
  %%str:        db      %2 
  %%endstr: 
        __SECT__ 
        mov     dx,%%str 
        mov     cx,%%endstr-%%str 
        mov     bx,%1 
        mov     ah,0x40 
        int     0x21 
%endmacro
This form of the macro, once passed a string to output, first switches
temporarily to the data section of the file, using the primitive form of
the  directive so as not to modify
. It then declares its string in the data
section, and then invokes  to switch back
to whichever section the user was previously working in. It thus
avoids the need, in the previous version of the macro, to include a
 instruction to jump over the data, and also
does not fail if, in a complicated  format
module, the user could potentially be assembling the code in any of several
separate code sections.
ABSOLUTE : Defining Absolute LabelsThe  directive can be thought of as an
alternative form of : it causes the
subsequent code to be directed at no physical section, but at the
hypothetical section starting at the given absolute address. The only
instructions you can use in this mode are the
 family.
 is used as follows:
absolute 0x1A 
    kbuf_chr    resw    1 
    kbuf_free   resw    1 
    kbuf        resw    16
This example describes a section of the PC BIOS data area, at segment
address 0x40: the above code defines  to
be 0x1A,  to be 0x1C, and
 to be 0x1E.
The user-level form of , like that of
, redefines the
 macro when it is invoked.
 and 
are defined as macros which use  (and
also ).
 doesn't have to take an absolute
constant as an argument: it can take an expression (actually, a critical
expression: see section 3.8) and it
can be a value in a segment. For example, a TSR can re-use its setup code
as run-time BSS like this:
        org     100h               ; it's a .COM program 
        jmp     setup              ; setup code comes last 
        ; the resident part of the TSR goes here 
setup: 
        ; now write the code that installs the TSR here 
absolute setup 
runtimevar1     resw    1 
runtimevar2     resd    20 
tsr_end:
This defines some variables `on top of' the setup code, so that after the setup has finished running, the space it took up can be re-used as data storage for the running TSR. The symbol `tsr_end' can be used to calculate the total size of the part of the TSR that needs to be made resident.
EXTERN : Importing Symbols from Other Modules is similar to the MASM directive
 and the C keyword
: it is used to declare a symbol which is
not defined anywhere in the module being assembled, but is assumed to be
defined in some other module and needs to be referred to by this one. Not
every object-file format can support external variables: the
 format cannot.
The  directive takes as many arguments
as you like. Each argument is the name of a symbol:
extern _printf extern _sscanf,_fscanf
Some object-file formats provide extra features to the
 directive. In all cases, the extra
features are used by suffixing a colon to the symbol name followed by
object-format specific text. For example, the 
format allows you to declare that the default segment base of an external
should be the group  by means of the
directive
extern _variable:wrt dgroup
The primitive form of  differs from the
user-level form only in that it can take only one argument at a time: the
support for multiple arguments is implemented at the preprocessor level.
You can declare the same variable as 
more than once: NASM will quietly ignore the second and later
redeclarations. You can't declare a variable as
 as well as something else, though.
GLOBAL : Exporting Symbols to Other Modules is the other end of
: if one module declares a symbol as
 and refers to it, then in order to prevent
linker errors, some other module must actually define the symbol
and declare it as . Some assemblers use the
name  for this purpose.
The  directive applying to a symbol must
appear before the definition of the symbol.
 uses the same syntax as
, except that it must refer to symbols
which are defined in the same module as the
 directive. For example:
global _main 
_main: 
        ; some code
, like ,
allows object formats to define private extensions by means of a colon. The
 object format, for example, lets you specify
whether global data items are functions or data:
global hashlookup:function, hashtable:data
Like , the primitive form of
 differs from the user-level form only in
that it can take only one argument at a time.
COMMON : Defining Common Data AreasThe  directive is used to declare
common variables. A common variable is much like a global variable
declared in the uninitialized data section, so that
common intvar 4
is similar in function to
global intvar section .bss intvar resd 1
The difference is that if more than one module defines the same common
variable, then at link time those variables will be merged, and
references to  in all modules will point at
the same piece of memory.
Like  and
,  supports
object-format specific extensions. For example, the
 format allows common variables to be NEAR or
FAR, and the  format allows you to specify the
alignment requirements of a common variable:
common commvar 4:near ; works in OBJ common intarray 100:4 ; works in ELF: 4 byte aligned
Once again, like  and
, the primitive form of
 differs from the user-level form only in
that it can take only one argument at a time.
CPU : Defining CPU DependenciesThe  directive restricts assembly to those
instructions which are available on the specified CPU.
Options are:
CPU 8086  Assemble only 8086 instruction set
CPU 186  Assemble instructions up to the 80186
instruction set
CPU 286  Assemble instructions up to the 286
instruction set
CPU 386  Assemble instructions up to the 386
instruction set
CPU 486  486 instruction set
CPU 586  Pentium instruction set
CPU PENTIUM  Same as 586
CPU 686  P6 instruction set
CPU PPRO  Same as 686
CPU P2  Same as 686
CPU P3  Pentium III (Katmai) instruction sets
CPU KATMAI  Same as P3
CPU P4  Pentium 4 (Willamette) instruction set
CPU WILLAMETTE  Same as P4
CPU PRESCOTT  Prescott instruction set
CPU X64  x86-64 (x64/AMD64/Intel 64)
instruction set
CPU IA64  IA64 CPU (in x86 mode) instruction
set
All options are case insensitive. All instructions will be selected only if they apply to the selected CPU or lower. By default, all instructions are available.
FLOAT : Handling of floating-point constantsBy default, floating-point constants are rounded to nearest, and IEEE denormals are supported. The following options can be set to alter this behaviour:
FLOAT DAZ  Flush denormals to zero
FLOAT NODAZ  Do not flush denormals to zero
(default)
FLOAT NEAR  Round to nearest (default)
FLOAT UP  Round up (toward +Infinity)
FLOAT DOWN  Round down (toward -Infinity)
FLOAT ZERO  Round toward zero
FLOAT DEFAULT  Restore default settings
The standard macros ,
, and
 contain the current state, as long as
the programmer has avoided the use of the brackeded primitive form,
().
 contains the full set of
floating-point settings; this value can be saved away and invoked later to
restore the setting.