The Netwide Assembler: NASM

Next Chapter | Previous Chapter | Contents | Index

Chapter 7: Output Formats

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.

7.1 bin: Flat-Form Binary Output

The 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 7.1.3.

Using the bin format puts NASM by default into 16-bit mode (see section 6.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.

7.1.1 ORG: Binary File Program Origin

The bin format provides an additional directive to the list given in chapter 6: 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 

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 12.1.3 for further comments.

7.1.2 bin Extensions to the SECTION Directive

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.

7.1.3 Multisection Support for the bin Format

The bin format allows the use of multiple sections, of arbitrary names, besides the "known" .text, .data, and .bss names.

7.1.4 Map Files

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]. No "user form" exists, the square brackets must be used.

7.2 ith: Intel Hex Output

The ith file format produces Intel hex-format 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.

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.

7.3 srec: Motorola S-Records Output

The 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.

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.

7.4 obj: Microsoft OMF Object Files

The 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 

        mov     ax,data         ; get segment address of data 
        mov     ds,ax           ; and move it into DS 
        inc     word [dvar]     ; now this reference will work 

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

7.4.1 obj Extensions to the SEGMENT Directive

The 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:

NASM's default segment attributes are PUBLIC, ALIGN=1, no class, no overlay, and USE16.

7.4.2 GROUP: Defining Groups of Segments

The 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.

7.4.3 UPPERCASE: Disabling Case Sensitivity in Output

Although 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.

7.4.4 IMPORT: Importing DLL Symbols

The 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

7.4.5 EXPORT: Exporting DLL Symbols

The 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:

For example:

    export  myfunc 
    export  myfunc TheRealMoreFormalLookingFunctionName 
    export  myfunc myfunc 1234  ; export by ordinal 
    export  myfunc myfunc resident parm=23 nodata

7.4.6 ..start: Defining the Program Entry Point

OMF 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.

7.4.7 obj Extensions to the EXTERN Directive

If 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 7.4.8.

7.4.8 obj Extensions to the COMMON Directive

The 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 7.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

7.5 win32: Microsoft Win32 Object Files

The 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 7.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.

7.5.1 win32 Extensions to the SECTION Directive

Like 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:

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

Any other section name is treated by default like .text.

7.5.2 win32: Safe Structured Exception Handling

Among 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:

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" 
        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 
global  _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 
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.

7.6 win64: Microsoft Win64 Object Files

The win64 output format generates Microsoft Win64 object files, which is nearly 100% identical to the win32 object format (section 7.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 7.5), in NASM, with regard to this exception.

7.6.1 win64: Writing Position-Independent Code

While 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 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,QWORD[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,DWORD[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

7.6.2 win64: Structured Exception Handling

Structured 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 
        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 
global  main 
        xor     rax,rax 
        mov     rax,QWORD[rax]  ; cause exception 
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:

        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 
        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 

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:

        CONTEXT *context,DISPATCHER_CONTEXT *disp) 
{   ULONG64 *rsp; 
    if (context->Rip<(ULONG64)magic_point) 
        rsp = (ULONG64 *)context->Rax; 
    {   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)); 
    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.

7.7 coff: Common Object File Format

The 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.

7.8 macho32 and macho64: Mach Object File Format

The 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.

7.9 elf32 and elf64: Executable and Linkable Format Object Files

The elf32 and elf64 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.

7.9.1 ELF specific directive osabi

The 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.

7.9.2 elf Extensions to the 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:

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 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.)

7.9.3 Position-Independent Code: elf Special Symbols and WRT

The ELF specification contains enough features to allow position-independent code (PIC) to be written, which makes ELF shared libraries very flexible. However, it also means NASM has to be able to generate a variety of ELF specific relocation types in ELF object files, if it is to be an assembler which can write PIC.

Since 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,, ..plt and ..sym. Their functions are summarized here:

A fuller explanation of how to use these relocation types to write shared libraries entirely in NASM is given in section 9.2.

7.9.4 Thread Local Storage: elf Special Symbols and WRT

       mov  eax,[tid wrt ..tlsie] 
       mov  [gs:eax],ebx

       mov   rax,[rel tid wrt ..gottpoff] 
       mov   rcx,[fs:rax]

7.9.5 elf Extensions to the GLOBAL Directive

ELF 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

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) 

        db this,that,theother  ; some data here 

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 9.2.4.

7.9.6 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.

7.9.7 16-bit code and ELF

The ELF32 specification doesn't provide relocations for 8- and 16-bit values, but the GNU ld linker adds these as an extension. NASM can generate GNU-compatible relocations, to allow 16-bit code to be linked as ELF using GNU ld. If NASM is used with the -w+gnu-elf-extensions option, a warning is issued when one of these relocations is generated.

7.9.8 Debug formats and ELF

ELF32 and ELF64 provide 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.

7.10 aout: Linux a.out Object Files

The aout format generates a.out object files, in the form used by early Linux systems (current Linux systems use ELF, see section 7.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.

7.11 aoutb: NetBSD/FreeBSD/OpenBSD a.out Object Files

The 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 7.9.3 for full documentation of this feature.

aoutb also supports the same extensions to the GLOBAL directive as elf does: see section 7.9.5 for documentation of this.

7.12 as86: Minix/Linux as86 Object Files

The 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.

7.13 rdf: Relocatable Dynamic Object File Format

The rdf output format produces RDOFF object files. RDOFF (Relocatable Dynamic Object File Format) is a home-grown object-file format, designed alongside NASM itself and reflecting in its file format the internal structure of the assembler.

RDOFF is not used by any well-known operating systems. Those writing their own systems, however, may well wish to use RDOFF as their object format, on the grounds that it is designed primarily for simplicity and contains very little file-header bureaucracy.

The Unix NASM archive, and the DOS archive which includes sources, both contain an rdoff subdirectory holding a set of RDOFF utilities: an RDF linker, an RDF static-library manager, an RDF file dump utility, and a program which will load and execute an RDF executable under Linux.

rdf supports only the standard section names .text, .data and .bss.

7.13.1 Requiring a Library: The LIBRARY Directive

RDOFF contains a mechanism for an object file to demand a given library to be linked to the module, either at load time or run time. This is done by the LIBRARY directive, which takes one argument which is the name of the module:

    library  mylib.rdl

7.13.2 Specifying a Module Name: The MODULE Directive

Special RDOFF header record is used to store the name of the module. It can be used, for example, by run-time loader to perform dynamic linking. MODULE directive takes one argument which is the name of current module:

    module  mymodname

Note that when you statically link modules and tell linker to strip the symbols from output file, all module names will be stripped too. To avoid it, you should start module names with $, like:

    module  $kernel.core

7.13.3 rdf Extensions to the GLOBAL Directive

RDOFF global symbols can contain additional information needed by the static linker. You can mark a global symbol as exported, thus telling the linker do not strip it from target executable or library file. Like in ELF, you can also specify whether an exported symbol is a procedure (function) or data object.

Suffixing the name with a colon and the word export you make the symbol exported:

    global  sys_open:export

To specify that exported symbol is a procedure (function), you add the word proc or function after declaration:

    global  sys_open:export proc

Similarly, to specify exported data object, add the word data or object to the directive:

    global  kernel_ticks:export data

7.13.4 rdf Extensions to the EXTERN Directive

By default the EXTERN directive in RDOFF declares a "pure external" symbol (i.e. the static linker will complain if such a symbol is not resolved). To declare an "imported" symbol, which must be resolved later during a dynamic linking phase, RDOFF offers an additional import modifier. As in GLOBAL, you can also specify whether an imported symbol is a procedure (function) or data object. For example:

    library $libc 
    extern  _open:import 
    extern  _printf:import proc 
    extern  _errno:import data

Here the directive LIBRARY is also included, which gives the dynamic linker a hint as to where to find requested symbols.

7.14 dbg: Debugging Format

The dbg output format is not built into NASM in the default configuration. If you are building your own NASM executable from the sources, you can define OF_DBG in output/outform.h or on the compiler command line, and obtain the dbg output format.

The 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 rdf -o rdfprog.i rdfprog.asm 
nasm -a -f dbg rdfprog.i

This preprocesses rdfprog.asm into rdfprog.i, keeping the rdf object format selected in order to make sure RDF 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.

Next Chapter | Previous Chapter | Contents | Index