| What is it? | Who wrote it? | Where is it? | Latest version | Known bugs | |||||
| Link to this site | Manual | Other documents | Chat forum | Tools and Libs | |||||
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 directivesuser-level directives and primitive directivesprimitive 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 directivesformat-specific directives are documented along with the formats that implement them, in chapter 6.
BITS : Specifying Target
Processor ModeThe directive specifies whether NASM should
generate code designed to run on a processor operating in 16-bit mode, or code
designed to run on a processor operating in 32-bit mode. The syntax is
or .
In most cases, you should not need to use
explicitly. The , ,
and object
formats, which are designed for use in 32-bit operating systems, all cause NASM
to select 32-bit mode 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 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 state, instructions which
use 32-bit data are prefixed with an 0x66 byte, and those referring to 32-bit
addresses have an 0x67 prefix. In state, the
reverse is true: 32-bit instructions require no prefixes, whereas instructions
using 16-bit data need an 0x66 and those working in 16-bit addresses need an
0x67.
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.
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,
all support the standardised section names ,
and for the code,
data and uninitialised-data sections. The format,
by contrast, does not recognise 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.2.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.7) 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
uninitialised 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.