NASM is a portable assembler, designed to be able to compile on any ANSI
C-supporting platform and produce output to run on a variety of Intel x86
operating systems. For this reason, it has a large number of available
output formats, selected using the -f option on the NASM
command line. Each of these formats, along with its extensions to the base
NASM syntax, is detailed in this chapter.
As stated in section 2.1.1,
NASM chooses a default name for your output file based on the input file
name and the chosen output format. This will be generated by removing the
extension (.asm, .s, or whatever you like to use)
from the input file name, and substituting an extension defined by the
output format. The extensions are given with each format below.
bin: Flat-Form Binary OutputThe bin format does not produce object files: it generates
nothing in the output file except the code you wrote. Such `pure binary'
files are used by MS-DOS: .COM executables and
.SYS device drivers are pure binary files. Pure binary output
is also useful for operating system and boot loader development.
The bin format supports multiple section names. For details
of how NASM handles sections in the bin format, see
section 8.1.3.
Using the bin format puts NASM by default into 16-bit mode
(see section 7.1). In order to use
bin to write 32-bit or 64-bit code, such as an OS kernel, you
need to explicitly issue the BITS 32 or BITS 64
directive.
bin has no default output file name extension: instead, it
leaves your file name as it is once the original extension has been
removed. Thus, the default is for NASM to assemble binprog.asm
into a binary file called binprog.
It is extremely important to understand that the binary output format is simply nothing other than a linker built into the NASM executable. As such, NASM behaves just as it does when producing any other output format: notably the list file reflects the code output before relocation, and the addresses in the list file are addresses relative to the start of the current output section.
ORG: Binary File Program OriginThe bin format provides an additional directive to the list
given in chapter 7: ORG. The
function of the ORG directive is to specify the origin address
which NASM will assume the program begins at when it is loaded into memory.
For example, the following code will generate the longword
0x00000104:
org 0x100
dd label
label:
Unlike the ORG directive provided by MASM-compatible
assemblers, which allows you to jump around in the object file and
overwrite code you have already generated, NASM's ORG does
exactly what the directive says: origin. Its sole function is to
specify one offset which is added to all internal address references within
the section; it does not permit any of the trickery that MASM's version
does. See section 13.1.3 for
further comments.
bin Extensions to the SECTION Directive, bin extensions to}The bin output format extends the SECTION (or
SEGMENT) directive to allow you to specify the alignment
requirements of segments. This is done by appending the ALIGN
qualifier to the end of the section-definition line. For example,
section .data align=16
switches to the section .data and also specifies that it
must be aligned on a 16-byte boundary.
The parameter to ALIGN specifies how many low bits of the
section start address must be forced to zero. The alignment value given may
be any power of two.
bin FormatThe bin format allows the use of multiple sections, of
arbitrary names, besides the "known" .text,
.data, and .bss names.
Sections may be designated progbits or nobits.
Default is progbits (except .bss, which defaults
to nobits, of course).
Sections can be aligned at a specified boundary following the previous
section with align=, or at an arbitrary byte-granular position
with start=.
Sections can be given a virtual start address, which will be used for
the calculation of all memory references within that section with
vstart=.
Sections can be ordered using
follows=<section> or
vfollows=<section> as an alternative to
specifying an explicit start address.
Arguments to org, start, vstart,
and align= are critical expressions. See
section 3.8. E.g.
align=(1 << ALIGN_SHIFT) –
ALIGN_SHIFT must be defined before it is used here.
Any code which comes before an explicit SECTION directive
is directed by default into the .text section.
If an ORG statement is not given, ORG 0 is
used by default.
The .bss section will be placed after the last
progbits section, unless start=,
vstart=, follows=, or vfollows= has
been specified.
All sections are aligned on dword boundaries, unless a different alignment has been specified.
Sections may not overlap.
NASM creates the section.<secname>.start for each
section, which may be used in your code.
Map files can be generated in -f bin format by means of the
[map] option. Map types of all (default),
brief, sections, segments, or
symbols may be specified. Output may be directed to
stdout (default), stderr, or a specified file.
E.g. [map symbols myfile.map]. No "user form" exists, the
square brackets must be used.
ith: Intel Hex OutputThe ith file format produces Intel hex-format files. Just
as the bin format, this is a flat memory image format with no
support for further relocation or linking. It is usually used with ROM
programmers and similar utilities.
From a programmer point of view, this behaves identically to the
.bin format; the only difference is the encoding of the
output. All extensions supported by the bin file format is
also supported by the ith file format.
ith provides a default output file-name extension of
.ith.
srec: Motorola S-Records OutputThe srec file format produces Motorola S-records files.
Just as the bin format, this is a flat memory image format
with no support for relocation or linking. It is usually used with ROM
programmers and similar utilities.
From a programmer point of view, this behaves identically to the
.bin format; the only difference is the encoding of the
output. All extensions supported by the bin file format is
also supported by the srec file format.
srec provides a default output file-name extension of
.srec.
obj: Microsoft OMF Object FilesThe obj file format (NASM calls it obj rather
than omf for historical reasons) is the one produced by MASM
and TASM, which is typically fed to 16-bit DOS linkers to produce
.EXE files. It is also the format used by OS/2.
obj provides a default output file-name extension of
.obj.
obj is not exclusively a 16-bit format, though: NASM has
full support for the 32-bit extensions to the format. In particular, 32-bit
obj format files are used by Borland's Win32 compilers,
instead of using Microsoft's newer win32 object file format.
The obj format does not define any special segment names:
you can call your segments anything you like. Typical names for segments in
obj format files are CODE, DATA and
BSS.
If your source file contains code before specifying an explicit
SEGMENT directive, then NASM will invent its own segment
called __NASMDEFSEG for you.
When you define a segment in an obj file, NASM defines the
segment name as a symbol as well, so that you can access the segment
address of the segment. So, for example:
segment data
dvar: dw 1234
segment code
function:
mov ax,data ; get segment address of data
mov ds,ax ; and move it into DS
inc word [dvar] ; now this reference will work
ret
The obj format also enables the use of the SEG
and WRT operators, so that you can write code which does
things like
extern foo
mov ax,seg foo ; get preferred segment of foo
mov ds,ax
mov ax,data ; a different segment
mov es,ax
mov ax,[ds:foo] ; this accesses `foo'
mov [es:foo wrt data],bx ; so does this
obj Extensions to the SEGMENT DirectiveThe obj output format extends the SEGMENT (or
SECTION) directive to allow you to specify various properties
of the segment you are defining. This is done by appending extra qualifiers
to the end of the segment-definition line. For example,
segment code private align=16
defines the segment code, but also declares it to be a
private segment, and requires that the portion of it described in this code
module must be aligned on a 16-byte boundary.
The available qualifiers are:
PRIVATE, PUBLIC, COMMON and
STACK specify the combination characteristics of the segment.
PRIVATE segments do not get combined with any others by the
linker; PUBLIC and STACK segments get
concatenated together at link time; and COMMON segments all
get overlaid on top of each other rather than stuck end-to-end.
ALIGN is used, as shown above, to specify how many low bits
of the segment start address must be forced to zero. The alignment value
given may be any power of two from 1 to 4096; in reality, the only values
supported are 1, 2, 4, 16, 256 and 4096, so if 8 is specified it will be
rounded up to 16, and 32, 64 and 128 will all be rounded up to 256, and so
on. Note that alignment to 4096-byte boundaries is a PharLap extension to
the format and may not be supported by all linkers.
CLASS can be used to specify the segment class; this
feature indicates to the linker that segments of the same class should be
placed near each other in the output file. The class name can be any word,
e.g. CLASS=CODE.
OVERLAY, like CLASS, is specified with an
arbitrary word as an argument, and provides overlay information to an
overlay-capable linker.
Segments can be declared as USE16 or USE32,
which has the effect of recording the choice in the object file and also
ensuring that NASM's default assembly mode when assembling in that segment
is 16-bit or 32-bit respectively.
When writing OS/2 object files, you should declare 32-bit segments as
FLAT, which causes the default segment base for anything in
the segment to be the special group FLAT, and also defines the
group if it is not already defined.
The obj file format also allows segments to be declared as
having a pre-defined absolute segment address, although no linkers are
currently known to make sensible use of this feature; nevertheless, NASM
allows you to declare a segment such as
SEGMENT SCREEN ABSOLUTE=0xB800 if you need to. The
ABSOLUTE and ALIGN keywords are mutually
exclusive.
NASM's default segment attributes are PUBLIC,
ALIGN=1, no class, no overlay, and USE16.
GROUP: Defining Groups of SegmentsThe obj format also allows segments to be grouped, so that
a single segment register can be used to refer to all the segments in a
group. NASM therefore supplies the GROUP directive, whereby
you can code
segment data
; some data
segment bss
; some uninitialized data
group dgroup data bss
which will define a group called dgroup to contain the
segments data and bss. Like SEGMENT,
GROUP causes the group name to be defined as a symbol, so that
you can refer to a variable var in the data
segment as var wrt data or as var wrt dgroup,
depending on which segment value is currently in your segment register.
If you just refer to var, however, and var is
declared in a segment which is part of a group, then NASM will default to
giving you the offset of var from the beginning of the
group, not the segment. Therefore SEG var,
also, will return the group base rather than the segment base.
NASM will allow a segment to be part of more than one group, but will generate a warning if you do this. Variables declared in a segment which is part of more than one group will default to being relative to the first group that was defined to contain the segment.
A group does not have to contain any segments; you can still make
WRT references to a group which does not contain the variable
you are referring to. OS/2, for example, defines the special group
FLAT with no segments in it.
UPPERCASE: Disabling Case Sensitivity in OutputAlthough NASM itself is case sensitive, some OMF linkers are not;
therefore it can be useful for NASM to output single-case object files. The
UPPERCASE format-specific directive causes all segment, group
and symbol names that are written to the object file to be forced to upper
case just before being written. Within a source file, NASM is still
case-sensitive; but the object file can be written entirely in upper case
if desired.
UPPERCASE is used alone on a line; it requires no
parameters.
IMPORT: Importing DLL SymbolsThe IMPORT format-specific directive defines a symbol to be
imported from a DLL, for use if you are writing a DLL's import library in
NASM. You still need to declare the symbol as EXTERN as well
as using the IMPORT directive.
The IMPORT directive takes two required parameters,
separated by white space, which are (respectively) the name of the symbol
you wish to import and the name of the library you wish to import it from.
For example:
import WSAStartup wsock32.dll
A third optional parameter gives the name by which the symbol is known in the library you are importing it from, in case this is not the same as the name you wish the symbol to be known by to your code once you have imported it. For example:
import asyncsel wsock32.dll WSAAsyncSelect
EXPORT: Exporting DLL SymbolsThe EXPORT format-specific directive defines a global
symbol to be exported as a DLL symbol, for use if you are writing a DLL in
NASM. You still need to declare the symbol as GLOBAL as well
as using the EXPORT directive.
EXPORT takes one required parameter, which is the name of
the symbol you wish to export, as it was defined in your source file. An
optional second parameter (separated by white space from the first) gives
the external name of the symbol: the name by which you wish the
symbol to be known to programs using the DLL. If this name is the same as
the internal name, you may leave the second parameter off.
Further parameters can be given to define attributes of the exported symbol. These parameters, like the second, are separated by white space. If further parameters are given, the external name must also be specified, even if it is the same as the internal name. The available attributes are:
resident indicates that the exported name is to be kept
resident by the system loader. This is an optimization for frequently used
symbols imported by name.
nodata indicates that the exported symbol is a function
which does not make use of any initialized data.
parm=NNN, where NNN is an integer, sets the
number of parameter words for the case in which the symbol is a call gate
between 32-bit and 16-bit segments.
An attribute which is just a number indicates that the symbol should be exported with an identifying number (ordinal), and gives the desired number.
For example:
export myfunc
export myfunc TheRealMoreFormalLookingFunctionName
export myfunc myfunc 1234 ; export by ordinal
export myfunc myfunc resident parm=23 nodata
..start: Defining the Program Entry PointOMF linkers require exactly one of the object files being
linked to define the program entry point, where execution will begin when
the program is run. If the object file that defines the entry point is
assembled using NASM, you specify the entry point by declaring the special
symbol ..start at the point where you wish execution to begin.
obj Extensions to the EXTERN DirectiveIf you declare an external symbol with the directive
extern foo
then references such as mov ax,foo will give you the offset
of foo from its preferred segment base (as specified in
whichever module foo is actually defined in). So to access the
contents of foo you will usually need to do something like
mov ax,seg foo ; get preferred segment base
mov es,ax ; move it into ES
mov ax,[es:foo] ; and use offset `foo' from it
This is a little unwieldy, particularly if you know that an external is
going to be accessible from a given segment or group, say
dgroup. So if DS already contained
dgroup, you could simply code
mov ax,[foo wrt dgroup]
However, having to type this every time you want to access
foo can be a pain; so NASM allows you to declare
foo in the alternative form
extern foo:wrt dgroup
This form causes NASM to pretend that the preferred segment base of
foo is in fact dgroup; so the expression
seg foo will now return dgroup, and the
expression foo is equivalent to foo wrt dgroup.
This default-WRT mechanism can be used to make externals
appear to be relative to any group or segment in your program. It can also
be applied to common variables: see section
8.4.8.
obj Extensions to the COMMON DirectiveThe obj format allows common variables to be either near or
far; NASM allows you to specify which your variables should be by the use
of the syntax
common nearvar 2:near ; `nearvar' is a near common common farvar 10:far ; and `farvar' is far
Far common variables may be greater in size than 64Kb, and so the OMF specification says that they are declared as a number of elements of a given size. So a 10-byte far common variable could be declared as ten one-byte elements, five two-byte elements, two five-byte elements or one ten-byte element.
Some OMF linkers require the element size, as well as the
variable size, to match when resolving common variables declared in more
than one module. Therefore NASM must allow you to specify the element size
on your far common variables. This is done by the following syntax:
common c_5by2 10:far 5 ; two five-byte elements common c_2by5 10:far 2 ; five two-byte elements
If no element size is specified, the default is 1. Also, the
FAR keyword is not required when an element size is specified,
since only far commons may have element sizes at all. So the above
declarations could equivalently be
common c_5by2 10:5 ; two five-byte elements common c_2by5 10:2 ; five two-byte elements
In addition to these extensions, the COMMON directive in
obj also supports default-WRT specification like
EXTERN does (explained in section
8.4.7). So you can also declare things like
common foo 10:wrt dgroup common bar 16:far 2:wrt data common baz 24:wrt data:6
Since NASM 2.13.02, obj files contain embedded dependency
file information. To suppress the generation of dependencies, use
%pragma obj nodepend
win32: Microsoft Win32 Object FilesThe win32 output format generates Microsoft Win32 object
files, suitable for passing to Microsoft linkers such as Visual C++. Note
that Borland Win32 compilers do not use this format, but use
obj instead (see section 8.4).
win32 provides a default output file-name extension of
.obj.
Note that although Microsoft say that Win32 object files follow the
COFF (Common Object File Format) standard, the object files
produced by Microsoft Win32 compilers are not compatible with COFF linkers
such as DJGPP's, and vice versa. This is due to a difference of opinion
over the precise semantics of PC-relative relocations. To produce COFF
files suitable for DJGPP, use NASM's coff output format;
conversely, the coff format does not produce object files that
Win32 linkers can generate correct output from.
win32 Extensions to the SECTION DirectiveLike the obj format, win32 allows you to
specify additional information on the SECTION directive line,
to control the type and properties of sections you declare. Section types
and properties are generated automatically by NASM for the standard section
names .text, .data and .bss, but may
still be overridden by these qualifiers.
The available qualifiers are:
code, or equivalently text, defines the
section to be a code section. This marks the section as readable and
executable, but not writable, and also indicates to the linker that the
type of the section is code.
data and bss define the section to be a data
section, analogously to code. Data sections are marked as
readable and writable, but not executable. data declares an
initialized data section, whereas bss declares an
uninitialized data section.
rdata declares an initialized data section that is readable
but not writable. Microsoft compilers use this section to place constants
in it.
info defines the section to be an informational section,
which is not included in the executable file by the linker, but may (for
example) pass information to the linker. For example, declaring an
info–type section called .drectve causes
the linker to interpret the contents of the section as command-line
options.
align=, used with a trailing number as in obj,
gives the alignment requirements of the section. The maximum you may
specify is 64: the Win32 object file format contains no means to request a
greater section alignment than this. If alignment is not explicitly
specified, the defaults are 16-byte alignment for code sections, 8-byte
alignment for rdata sections and 4-byte alignment for data (and BSS)
sections. Informational sections get a default alignment of 1 byte (no
alignment), though the value does not matter.
comdat=, followed by a number ("selection"), colon (acting
as a separator) and a name, marks the section as a "COMDAT section". It
allows Microsoft linkers to perform function-level linking, to deal with
multiply defined symbols, to eliminate dead code/data. The "selection"
number should be one of the IMAGE_COMDAT_SELECT_* constants
from
COFF format specification;
this value controls if the linker allows multiply defined symbols and how
it handles them. The name is the "COMDAT symbol" – basically a new
name for the section. So even though you have one section given by the main
name (e.g. .text), it can actually consist of hundreds of
COMDAT sections having their own name (and alignment). When the "selection"
is IMAGE_COMDAT_SELECT_ASSOCIATIVE (5), the following name is the "COMDAT
symbol" of the associated COMDAT section; this way you can link a piece of
code or data only when another piece of code or data gets actually linked.
So, when linking a NASM-compiled file with some C code, the source may
be structured as follows. Note that the default .text section
in handled in a special way and it doesn't work well with
comdat; you may want to append a $ character and
an arbitrary suffix to the section name. It will get linked into the
.text section anyway – see the info on
Grouped Sections.
section .text$1 align=16 comdat=1:FirstFnc
... ; Code linked only if referenced from C
section .text$1 align=16 comdat=1:SecondFnc
... ; Code linked only if referenced from C
section .rdata align=32 comdat=5:FirstFnc
... ; Data linked only if the related code (FirstFnc) is linked
The defaults assumed by NASM if you do not specify the above qualifiers are:
section .text code align=16 section .data data align=4 section .rdata rdata align=8 section .bss bss align=4
The win64 format also adds:
section .pdata rdata align=4 section .xdata rdata align=8
Any other section name is treated by default like .text.
win32: Safe Structured Exception HandlingAmong other improvements in Windows XP SP2 and Windows Server 2003
Microsoft has introduced concept of "safe structured exception handling."
General idea is to collect handlers' entry points in designated read-only
table and have alleged entry point verified against this table prior
exception control is passed to the handler. In order for an executable
module to be equipped with such "safe exception handler table," all object
modules on linker command line has to comply with certain criteria. If one
single module among them does not, then the table in question is omitted
and above mentioned run-time checks will not be performed for application
in question. Table omission is by default silent and therefore can be
easily overlooked. One can instruct linker to refuse to produce binary
without such table by passing /safeseh command line option.
Without regard to this run-time check merits it's natural to expect NASM
to be capable of generating modules suitable for /safeseh
linking. From developer's viewpoint the problem is two-fold:
how to adapt modules not deploying exception handlers of their own;
how to adapt/develop modules utilizing custom exception handling;
Former can be easily achieved with any NASM version by adding following line to source code:
$@feat.00 equ 1
As of version 2.03 NASM adds this absolute symbol automatically. If it's not already present to be precise. I.e. if for whatever reason developer would choose to assign another value in source file, it would still be perfectly possible.
Registering custom exception handler on the other hand requires certain
"magic." As of version 2.03 additional directive is implemented,
safeseh, which instructs the assembler to produce
appropriately formatted input data for above mentioned "safe exception
handler table." Its typical use would be:
section .text
extern _MessageBoxA@16
%if __?NASM_VERSION_ID?__ >= 0x02030000
safeseh handler ; register handler as "safe handler"
%endif
handler:
push DWORD 1 ; MB_OKCANCEL
push DWORD caption
push DWORD text
push DWORD 0
call _MessageBoxA@16
sub eax,1 ; incidentally suits as return value
; for exception handler
ret
global _main
_main:
push DWORD handler
push DWORD [fs:0]
mov DWORD [fs:0],esp ; engage exception handler
xor eax,eax
mov eax,DWORD[eax] ; cause exception
pop DWORD [fs:0] ; disengage exception handler
add esp,4
ret
text: db 'OK to rethrow, CANCEL to generate core dump',0
caption:db 'SEGV',0
section .drectve info
db '/defaultlib:user32.lib /defaultlib:msvcrt.lib '
As you might imagine, it's perfectly possible to produce .exe binary
with "safe exception handler table" and yet engage unregistered exception
handler. Indeed, handler is engaged by simply manipulating
[fs:0] location at run-time, something linker has no power
over, run-time that is. It should be explicitly mentioned that such failure
to register handler's entry point with safeseh directive has
undesired side effect at run-time. If exception is raised and unregistered
handler is to be executed, the application is abruptly terminated without
any notification whatsoever. One can argue that system could at least have
logged some kind "non-safe exception handler in x.exe at address n" message
in event log, but no, literally no notification is provided and user is
left with no clue on what caused application failure.
Finally, all mentions of linker in this paragraph refer to Microsoft
linker version 7.x and later. Presence of @feat.00 symbol and
input data for "safe exception handler table" causes no backward
incompatibilities and "safeseh" modules generated by NASM 2.03 and later
can still be linked by earlier versions or non-Microsoft linkers.
The win32 and win64 formats support the
Microsoft CodeView debugging format. Currently CodeView version 8 format is
supported (cv8), but newer versions of the CodeView debugger
should be able to handle this format as well.
win64: Microsoft Win64 Object FilesThe win64 output format generates Microsoft Win64 object
files, which is nearly 100% identical to the win32 object
format (section 8.5) with the exception that it
is meant to target 64-bit code and the x86-64 platform altogether. This
object file is used exactly the same as the win32 object
format (section 8.5), in NASM, with regard to
this exception.
win64: Writing Position-Independent CodeWhile REL takes good care of RIP-relative addressing, there
is one aspect that is easy to overlook for a Win64 programmer: indirect
references. Consider a switch dispatch table:
jmp qword [dsptch+rax*8]
...
dsptch: dq case0
dq case1
...
Even a novice Win64 assembler programmer will soon realize that the code is not 64-bit savvy. Most notably linker will refuse to link it with
'ADDR32' relocation to '.text' invalid without /LARGEADDRESSAWARE:NO
So [s]he will have to split jmp instruction as following:
lea rbx,[rel dsptch]
jmp qword [rbx+rax*8]
What happens behind the scene is that effective address in
lea is encoded relative to instruction pointer, or in
perfectly position-independent manner. But this is only part of the
problem! Trouble is that in .dll context caseN relocations
will make their way to the final module and might have to be adjusted at
.dll load time. To be specific when it can't be loaded at preferred
address. And when this occurs, pages with such relocations will be rendered
private to current process, which kind of undermines the idea of sharing
.dll. But no worry, it's trivial to fix:
lea rbx,[rel dsptch]
add rbx,[rbx+rax*8]
jmp rbx
...
dsptch: dq case0-dsptch
dq case1-dsptch
...
NASM version 2.03 and later provides another alternative,
wrt ..imagebase operator, which returns offset from base
address of the current image, be it .exe or .dll module, therefore the
name. For those acquainted with PE-COFF format base address denotes start
of IMAGE_DOS_HEADER structure. Here is how to implement switch
with these image-relative references:
lea rbx,[rel dsptch]
mov eax,[rbx+rax*4]
sub rbx,dsptch wrt ..imagebase
add rbx,rax
jmp rbx
...
dsptch: dd case0 wrt ..imagebase
dd case1 wrt ..imagebase
One can argue that the operator is redundant. Indeed, snippet before
last works just fine with any NASM version and is not even Windows
specific... The real reason for implementing wrt ..imagebase
will become apparent in next paragraph.
It should be noted that wrt ..imagebase is defined as
32-bit operand only:
dd label wrt ..imagebase ; ok
dq label wrt ..imagebase ; bad
mov eax,label wrt ..imagebase ; ok
mov rax,label wrt ..imagebase ; bad
win64: Structured Exception HandlingStructured exception handing in Win64 is completely different matter
from Win32. Upon exception program counter value is noted, and
linker-generated table comprising start and end addresses of all the
functions [in given executable module] is traversed and compared to the
saved program counter. Thus so called UNWIND_INFO structure is
identified. If it's not found, then offending subroutine is assumed to be
"leaf" and just mentioned lookup procedure is attempted for its caller. In
Win64 leaf function is such function that does not call any other function
nor modifies any Win64 non-volatile registers, including stack
pointer. The latter ensures that it's possible to identify leaf function's
caller by simply pulling the value from the top of the stack.
While majority of subroutines written in assembler are not calling any
other function, requirement for non-volatile registers' immutability leaves
developer with not more than 7 registers and no stack frame, which is not
necessarily what [s]he counted with. Customarily one would meet the
requirement by saving non-volatile registers on stack and restoring them
upon return, so what can go wrong? If [and only if] an exception is raised
at run-time and no UNWIND_INFO structure is associated with
such "leaf" function, the stack unwind procedure will expect to find
caller's return address on the top of stack immediately followed by its
frame. Given that developer pushed caller's non-volatile registers on
stack, would the value on top point at some code segment or even
addressable space? Well, developer can attempt copying caller's return
address to the top of stack and this would actually work in some very
specific circumstances. But unless developer can guarantee that these
circumstances are always met, it's more appropriate to assume worst case
scenario, i.e. stack unwind procedure going berserk. Relevant question is
what happens then? Application is abruptly terminated without any
notification whatsoever. Just like in Win32 case, one can argue that system
could at least have logged "unwind procedure went berserk in x.exe at
address n" in event log, but no, no trace of failure is left.
Now, when we understand significance of the UNWIND_INFO
structure, let's discuss what's in it and/or how it's processed. First of
all it is checked for presence of reference to custom language-specific
exception handler. If there is one, then it's invoked. Depending on the
return value, execution flow is resumed (exception is said to be
"handled"), or rest of UNWIND_INFO structure is
processed as following. Beside optional reference to custom handler, it
carries information about current callee's stack frame and where
non-volatile registers are saved. Information is detailed enough to be able
to reconstruct contents of caller's non-volatile registers upon call to
current callee. And so caller's context is reconstructed, and then unwind
procedure is repeated, i.e. another UNWIND_INFO structure is
associated, this time, with caller's instruction pointer, which is then
checked for presence of reference to language-specific handler, etc. The
procedure is recursively repeated till exception is handled. As last resort
system "handles" it by generating memory core dump and terminating the
application.
As for the moment of this writing NASM unfortunately does not facilitate generation of above mentioned detailed information about stack frame layout. But as of version 2.03 it implements building blocks for generating structures involved in stack unwinding. As simplest example, here is how to deploy custom exception handler for leaf function:
default rel
section .text
extern MessageBoxA
handler:
sub rsp,40
mov rcx,0
lea rdx,[text]
lea r8,[caption]
mov r9,1 ; MB_OKCANCEL
call MessageBoxA
sub eax,1 ; incidentally suits as return value
; for exception handler
add rsp,40
ret
global main
main:
xor rax,rax
mov rax,QWORD[rax] ; cause exception
ret
main_end:
text: db 'OK to rethrow, CANCEL to generate core dump',0
caption:db 'SEGV',0
section .pdata rdata align=4
dd main wrt ..imagebase
dd main_end wrt ..imagebase
dd xmain wrt ..imagebase
section .xdata rdata align=8
xmain: db 9,0,0,0
dd handler wrt ..imagebase
section .drectve info
db '/defaultlib:user32.lib /defaultlib:msvcrt.lib '
What you see in .pdata section is element of the "table
comprising start and end addresses of function" along with reference to
associated UNWIND_INFO structure. And what you see in
.xdata section is UNWIND_INFO structure
describing function with no frame, but with designated exception handler.
References are required to be image-relative (which is the real
reason for implementing wrt ..imagebase operator). It should
be noted that rdata align=n, as well as
wrt ..imagebase, are optional in these two segments' contexts,
i.e. can be omitted. Latter means that all 32-bit references, not
only above listed required ones, placed into these two segments turn out
image-relative. Why is it important to understand? Developer is allowed to
append handler-specific data to UNWIND_INFO structure, and if
[s]he adds a 32-bit reference, then [s]he will have to remember to adjust
its value to obtain the real pointer.
As already mentioned, in Win64 terms leaf function is one that does not
call any other function nor modifies any non-volatile register,
including stack pointer. But it's not uncommon that assembler programmer
plans to utilize every single register and sometimes even have variable
stack frame. Is there anything one can do with bare building blocks? I.e.
besides manually composing fully-fledged UNWIND_INFO
structure, which would surely be considered error-prone? Yes, there is.
Recall that exception handler is called first, before stack layout is
analyzed. As it turned out, it's perfectly possible to manipulate current
callee's context in custom handler in manner that permits further stack
unwinding. General idea is that handler would not actually "handle" the
exception, but instead restore callee's context, as it was at its entry
point and thus mimic leaf function. In other words, handler would simply
undertake part of unwinding procedure. Consider following example:
function:
mov rax,rsp ; copy rsp to volatile register
push r15 ; save non-volatile registers
push rbx
push rbp
mov r11,rsp ; prepare variable stack frame
sub r11,rcx
and r11,-64
mov QWORD[r11],rax ; check for exceptions
mov rsp,r11 ; allocate stack frame
mov QWORD[rsp],rax ; save original rsp value
magic_point:
...
mov r11,QWORD[rsp] ; pull original rsp value
mov rbp,QWORD[r11-24]
mov rbx,QWORD[r11-16]
mov r15,QWORD[r11-8]
mov rsp,r11 ; destroy frame
ret
The keyword is that up to magic_point original
rsp value remains in chosen volatile register and no
non-volatile register, except for rsp, is modified. While past
magic_point rsp remains constant till the very
end of the function. In this case custom language-specific
exception handler would look like this:
EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
CONTEXT *context,DISPATCHER_CONTEXT *disp)
{ ULONG64 *rsp;
if (context->Rip<(ULONG64)magic_point)
rsp = (ULONG64 *)context->Rax;
else
{ rsp = ((ULONG64 **)context->Rsp)[0];
context->Rbp = rsp[-3];
context->Rbx = rsp[-2];
context->R15 = rsp[-1];
}
context->Rsp = (ULONG64)rsp;
memcpy (disp->ContextRecord,context,sizeof(CONTEXT));
RtlVirtualUnwind(UNW_FLAG_NHANDLER,disp->ImageBase,
dips->ControlPc,disp->FunctionEntry,disp->ContextRecord,
&disp->HandlerData,&disp->EstablisherFrame,NULL);
return ExceptionContinueSearch;
}
As custom handler mimics leaf function, corresponding
UNWIND_INFO structure does not have to contain any information
about stack frame and its layout.
coff: Common Object File FormatThe coff output type produces COFF object
files suitable for linking with the DJGPP linker.
coff provides a default output file-name extension of
.o.
The coff format supports the same extensions to the
SECTION directive as win32 does, except that the
align qualifier and the info section type are not
supported.
macho32 and macho64: Mach Object File FormatThe macho32 and macho64 output formts produces
Mach-O object files suitable for linking with the MacOS X linker.
macho is a synonym for macho32.
macho provides a default output file-name extension of
.o.
macho extensions to the SECTION Directive The macho output format specifies section names in the
format "segment,section". No spaces are
allowed around the comma. The following flags can also be specified:
data – this section contains initialized data items
code – this section contains code exclusively
mixed – this section contains both code and data
bss – this section is uninitialized and filled with
zero
zerofill – same as bss
no_dead_strip – inhibit dead code stripping for this
section
live_support – set the live support flag for this
section
strip_static_syms – strip static symbols for this
section
debug – this section contains debugging information
align=alignment – specify section alignment
The default is data, unless the section name is
__text or __bss in which case the default is
text or bss, respectively.
For compatibility with other Unix platforms, the following standard names are also supported:
.text = __TEXT,__text text .rodata = __DATA,__const data .data = __DATA,__data data .bss = __DATA,__bss bss
If the .rodata section contains no relocations, it is
instead put into the __TEXT,__const section unless this
section has already been specified explicitly. However, it is probably
better to specify __TEXT,__const and
__DATA,__const explicitly as appropriate.
macho special symbols and WRTMach-O defines the following special symbols that can be used on the
right-hand side of the WRT operator:
..tlvp is used to specify access to thread-local storage.
..gotpcrel is used to specify references to the Global
Offset Table. The GOT is supported in the macho64 format only.
macho specific directive subsections_via_symbolsThe directive subsections_via_symbols sets the
MH_SUBSECTIONS_VIA_SYMBOLS flag in the Mach-O header, that
effectively separates a block (or a subsection) based on a symbol. It is
often used for eliminating dead codes by a linker.
This directive takes no arguments.
This is a macro implemented as a %pragma. It can also be
specified in its %pragma form, in which case it will not
affect non-Mach-O builds of the same source code:
%pragma macho subsections_via_symbols
macho specific directive no_dead_stripThe directive no_dead_strip sets the Mach-O
SH_NO_DEAD_STRIP section flag on the section containing a a
specific symbol. This directive takes a list of symbols as its arguments.
This is a macro implemented as a %pragma. It can also be
specified in its %pragma form, in which case it will not
affect non-Mach-O builds of the same source code:
%pragma macho no_dead_strip symbol...
macho specific extensions to the GLOBAL Directive: private_externThe directive extension to GLOBAL marks the symbol with
limited global scope. For example, you can specify the global symbol with
this extension:
global foo:private_extern
foo:
; codes
Using with static linker will clear the private extern attribute. But
linker option like -keep_private_externs can avoid it.
elf32, elf64, elfx32: Executable and Linkable Format Object FilesThe elf32, elf64 and elfx32
output formats generate ELF32 and ELF64 (Executable and
Linkable Format) object files, as used by Linux as well as Unix System V,
including Solaris x86, UnixWare and SCO Unix. ELF provides a default output
file-name extension of .o. elf is a synonym for
elf32.
The elfx32 format is used for the x32 ABI, which is a
32-bit ABI with the CPU in 64-bit mode.
osabiThe ELF header specifies the application binary interface for the target
operating system (OSABI). This field can be set by using the
osabi directive with the numeric value (0-255) of the target
system. If this directive is not used, the default value will be "UNIX
System V ABI" (0) which will work on most systems which support ELF.
SECTION Directive Like the obj format, elf allows you to specify
additional information on the SECTION directive line, to
control the type and properties of sections you declare. Section types and
properties are generated automatically by NASM for the standard section
names, but may still be overridden by these qualifiers.
The available qualifiers are:
alloc defines the section to be one which is loaded into
memory when the program is run. noalloc defines it to be one
which is not, such as an informational or comment section.
exec defines the section to be one which should have
execute permission when the program is run. noexec defines it
as one which should not.
write defines the section to be one which should be
writable when the program is run. nowrite defines it as one
which should not.
progbits defines the section to be one with explicit
contents stored in the object file: an ordinary code or data section, for
example.
nobits defines the section to be one with no explicit
contents given, such as a BSS section.
note indicates that this section contains ELF notes. The
content of ELF notes are specified using normal assembly instructions; it
is up to the programmer to ensure these are valid ELF notes.
preinit_array indicates that this section contains function
addresses to be called before any other initialization has happened.
init_array indicates that this section contains function
addresses to be called during initialization.
fini_array indicates that this section contains function
pointers to be called during termination.
align=, used with a trailing number as in obj,
gives the alignment requirements of the section.
byte, word, dword,
qword, tword, oword,
yword, or zword with an optional
*multiplier specify the fundamental data item size for a
section which contains either fixed-sized data structures or strings; it
also sets a default alignment. This is generally used with the
strings and merge attributes (see below.) For
example byte*4 defines a unit size of 4 bytes, with a default
alignment of 1; dword also defines a unit size of 4 bytes, but
with a default alignment of 4. The align= attribute, if
specified, overrides this default alignment.
pointer is equivalent to dword for
elf32 or elfx32, and qword for
elf64.
strings indicate that this section contains exclusively
null-terminated strings. By default these are assumed to be byte strings,
but a size specifier can be used to override that.
merge indicates that duplicate data elements in this
section should be merged with data elements from other object files. Data
elements can be either fixed-sized objects or null-terminatedstrings (with
the strings attribute.) A size specifier is required unless
strings is specified, in which case the size defaults to
byte.
tls defines the section to be one which contains thread
local variables.
The defaults assumed by NASM if you do not specify the above qualifiers are:
section .text progbits alloc exec nowrite align=16 section .rodata progbits alloc noexec nowrite align=4 section .lrodata progbits alloc noexec nowrite align=4 section .data progbits alloc noexec write align=4 section .ldata progbits alloc noexec write align=4 section .bss nobits alloc noexec write align=4 section .lbss nobits alloc noexec write align=4 section .tdata progbits alloc noexec write align=4 tls section .tbss nobits alloc noexec write align=4 tls section .comment progbits noalloc noexec nowrite align=1 section .preinit_array preinit_array alloc noexec nowrite pointer section .init_array init_array alloc noexec nowrite pointer section .fini_array fini_array alloc noexec nowrite pointer section .note note noalloc noexec nowrite align=4 section other progbits alloc noexec nowrite align=1
(Any section name other than those in the above table is treated by
default like other in the above table. Please note that
section names are case sensitive.)
WRTSince ELF does not support segment-base references, the
WRT operator is not used for its normal purpose; therefore
NASM's elf output format makes use of WRT for a
different purpose, namely the PIC-specific relocation types.
elf defines five special symbols which you can use as the
right-hand side of the WRT operator to obtain PIC relocation
types. They are ..gotpc, ..gotoff,
..got, ..plt and ..sym. Their
functions are summarized here:
Referring to the symbol marking the global offset table base using
wrt ..gotpc will end up giving the distance from the beginning
of the current section to the global offset table.
(_GLOBAL_OFFSET_TABLE_ is the standard symbol name used to
refer to the GOT.) So you would then need to add $$ to the
result to get the real address of the GOT.
Referring to a location in one of your own sections using
wrt ..gotoff will give the distance from the beginning of the
GOT to the specified location, so that adding on the address of the GOT
would give the real address of the location you wanted.
Referring to an external or global symbol using wrt ..got
causes the linker to build an entry in the GOT containing the
address of the symbol, and the reference gives the distance from the
beginning of the GOT to the entry; so you can add on the address of the
GOT, load from the resulting address, and end up with the address of the
symbol.
Referring to a procedure name using wrt ..plt causes the
linker to build a procedure linkage table entry for the symbol, and the
reference gives the address of the PLT entry. You can only use this in
contexts which would generate a PC-relative relocation normally (i.e. as
the destination for CALL or JMP), since ELF
contains no relocation type to refer to PLT entries absolutely.
Referring to a symbol name using wrt ..sym causes NASM to
write an ordinary relocation, but instead of making the relocation relative
to the start of the section and then adding on the offset to the symbol, it
will write a relocation record aimed directly at the symbol in question.
The distinction is a necessary one due to a peculiarity of the dynamic
linker.
A fuller explanation of how to use these relocation types to write shared libraries entirely in NASM is given in section 10.2.
elf Special Symbols and WRTIn ELF32 mode, referring to an external or global symbol using
wrt ..tlsie causes the linker to build an entry in
the GOT containing the offset of the symbol within the TLS block, so you
can access the value of the symbol with code such as:
mov eax,[tid wrt ..tlsie]
mov [gs:eax],ebx
In ELF64 or ELFx32 mode, referring to an external or global symbol using
wrt ..gottpoff causes the linker to build an entry
in the GOT containing the offset of the symbol within the TLS
block, so you can access the value of the symbol with code such as:
mov rax,[rel tid wrt ..gottpoff]
mov rcx,[fs:rax]
elf Extensions to the GLOBAL DirectiveELF object files can contain more information about a
global symbol than just its address: they can contain the size of the
symbol and its type as well. These are not merely debugger conveniences,
but are actually necessary when the program being written is a shared
library. NASM therefore supports some extensions to the GLOBAL
directive, allowing you to specify these features.
You can specify whether a global variable is a function or a data object
by suffixing the name with a colon and the word function or
data. (object is a synonym for
data.) For example:
global hashlookup:function, hashtable:data
exports the global symbol hashlookup as a function and
hashtable as a data object.
Optionally, you can control the ELF visibility of the symbol. Just add
one of the visibility keywords: default,
internal, hidden, or protected. The
default is default of course. For example, to make
hashlookup hidden:
global hashlookup:function hidden
Since version 2.15, it is possible to specify symbols binding. The
keywords are: weak to generate weak symbol or
strong. The default is strong.
You can also specify the size of the data associated with the symbol, as a numeric expression (which may involve labels, and even forward references) after the type specifier. Like this:
global hashtable:data (hashtable.end - hashtable)
hashtable:
db this,that,theother ; some data here
.end:
This makes NASM automatically calculate the length of the table and
place that information into the ELF symbol table.
Declaring the type and size of global symbols is necessary when writing shared library code. For more information, see section 10.2.4.
elf Extensions to the EXTERN DirectiveSince version 2.15 it is possible to specify keyword weak
to generate weak external reference. Example:
extern weak_ref:weak
elf Extensions to the COMMON Directive ELF also allows you to specify alignment requirements on
common variables. This is done by putting a number (which must be a power
of two) after the name and size of the common variable, separated (as
usual) by a colon. For example, an array of doublewords would benefit from
4-byte alignment:
common dwordarray 128:4
This declares the total size of the array to be 128 bytes, and requires that it be aligned on a 4-byte boundary.
Older versions of the ELF32 specification did not provide
relocations for 8- and 16-bit values. It is now part of the formal
specification, and any new enough linker should support them.
ELF has currently no support for segmented programming.
ELF provides debug information in STABS and
DWARF formats. Line number information is generated for all
executable sections, but please note that only the ".text" section is
executable by default.
aout: Linux a.out Object FilesThe aout format generates a.out object files,
in the form used by early Linux systems (current Linux systems use ELF, see
section 8.9.) These differ from other
a.out object files in that the magic number in the first four
bytes of the file is different; also, some implementations of
a.out, for example NetBSD's, support position-independent
code, which Linux's implementation does not.
a.out provides a default output file-name extension of
.o.
a.out is a very simple object format. It supports no
special directives, no special symbols, no use of SEG or
WRT, and no extensions to any standard directives. It supports
only the three standard section names .text,
.data and .bss.
aoutb: NetBSD/FreeBSD/OpenBSD a.out Object FilesThe aoutb format generates a.out object files,
in the form used by the various free BSD Unix clones,
NetBSD, FreeBSD and OpenBSD. For
simple object files, this object format is exactly the same as
aout except for the magic number in the first four bytes of
the file. However, the aoutb format supports
position-independent code in the same way as the elf format,
so you can use it to write BSD shared libraries.
aoutb provides a default output file-name extension of
.o.
aoutb supports no special directives, no special symbols,
and only the three standard section names .text,
.data and .bss. However, it also supports the
same use of WRT as elf does, to provide
position-independent code relocation types. See
section 8.9.3 for full documentation of this
feature.
aoutb also supports the same extensions to the
GLOBAL directive as elf does: see
section 8.9.5 for documentation of this.
as86: Minix/Linux as86 Object FilesThe Minix/Linux 16-bit assembler as86 has its own
non-standard object file format. Although its companion linker
ld86 produces something close to ordinary a.out
binaries as output, the object file format used to communicate between
as86 and ld86 is not itself a.out.
NASM supports this format, just in case it is useful, as
as86. as86 provides a default output file-name
extension of .o.
as86 is a very simple object format (from the NASM user's
point of view). It supports no special directives, no use of
SEG or WRT, and no extensions to any standard
directives. It supports only the three standard section names
.text, .data and .bss. The only
special symbol supported is ..start.
dbg: Debugging FormatThe dbg format does not output an object file as such;
instead, it outputs a text file which contains a complete list of all the
transactions between the main body of NASM and the output-format back end
module. It is primarily intended to aid people who want to write their own
output drivers, so that they can get a clearer idea of the various requests
the main program makes of the output driver, and in what order they happen.
For simple files, one can easily use the dbg format like
this:
nasm -f dbg filename.asm
which will generate a diagnostic file called filename.dbg.
However, this will not work well on files which were designed for a
different object format, because each object format defines its own macros
(usually user-level forms of directives), and those macros will not be
defined in the dbg format. Therefore it can be useful to run
NASM twice, in order to do the preprocessing with the native object format
selected:
nasm -e -f elf32 -o elfprog.i elfprog.asm nasm -a -f dbg elfprog.i
This preprocesses elfprog.asm into elfprog.i,
keeping the elf32 object format selected in order to make sure
ELF special directives are converted into primitive form correctly. Then
the preprocessed source is fed through the dbg format to
generate the final diagnostic output.
This workaround will still typically not work for programs intended for
obj format, because the obj SEGMENT
and GROUP directives have side effects of defining the segment
and group names as symbols; dbg will not do this, so the
program will not assemble. You will have to work around that by defining
the symbols yourself (using EXTERN, for example) if you really
need to get a dbg trace of an obj–specific
source file.
dbg accepts any section name and any directives at all, and
logs them all to its output file.
dbg accepts and logs any %pragma, but the
specific %pragma:
%pragma dbg maxdump <size>
where <size> is either a number or
unlimited, can be used to control the maximum size for dumping
the full contents of a rawdata output object.