Chapter 5. NASM Assembler Directives

Table of Contents

5.1. Specifying Target Processor Mode
5.1.1. BITS
5.1.2. USE16, USE32, and USE64
5.2. DEFAULT: Change the assembler defaults
5.3. Changing and Defining Sections
5.3.2. Standardized Section Names
5.3.3. The __SECT__ Macro
5.4. ABSOLUTE: Defining Absolute Labels
5.5. EXTERN: Importing Symbols
5.6. GLOBAL: Exporting Symbols
5.7. COMMON: Defining Common Data Areas
5.8. CPU: Defining CPU Dependencies

NASM, though it attempts to avoid the bureaucracy of assemblers like MASM and TASM, is nevertheless forced to support a few directives. These are described in this chapter.

NASM’s directives come in two types: user-level directives and primitive directives. Typically, each directive has a user-level form and a primitive form. In almost all cases, we recommend that users use the user-level forms of the directives, which are implemented as macros which call the primitive forms.

Primitive directives are enclosed in square brackets; user-level directives are not.

In addition to the universal directives described in this chapter, each object file format can optionally supply extra directives in order to control particular features of that file format. These format-specific directives are documented along with the formats that implement them, in Part IV.

5.1. Specifying Target Processor Mode

5.1.1. BITS

The BITS directive specifies whether Yasm should generate code designed to run on a processor operating in 16-bit mode, 32-bit mode, or 64-bit mode. The syntax is BITS 16, BITS 32, or BITS 64.

In most cases, you should not need to use BITS explicitly. The coff, elf32, macho32, and win32 object formats, which are designed for use in 32-bit operating systems, all cause Yasm to select 32-bit mode by default. The elf64, macho64, and win64 object formats, which are designed for use in 64-bit operating systems, both cause Yasm to select 64-bit mode by default. The xdf object format allows you to specify each segment you define as USE16, USE32, or USE64, and Yasm will set its operating mode accordingly, so the use of the BITS directive is once again unnecessary.

The most likely reason for using the BITS directive is to write 32-bit or 64-bit code in a flat binary file; this is because the bin object format defaults to 16-bit mode in anticipation of it being used most frequently to write DOS .COM programs, DOS .SYS device drivers and boot loader software.

You do not need to specify BITS 32 merely in order to use 32-bit instructions in a 16-bit DOS program; if you do, the assembler will generate incorrect code because it will be writing code targeted at a 32-bit platform, to be run on a 16-bit one. However, it is necessary to specify BITS 64 to use 64-bit instructions and registers; this is done to allow use of those instruction and register names in 32-bit or 16-bit programs, although such use will generate a warning.

When Yasm is in BITS 16 mode, instructions which use 32-bit data are prefixed with an 0x66 byte, and those referring to 32-bit addresses have an 0x67 prefix. In BITS 32 mode, the reverse is true: 32-bit instructions require no prefixes, whereas instructions using 16-bit data need an 0x66 and those working in 16-bit addresses need an 0x67.

When Yasm is in BITS 64 mode, 32-bit instructions usually require no prefixes, and most uses of 64-bit registers or data size requires a REX prefix. Yasm automatically inserts REX prefixes where necessary. There are also 8 more general and SSE registers, and 16-bit addressing is no longer supported. The default address size is 64 bits; 32-bit addressing can be selected with the 0x67 prefix. The default operand size is still 32 bits, however, and the 0x66 prefix selects 16-bit operand size. The REX prefix is used both to select 64-bit operand size, and to access the new registers. A few instructions have a default 64-bit operand size.

When the REX prefix is used, the processor does not know how to address the AH, BH, CH or DH (high 8-bit legacy) registers. Instead, it is possible to access the the low 8-bits of the SP, BP SI, and DI registers as SPL, BPL, SIL, and DIL, respectively; but only when the REX prefix is used.

The BITS directive has an exactly equivalent primitive form, [BITS 16], [BITS 32], and [BITS 64]. The user-level form is a macro which has no function other than to call the primitive form.

5.1.2. USE16, USE32, and USE64

The USE16, USE32, and USE64 directives can be used in place of BITS 16, BITS 32, and BITS 64 respectively for compatibility with other assemblers.