Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Secure Programming for Li...6507 
 Linux Kernel 2.6...5279 
 Trees...1119 
 Максвелл 3...1051 
 William Gropp...990 
 Go Web ...963 
 Ethreal 3...930 
 Ethreal 4...918 
 Gary V.Vaughan-> Libtool...914 
 Ext4 FS...905 
 Clickhouse...901 
 Rodriguez 6...900 
 Ethreal 1...897 
 Steve Pate 1...886 
 C++ Patterns 3...864 
 Assembler...854 
 Ulrich Drepper...844 
 DevFS...788 
 MySQL & PosgreSQL...774 
 Стивенс 9...758 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

NASM info

3.1. Layout of a NASM Source Line Как в других ассемблерах,каждая строка NASM-исходника состоит из 4 основных частей :
 
      label:    instruction operands        ; comment


As usual, most of these fields are optional; the presence or absence of any combination of a label, an instruction and a comment is allowed. Of course, the operand field is either required or forbidden by the presence and nature of the instruction field.

NASM uses backslash (\) as the line continuation character; if a line ends with backslash, the next line is considered to be a part of the backslash- ended line.

NASM places no restrictions on white space within a line: labels may have white space before them, or instructions may have no space before them, or anything. The colon after a label is also optional. (Note that this means that if you intend to code `lodsb' alone on a line, and type `lodab' by accident, then that's still a valid source line which does nothing but define a label. Running NASM with the command-line option `-w+orphan-labels' will cause it to warn you if you define a label alone on a line without a trailing colon.)

Valid characters in labels are letters, numbers, `_', `$', `#', `@', `~', `.', and `?'. The only characters which may be used as the _first_ character of an identifier are letters, `.' (with special meaning: see *Note Section 3.9::), `_' and `?'. An identifier may also be prefixed with a `$' to indicate that it is intended to be read as an identifier and not a reserved word; thus, if some other module you are linking with defines a symbol called `eax', you can refer to `$eax' in NASM code to distinguish the symbol from the register.

The instruction field may contain any machine instruction: Pentium and P6 instructions, FPU instructions, MMX instructions and even undocumented instructions are all supported. The instruction may be prefixed by `LOCK', `REP', `REPE'/`REPZ' or `REPNE'/`REPNZ', in the usual way. Explicit address-size and operand-size prefixes `A16', `A32', `O16' and `O32' are provided - one example of their use is given in *Note Chapter 9::. You can also use the name of a segment register as an instruction prefix: coding `es mov [bx],ax' is equivalent to coding `mov [es:bx],ax'. We recommend the latter syntax, since it is consistent with other syntactic features of the language, but for instructions such as `LODSB', which has no operands and yet can require a segment override, there is no clean syntactic way to proceed apart from `es lodsb'.

An instruction is not required to use a prefix: prefixes such as `CS', `A32', `LOCK' or `REPE' can appear on a line by themselves, and NASM will just generate the prefix bytes.

In addition to actual machine instructions, NASM also supports a number of pseudo-instructions, described in *Note Section 3.2::. Instruction operands may take a number of forms: they can be registers, described simply by the register name (e.g. `ax', `bp', `ebx', `cr0': NASM does not use the `gas'-style syntax in which register names must be prefixed by a `%' sign), or they can be effective addresses (see *Note Section 3.3::), constants (*Note Section 3.4::) or expressions (*Note Section 3.5::).

For floating-point instructions, NASM accepts a wide range of syntaxes: you can use two-operand forms like MASM supports, or you can use NASM's native single-operand forms in most cases. Details of all forms of each supported instruction are given in *Note Appendix B::. For example, you can code:
                                                                                        
              fadd    st1             ; this sets st0 := st0 + st1
              fadd    st0,st1         ; so does this
                                                                                        
              fadd    st1,st0         ; this sets st1 := st1 + st0
              fadd    to st1          ; so does this
Almost any floating-point instruction that references memory must use one of the prefixes `DWORD', `QWORD' or `TWORD' to indicate what size of memory operand it refers to.

3.2. Pseudo-Instructions

Pseudo-instructions are things which, though not real x86 machine instructions, are used in the instruction field anyway because that's the most convenient place to put them. The current pseudo-instructions are `DB', `DW', `DD', `DQ' and `DT', their uninitialised counterparts `RESB', `RESW', `RESD', `RESQ' and `REST', the `INCBIN' command, the `EQU' command, and the `TIMES' prefix.

3.2.1. `DB' and friends: Declaring Initialised Data ---------------------------------------------------

`DB', `DW', `DD', `DQ' and `DT' are used, much as in MASM, to declare initialised data in the output file. They can be invoked in a wide range of ways:
                                                                                        
            db    0x55                ; just the byte 0x55
            db    0x55,0x56,0x57      ; three bytes in succession
            db    'a',0x55            ; character constants are OK
            db    'hello',13,10,'$'   ; so are string constants
            dw    0x1234              ; 0x34 0x12
            dw    'a'                 ; 0x61 0x00 (it's just a number)
            dw    'ab'                ; 0x61 0x62 (character constant)
            dw    'abc'               ; 0x61 0x62 0x63 0x00 (string)
            dd    0x12345678          ; 0x78 0x56 0x34 0x12
            dd    1.234567e20         ; floating-point constant
            dq    1.234567e20         ; double-precision float
            dt    1.234567e20         ; extended-precision float
`DQ' and `DT' do not accept numeric constants or string constants as operands.

3.2.2. `RESB' and friends: Declaring Uninitialised Data

`RESB', `RESW', `RESD', `RESQ' and `REST' are designed to be used in the BSS section of a module: they declare _uninitialised_ storage space. Each takes a single operand, which is the number of bytes, words, doublewords or whatever to reserve. As stated in *Note Section 2.2.7::, NASM does not support the MASM/TASM syntax of reserving uninitialised space by writing `DW ?' or similar things: this is what it does instead. The operand to a `RESB'-type pseudo- instruction is a _critical expression_: see *Note Section 3.8::.

For example:
                                                                                        
      buffer:         resb    64              ; reserve 64 bytes
      wordvar:        resw    1               ; reserve a word
      realarray       resq    10              ; array of ten reals


3.2.3. `INCBIN': Including External Binary Files

`INCBIN' is borrowed from the old Amiga assembler DevPac: it includes a binary file verbatim into the output file. This can be handy for (for example) including graphics and sound data directly into a game executable file. It can be called in one of these three ways:
                                                                                        
          incbin  "file.dat"             ; include the whole file
          incbin  "file.dat",1024        ; skip the first 1024 bytes
          incbin  "file.dat",1024,512    ; skip the first 1024, and
                                         ; actually include at most 512


3.2.4. `EQU': Defining Constants

`EQU' defines a symbol to a given constant value: when `EQU' is used, the source line must contain a label. The action of `EQU' is to define the given label name to the value of its (only) operand. This definition is absolute, and cannot change later. So, for example,
                                                                                        
      message         db      'hello, world'
      msglen          equ     $-message
defines `msglen' to be the constant 12. `msglen' may not then be redefined later. This is not a preprocessor definition either: the value of `msglen' is evaluated _once_, using the value of `$' (see *Note Section 3.5:: for an explanation of `$') at the point of definition, rather than being evaluated wherever it is referenced and using the value of `$' at the point of reference. Note that the operand to an `EQU' is also a critical expression (*Note Section 3.8::).

3.2.5. `TIMES': Repeating Instructions or Data

The `TIMES' prefix causes the instruction to be assembled multiple times. This is partly present as NASM's equivalent of the `DUP' syntax supported by MASM-compatible assemblers, in that you can code

zerobuf: times 64 db 0

or similar things; but `TIMES' is more versatile than that. The argument to `TIMES' is not just a numeric constant, but a numeric _expression_, so you can do things like
                                                                                       
      buffer: db      'hello, world'
              times 64-$+buffer db ' '
which will store exactly enough spaces to make the total length of `buffer' up to 64. Finally, `TIMES' can be applied to ordinary instructions, so you can code trivial unrolled loops in it:

times 100 movsb

Note that there is no effective difference between `times 100 resb 1' and `resb 100', except that the latter will be assembled about 100 times faster due to the internal structure of the assembler.

The operand to `TIMES', like that of `EQU' and those of `RESB' and friends, is a critical expression (*Note Section 3.8::).

3.3. Effective Addresses

An effective address is any operand to an instruction which references memory. Effective addresses, in NASM, have a very simple syntax: they consist of an expression evaluating to the desired address, enclosed in square brackets. For example:
                                                                                       
      wordvar dw      123
              mov     ax,[wordvar]
              mov     ax,[wordvar+1]
              mov     ax,[es:wordvar+bx]
Anything not conforming to this simple system is not a valid memory reference in NASM, for example `es:wordvar[bx]'.

More complicated effective addresses, such as those involving more than one register, work in exactly the same way:
                                                                                       
              mov     eax,[ebx*2+ecx+offset]
              mov     ax,[bp+di+8]
NASM is capable of doing algebra on these effective addresses, so that things which don't necessarily _look_ legal are perfectly all right:
                                                                                        
          mov     eax,[ebx*5]             ; assembles as [ebx*4+ebx]
          mov     eax,[label1*2-label2]   ; ie [label1+(label1-label2)]
Some forms of effective address have more than one assembled form; in most such cases NASM will generate the smallest form it can. For example, there are distinct assembled forms for the 32-bit effective addresses `[eax*2+0]' and `[eax+eax]', and NASM will generally generate the latter on the grounds that the former requires four bytes to store a zero offset.

NASM has a hinting mechanism which will cause `[eax+ebx]' and `[ebx+eax]' to generate different opcodes; this is occasionally useful because `[esi+ebp]' and `[ebp+esi]' have different default segment registers.

However, you can force NASM to generate an effective address in a particular form by the use of the keywords `BYTE', `WORD', `DWORD' and `NOSPLIT'. If you need `[eax+3]' to be assembled using a double-word offset field instead of the one byte NASM will normally generate, you can code `[dword eax+3]'. Similarly, you can force NASM to use a byte offset for a small value which it hasn't seen on the first pass (see *Note Section 3.8:: for an example of such a code fragment) by using `[byte eax+offset]'. As special cases, `[byte eax]' will code `[eax+0]' with a byte offset of zero, and `[dword eax]' will code it with a double-word offset of zero. The normal form, `[eax]', will be coded with no offset field.

The form described in the previous paragraph is also useful if you are trying to access data in a 32-bit segment from within 16 bit code. For more information on this see the section on mixed-size addressing (*Note Section 9.2::). In particular, if you need to access data with a known offset that is larger than will fit in a 16-bit value, if you don't specify that it is a dword offset, nasm will cause the high word of the offset to be lost. Similarly, NASM will split `[eax*2]' into `[eax+eax]' because that allows the offset field to be absent and space to be saved; in fact, it will also split `[eax*2+offset]' into `[eax+eax+offset]'. You can combat this behaviour by the use of the `NOSPLIT' keyword: `[nosplit eax*2]' will force `[eax*2+0]' to be generated literally.

3.4. Constants

NASM understands four different types of constant: numeric, character, string and floating-point.

3.4.1. Numeric Constants

A numeric constant is simply a number. NASM allows you to specify numbers in a variety of number bases, in a variety of ways: you can suffix `H', `Q' or `O', and `B' for hex, octal and binary, or you can prefix `0x' for hex in the style of C, or you can prefix `$' for hex in the style of Borland Pascal. Note, though, that the `$' prefix does double duty as a prefix on identifiers (see *Note Section 3.1::), so a hex number prefixed with a `$' sign must have a digit after the `$' rather than a letter.

Some examples:
                                                                                        
              mov     ax,100          ; decimal
              mov     ax,0a2h         ; hex
              mov     ax,$0a2         ; hex again: the 0 is required
              mov     ax,0xa2         ; hex yet again
              mov     ax,777q         ; octal
              mov     ax,777o         ; octal again
              mov     ax,10010011b    ; binary
 
 3.4.2. Character Constants
 

A character constant consists of up to four characters enclosed in either single or double quotes. The type of quote makes no difference to NASM, except of course that surrounding the constant with single quotes allows double quotes to appear within it and vice versa.

A character constant with more than one character will be arranged with little-endian order in mind: if you code
                                                                                        
                mov eax,'abcd'
then the constant generated is not `0x61626364', but `0x64636261', so that if you were then to store the value into memory, it would read `abcd' rather than `dcba'. This is also the sense of character constants understood by the Pentium's `CPUID' instruction (see *Note Section B.4.34::).

3.4.3. String Constants

String constants are only acceptable to some pseudo-instructions, namely the `DB' family and `INCBIN'.

A string constant looks like a character constant, only longer. It is treated as a concatenation of maximum-size character constants for the conditions. So the following are equivalent:
                                                                                        
            db    'hello'               ; string constant
            db    'h','e','l','l','o'   ; equivalent character constants
                                                                                        
    And the following are also equivalent:
                                                                                        
            dd    'ninechars'           ; doubleword string constant
            dd    'nine','char','s'     ; becomes three doublewords
            db    'ninechars',0,0,0     ; and really looks like this
Note that when used as an operand to `db', a constant like `'ab'' is treated as a string constant despite being short enough to be a character constant, because otherwise `db 'ab'' would have the same effect as `db 'a'', which would be silly. Similarly, three-character or four-character constants are treated as strings when they are operands to `dw'.

3.4.4. Floating-Point Constants

Floating-point constants are acceptable only as arguments to `DD', `DQ' and `DT'. They are expressed in the traditional form: digits, then a period, then optionally more digits, then optionally an `E' followed by an exponent. The period is mandatory, so that NASM can distinguish between `dd 1', which declares an integer constant, and `dd 1.0' which declares a floating-point constant.

Some examples:
                                                                                        
            dd    1.2                     ; an easy one
            dq    1.e10                   ; 10,000,000,000
            dq    1.e+10                  ; synonymous with 1.e10
            dq    1.e-10                  ; 0.000 000 000 1
            dt    3.141592653589793238462 ; pi
NASM cannot do compile-time arithmetic on floating-point constants. This is because NASM is designed to be portable - although it always generates code to run on x86 processors, the assembler itself can run on any system with an ANSI C compiler. Therefore, the assembler cannot guarantee the presence of a floating-point unit capable of handling the Intel number formats, and so for NASM to be able to do floating arithmetic it would have to include its own complete set of floating-point routines, which would significantly increase the size of the assembler for very little benefit.

3.5. Expressions

Expressions in NASM are similar in syntax to those in C.

NASM does not guarantee the size of the integers used to evaluate expressions at compile time: since NASM can compile and run on 64-bit systems quite happily, don't assume that expressions are evaluated in 32- bit registers and so try to make deliberate use of integer overflow. It might not always work. The only thing NASM will guarantee is what's guaranteed by ANSI C: you always have _at least_ 32 bits to work in.

NASM supports two special tokens in expressions, allowing calculations to involve the current assembly position: the `$' and `$$' tokens. `$' evaluates to the assembly position at the beginning of the line containing the expression; so you can code an infinite loop using `JMP $'. `$$' evaluates to the beginning of the current section; so you can tell how far into the section you are by using `($-$$)'.

The arithmetic operators provided by NASM are listed here, in increasing order of precedence.

3.5.1. `|': Bitwise OR Operator

The `|' operator gives a bitwise OR, exactly as performed by the `OR' machine instruction. Bitwise OR is the lowest-priority arithmetic operator supported by NASM.

3.5.2. `^': Bitwise XOR Operator

`^' provides the bitwise XOR operation.

3.5.3. `&': Bitwise AND Operator

`&' provides the bitwise AND operation.

3.5.4. `<<' and `>>': Bit Shift Operators

`<<' gives a bit-shift to the left, just as it does in C. So `5<<3' evaluates to 5 times 8, or 40. `>>' gives a bit-shift to the right; in NASM, such a shift is _always_ unsigned, so that the bits shifted in from the left-hand end are filled with zero rather than a sign-extension of the previous highest bit.

3.5.6. `*', `/', `//', `%' and `%%': Multiplication and Division

`*' is the multiplication operator. `/' and `//' are both division operators: `/' is unsigned division and `//' is signed division. Similarly, `%' and `%%' provide unsigned and signed modulo operators respectively.

NASM, like ANSI C, provides no guarantees about the sensible operation of the signed modulo operator.

Since the `%' character is used extensively by the macro preprocessor, you should ensure that both the signed and unsigned modulo operators are followed by white space wherever they appear.

3.6. `SEG' and `WRT'

When writing large 16-bit programs, which must be split into multiple segments, it is often necessary to be able to refer to the segment part of the address of a symbol. NASM supports the `SEG' operator to perform this function.

The `SEG' operator returns the _preferred_ segment base of a symbol, defined as the segment base relative to which the offset of the symbol makes sense. So the code
                                                                                        
              mov     ax,seg symbol
              mov     es,ax
              mov     bx,symbol
will load `ES:BX' with a valid pointer to the symbol `symbol'.

Things can be more complex than this: since 16-bit segments and groups may overlap, you might occasionally want to refer to some symbol using a different segment base from the preferred one. NASM lets you do this, by the use of the `WRT' (With Reference To) keyword. So you can do things like
                                                                                        
              mov     ax,weird_seg        ; weird_seg is a segment base
              mov     es,ax
              mov     bx,symbol wrt weird_seg
to load `ES:BX' with a different, but functionally equivalent, pointer to the symbol `symbol'. NASM supports far (inter-segment) calls and jumps by means of the syntax `call segment:offset', where `segment' and `offset' both represent immediate values. So to call a far procedure, you could code either of
                                                                                        
              call    (seg procedure):procedure
              call    weird_seg:(procedure wrt weird_seg)
(The parentheses are included for clarity, to show the intended parsing of the above instructions. They are not necessary in practice.)

NASM supports the syntax `call far procedure' as a synonym for the first of the above usages. `JMP' works identically to `CALL' in these examples.

To declare a far pointer to a data item in a data segment, you must code

dw symbol, seg symbol

NASM supports no convenient synonym for this, though you can always invent one using the macro processor.

3.7. `STRICT': Inhibiting Optimization

When assembling with the optimizer set to level 2 or higher (see *Note Section 2.1.16::), NASM will use size specifiers (`BYTE', `WORD', `DWORD', `QWORD', or `TWORD'), but will give them the smallest possible size. The keyword `STRICT' can be used to inhibit optimization and force a particular operand to be emitted in the specified size. For example, with the optimizer on, and in `BITS 16' mode,

push dword 33

is encoded in three bytes `66 6A 21', whereas

push strict dword 33

is encoded in six bytes, with a full dword immediate operand `66 68 21 00 00 00'.

With the optimizer off, the same code (six bytes) is generated whether the `STRICT' keyword was used or not.

3.8. Critical Expressions

A limitation of NASM is that it is a two-pass assembler; unlike TASM and others, it will always do exactly two assembly passes. Therefore it is unable to cope with source files that are complex enough to require three or more passes.

The first pass is used to determine the size of all the assembled code and data, so that the second pass, when generating all the code, knows all the symbol addresses the code refers to. So one thing NASM can't handle is code whose size depends on the value of a symbol declared after the code in question. For example,
                                                                                       
              times (label-$) db 0
      label:  db      'Where am I?'
 
The argument to `TIMES' in this case could equally legally evaluate to anything at all; NASM will reject this example because it cannot tell the size of the `TIMES' line when it first sees it. It will just as firmly reject the slightly paradoxical code
                                                                                       
              times (label-$+1) db 0
      label:  db      'NOW where am I?'
 
in which _any_ value for the `TIMES' argument is by definition wrong! NASM rejects these examples by means of a concept called a _critical expression_, which is defined to be an expression whose value is required to be computable in the first pass, and which must therefore depend only on symbols defined before it. The argument to the `TIMES' prefix is a critical expression; for the same reason, the arguments to the `RESB' family of pseudo-instructions are also critical expressions.

Critical expressions can crop up in other contexts as well: consider the following code.
                                                                                       
                      mov     ax,symbol1
      symbol1         equ     symbol2
      symbol2:
 
On the first pass, NASM cannot determine the value of `symbol1', because `symbol1' is defined to be equal to `symbol2' which NASM hasn't seen yet. On the second pass, therefore, when it encounters the line `mov ax,symbol1', it is unable to generate the code for it because it still doesn't know the value of `symbol1'. On the next line, it would see the `EQU' again and be able to determine the value of `symbol1', but by then it would be too late.

NASM avoids this problem by defining the right-hand side of an `EQU' statement to be a critical expression, so the definition of `symbol1' would be rejected in the first pass.

There is a related issue involving forward references: consider this code fragment.
              mov     eax,[ebx+offset]
      offset  equ     10
 
NASM, on pass one, must calculate the size of the instruction `mov eax,[ebx+offset]' without knowing the value of `offset'. It has no way of knowing that `offset' is small enough to fit into a one- byte offset field and that it could therefore get away with generating a shorter form of the effective-address encoding; for all it knows, in pass one, `offset' could be a symbol in the code segment, and it might need the full four-byte form. So it is forced to compute the size of the instruction to accommodate a four-byte address part. In pass two, having made this decision, it is now forced to honour it and keep the instruction large, so the code generated in this case is not as small as it could have been. This problem can be solved by defining `offset' before using it, or by forcing byte size in the effective address by coding `[byte ebx+offset]'.

3.9. Local Labels

NASM gives special treatment to symbols beginning with a period. A label beginning with a single period is treated as a _local_ label, which means that it is associated with the previous non-local label. So, for example:
                                                                                        
      label1  ; some code
                                                                                        
      .loop
              ; some more code
                                                                                        
              jne     .loop
              ret
                                                                                        
      label2  ; some code
                                                                                        
      .loop
              ; some more code
                                                                                        
              jne     .loop
              ret
 
In the above code fragment, each `JNE' instruction jumps to the line immediately before it, because the two definitions of `.loop' are kept separate by virtue of each being associated with the previous non-local label.

This form of local label handling is borrowed from the old Amiga assembler DevPac; however, NASM goes one step further, in allowing access to local labels from other parts of the code. This is achieved by means of _defining_ a local label in terms of the previous non-local label: the first definition of `.loop' above is really defining a symbol called `label1.loop', and the second defines a symbol called `label2.loop'. So, if you really needed to, you could write
                                                                                       
      label3  ; some more code
              ; and some more
                                                                                        
              jmp label1.loop
 
Sometimes it is useful - in a macro, for instance - to be able to define a label which can be referenced from anywhere but which doesn't interfere with the normal local-label mechanism. Such a label can't be non-local because it would interfere with subsequent definitions of, and references to, local labels; and it can't be local because the macro that defined it wouldn't know the label's full name. NASM therefore introduces a third type of label, which is probably only useful in macro definitions: if a label begins with the special prefix `..@', then it does nothing to the local label mechanism. So you could code
                                                                                        
      label1:                         ; a non-local label
      .local:                         ; this is really label1.local
      ..@foo:                         ; this is a special symbol
      label2:                         ; another non-local label
      .local:                         ; this is really label2.local
                                                                                        
              jmp     ..@foo          ; this will jump three lines up
 
Chapter 4: The NASM Preprocessor

                                                                                      
    NASM contains a powerful macro processor, which supports conditional
 assembly, multi-level file inclusion, two forms of macro (single-line
 and multi-line), and a `context stack' mechanism for extra macro power.
 Preprocessor directives all begin with a `%' sign.
 

The preprocessor collapses all lines which end with a backslash (\) character into a single line. Thus:
                                                                                       
      %define THIS_VERY_LONG_MACRO_NAME_IS_DEFINED_TO \
              THIS_VALUE
 
will work like a single-line macro without the backslash-newline sequence.

4.1.1. The Normal Way: `%define'

Single-line macros are defined using the `%define' preprocessor directive. The definitions work in a similar way to C; so you can do things like %define ctrl 0x1F & %define param(a,b) ((a)+(a)*(b)) mov byte [param(2,ebx)], ctrl 'D' which will expand to mov byte [(2)+(2)*(ebx)], 0x1F & 'D' When the expansion of a single-line macro contains tokens which invoke another macro, the expansion is performed at invocation time, not at definition time. Thus the code %define a(x) 1+b(x) %define b(x) 2*x mov ax,a(8) will evaluate in the expected way to `mov ax,1+2*8', even though the macro `b' wasn't defined at the time of definition of `a'. Macros defined with `%define' are case sensitive: after `%define foo bar', only `foo' will expand to `bar': `Foo' or `FOO' will not. By using `%idefin!"e' instead of `%define' (the `i' stands for `insensitive') you can define all the case variants of a macro at once, so that `%idefine foo bar' would cause `foo', `Foo', `FOO', `fOO' and so on all to expand to `bar'. There is a mechanism which detects when a macro call has occurred as a result of a previous expansion of the same macro, to guard against circular references and infinite loops. If this happens, the preprocessor will only expand the first occurrence of the macro. Hence, if you code %define a(x) 1+a(x) mov ax,a(3) the macro `a(3)' will expand once, becoming `1+a(3)', and will then expand no further. This behaviour can be useful: see *Note Section 8.1:: for an example of its use. You can overload single-line macros: if you write %define foo(x) 1+x %define foo(x,y) 1+x*y the preprocessor will be able to handle both types of macro call, by counting the parameters you pass; so `foo(3)' will become `1+3' whereas `foo(ebx,2)' will become `1+ebx*2'. However, if you define %define foo bar then no other definition of `foo' will be accepted: a macro with no parameters prohibits the definition of the same name as a macro _with_ parameters, and vice versa. This doesn't prevent single-line macros being _redefined_: you can perfectly well define a macro with %define foo bar and then re-define it later in the same source file with %define foo baz Then everywhere the macro `foo' is invoked, it will be expanded according to the most recent definition. This is particularly useful when defining single-line macros with `%assign' (see *Note Section 4.1.5::). 4.4. Conditional Assembly ========================= Similarly to the C preprocessor, NASM allows sections of a source file to be assembled only if certain conditions are met. The general syntax of this feature looks like this: %if ; some code which only appears if is met %elif ; only appears if is not met but is %else ; this appears if neither nor was met %endif The `%else' clause is optional, as is the `%elif' clause. You can have more than one `%elif' clause as well. 4.4.1. `%ifdef': Testing Single-Line Macro Existence ---------------------------------------------------- Beginning a conditional-assembly block with the line `%ifdef MACRO' will assemble the subsequent code if, and only if, a single-line macro called `MACRO' is defined. If not, then the `%elif' and `%else' blocks (if any) will be processed instead. For example, when debugging a program, you might want to write code such as ; perform some function %ifdef DEBUG writefile 2,"Function performed successfully",13,10 %endif ; go and do something else Then you could use the command-line option `-dDEBUG' to create a version of the program which produced debugging messages, and remove the option to generate the final release version of the program. You can test for a macro _not_ being defined by using `%ifndef' instead of `%ifdef'. You can also test for macro definitions in `%elif' blocks by using `%elifdef' and `%elifndef'. 4.4.2. `ifmacro': Testing Multi-Line Macro Existence ---------------------------------------------------- The `%ifmacro' directive operates in the same way as the `%ifdef' directive, except that it checks for the existence of a multi-line macro. For example, you may be working with a large project and not have control over the macros in a library. You may want to create a macro with one name if it doesn't already exist, and another name if one with that name does exist. The `%ifmacro' is considered true if defining a macro with the given name and number of arguments would cause a definitions conflict. For example: %ifmacro MyMacro 1-3 %error "MyMacro 1-3" causes a conflict with an existing macro. %else %macro MyMacro 1-3 ; insert code to define the macro %endmacro %endif 4.4.4. `%if': Testing Arbitrary Numeric Expressions --------------------------------------------------- The conditional-assembly construct `%if expr' will cause the subsequent code to be assembled if and only if the value of the numeric expression `expr' is non-zero. An example of the use of this feature is in deciding when to break out of a `%rep' preprocessor loop: see *Note Section 4.5:: for a detailed example. The expression given to `%if', and its counterpart `%elif', is a critical expression (see *Note Section 3.8::). `%if' extends the normal NASM expression syntax, by providing a set of relational operators which are not normally available in expressions. The operators `=', `<', `>', `<=', `>=' and `<>' test equality, less-than, greater-than, less-or-equal, greater-or-equal and not-equal respectively. The C-like forms `==' and `!=' are supported as alternative forms of `=' and `<>'. In addition, low- priority logical operators `&&', `^^' and `||' are provided, supplying logical AND, logical XOR and logical OR. These work like the C logical operators (although C has no logical XOR), in that they always return either 0 or 1, and treat any non-zero input as 1 (so that `^^', for example, returns 1 if exactly one of its inputs is zero, and 0 otherwise). The relational operators also return 1 for true and 0 for false. 4.5. Preprocessor Loops: `%rep' =============================== NASM's `TIMES' prefix, though useful, cannot be used to invoke a multi-line macro multiple times, because it is processed by NASM after macros have already been expanded. Therefore NASM provides another form of loop, this time at the preprocessor level: `%rep'. The directives `%rep' and `%endrep' (`%rep' takes a numeric argument, which can be an expression; `%endrep' takes no arguments) can be used to enclose a chunk of code, which is then replicated as many times as specified by the preprocessor: %assign i 0 %rep 64 inc word [table+2*i] %assign i i+1 %endrep This will generate a sequence of 64 `INC' instructions, incrementing every word of memory from `[table]' to `[table+126]'. For more complex termination conditions, or to break out of a repeat loop part way along, you can use the `%exitrep' directive to terminate the loop, like this: fibonacci: %assign i 0 %assign j 1 %rep 100 %if j > 65535 %exitrep %endif dw j %assign k j+i %assign i j %assign j k %endrep fib_number equ ($-fibonacci)/2 This produces a list of all the Fibonacci numbers that will fit in 16 bits. Note that a maximum repeat count must still be given to `%rep'. This is to prevent the possibility of NASM getting into an infinite loop in the preprocessor, which (on multitasking or multi-user systems) would typically cause all the system memory to be gradually used up and other applications to start crashing. .6. Including Other Files ========================== Using, once again, a very similar syntax to the C preprocessor, NASM's preprocessor lets you include other source files into your code. This is done by the use of the `%include' directive: %include "macros.mac" will include the contents of the file `macros.mac' into the source file containing the `%include' directive. Include files are searched for in the current directory (the directory you're in when you run NASM, as opposed to the location of the NASM executable or the location of the source file), plus any directories specified on the NASM command line using the `-i' option. The standard C idiom for preventing a file being included more than once is just as applicable in NASM: if the file `macros.mac' has the form %ifndef MACROS_MAC %define MACROS_MAC ; now define some macros %endif then including the file more than once will not cause errors, because the second time the file is included nothing will happen because the macro `MACROS_MAC' will already be defined. 4.7. The Context Stack ====================== Having labels that are local to a macro definition is sometimes not quite powerful enough: sometimes you want to be able to share labels between several macro calls. An example might be a `REPEAT' ... `UNTIL' loop, in which the expansion of the `REPEAT' macro would need to be able to refer to a label which the `UNTIL' macro had defined. However, for such a macro you would also want to be able to nest these loops. NASM provides this level of power by means of a _context stack_. The preprocessor maintains a stack of _contexts_, each of which is characterised by a name. You add a new context to the stack using the `%push' directive, and remove one using `%pop'. You can define labels that are local to a particular context on the stack. 4.7.1. `%push' and `%pop': Creating and Removing Contexts --------------------------------------------------------- The `%push' directive is used to create a new context and place it on the top of the context stack. `%push' requires one argument, which is the name of the context. For example: %push foobar This pushes a new context called `foobar' on the stack. You can have several contexts on the stack with the same name: they can still be distinguished. The directive `%pop', requiring no arguments, removes the top context from the context stack and destroys it, along with any labels associated with it. 4.7.2. Context-Local Labels --------------------------- Just as the usage `%%foo' defines a label which is local to the particular macro call in which it is used, the usage `%$foo' is used to define a label which is local to the context on the top of the context stack. So the `REPEAT' and `UNTIL' example given above could be implemented by means of: %macro repeat 0 %push repeat %$begin: %endmacro %macro until 1 j%-1 %$begin %pop %endmacro and invoked by means of, for example, mov cx,string repeat add cx,3 scasb until e which would scan every fourth byte of a string in search of the byte in `AL'. If you need to define, or access, labels local to the context _below_ the top one on the stack, you can use `%$$foo', or `%$$$foo' for the context below that, and so on. 4.8. Standard Macros ==================== NASM defines a set of standard macros, which are already defined when it starts to process any source file. If you really need a program to be assembled with no pre-defined macros, you can use the `%clear' directive to empty the preprocessor of everything. Most user-level assembler directives (see *Note Chapter 5::) are implemented as macros which invoke primitive directives; these are described in *Note Chapter 5::. The rest of the standard macro set is described here. 4.8.1. `__NASM_MAJOR__', `__NASM_MINOR__', `__NASM_SUBMINOR__' and `___NASM_PATCHLEVEL_ The single-line macros `__NASM_MAJOR__', `__NASM_MINOR__', `__NASM_SUBMINOR__' and `___NASM_PATCHLEVEL__' expand to the major, minor, subminor and patch level parts of the version number of NASM being used. So, under NASM 0.98.32p1 for example, `__NASM_MAJOR__' would be defined to be 0, `__NASM_MINOR__' would be defined as 98, `__NASM_SUBMINOR__' would be defined to 32, and `___NASM_PATCHLEVEL__' would be defined as 1. 4.8.7. `ALIGN' and `ALIGNB': Data Alignment ------------------------------------------- The `ALIGN' and `ALIGNB' macros provides a convenient way to align code or data on a word, longword, paragraph or other boundary. (Some assemblers call this directive `EVEN'.) The syntax of the `ALIGN' and `ALIGNB' macros is align 4 ; align on 4-byte boundary align 16 ; align on 16-byte boundary align 8,db 0 ; pad with 0s rather than NOPs align 4,resb 1 ; align to 4 in the BSS alignb 4 ; equivalent to previous line Both macros require their first argument to be a power of two; they both compute the number of additional bytes required to bring the length of the current section up to a multiple of that power of two, and then apply the `TIMES' prefix to their second argument to perform the alignment. If the second argument is not specified, the default for `ALIGN' is `NOP', and the default for `ALIGNB' is `RESB 1'. So if the second argument is specified, the two macros are equivalent. Normally, you can just use `ALIGN' in code and data sections and `ALIGNB' in BSS sections, and never need the second argument except for special purposes. `ALIGN' and `ALIGNB', being simple macros, perform no error checking: they cannot warn you if their first argument fails to be a power of two, or if their second argument generates more than one byte of code. In each of these cases they will silently do the wrong thing. `ALIGNB' (or `ALIGN' with a second argument of `RESB 1') can be used within structure definitions: struc mytype2 mt_byte: resb 1 alignb 2 mt_word: resw 1 alignb 4 mt_long: resd 1 mt_str: resb 32 endstruc This will ensure that the structure members are sensibly aligned relative to the base of the structure. A final caveat: `ALIGN' and `ALIGNB' work relative to the beginning of the _section_, not the beginning of the address space in the final executable. Aligning to a 16-byte boundary when the section you're in is only guaranteed to be aligned to a 4-byte boundary, for example, is a waste of effort. Again, NASM does not check that the section's alignment characteristics are sensible for the use of `ALIGN' or `ALIGNB'. 4.10. Other Preprocessor Directives =================================== NASM also has preprocessor directives which allow access to information from external sources. Currently they include: The following preprocessor directive is supported to allow NASM to correctly handle output of the cpp C language preprocessor. * `%line' enables NAsM to correctly handle the output of the cpp C language preprocessor (see *Note Section 4.10.1::). * `%!' enables NASM to read in the value of an environment variable, which can then be used in your program (see *Note Section 4.10.2::). Chapter 5: Assembler Directives ******************************* 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 *Note Chapter 6::. 5.1. `BITS': Specifying Target Processor Mode ============================================= The `BITS' directive specifies whether NASM should generate code designed to run on a processor operating in 16-bit mode, or code designed to run on a processor operating in 32-bit mode. The syntax is `BITS 16' or `BITS 32'. In most cases, you should not need to use `BITS' explicitly. The `aout', `coff', `elf' and `win32' object formats, which are designed for use in 32-bit operating systems, all cause NASM to select 32-bit mode by default. The `obj' object format allows you to specify each segment you define as either `USE16' or `USE32', and NASM 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 code in a flat binary file; this is because the `bin' output 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. When NASM is in `BITS 16' state, instructions which use 32-bit data are prefixed with an 0x66 byte, and those referring to 32-bit addresses have an 0x67 prefix. In `BITS 32' state, the reverse is true: 32-bit instructions require no prefixes, whereas instructions using 16-bit data need an 0x66 and those working on 16-bit addresses need an 0x67. The `BITS' directive has an exactly equivalent primitive form, `[BITS 16]' and `[BITS 32]'. The user-level form is a macro which has no function other than to call the primitive form. Note that the space is neccessary, `BITS32' will _not_ work! 5.2. `SECTION' or `SEGMENT': Changing and Defining Sections =========================================================== The `SECTION' directive (`SEGMENT' is an exactly equivalent synonym) changes which section of the output file the code you write will be assembled into. In some object file formats, the number and names of sections are fixed; in others, the user may make up as many as they wish. Hence `SECTION' may sometimes give an error message, or may define a new section, if you try to switch to a section that does not (yet) exist. The Unix object formats, and the `bin' object format (but see *Note Section 6.1.3::, all support the standardised section names `.text', `.data' and `.bss' for the code, data and uninitialised-data sections. The `obj' format, by contrast, does not recognise these section names as being special, and indeed will strip off the leading period of any section name that has one. 5.4. `EXTERN': Importing Symbols from Other Modules =================================================== `EXTERN' is similar to the MASM directive `EXTRN' and the C keyword `extern': it is used to declare a symbol which is not defined anywhere in the module being assembled, but is assumed to be defined in some other module and needs to be referred to by this one. Not every object-file format can support external variables: the `bin' format cannot. The `EXTERN' directive takes as many arguments as you like. Each argument is the name of a symbol: extern _printf extern _sscanf,_fscanf Some object-file formats provide extra features to the `EXTERN' directive. In all cases, the extra features are used by suffixing a colon to the symbol name followed by object-format specific text. For example, the `obj' format allows you to declare that the default segment base of an external should be the group `dgroup' by means of the directive extern _variable:wrt dgroup The primitive form of `EXTERN' differs from the user-level form only in that it can take only one argument at a time: the support for multiple arguments is implemented at the preprocessor level. 5.5. `GLOBAL': Exporting Symbols to Other Modules ================================================= `GLOBAL' is the other end of `EXTERN': if one module declares a symbol as `EXTERN' and refers to it, then in order to prevent linker errors, some other module must actually _define_ the symbol and declare it as `GLOBAL'. Some assemblers use the name `PUBLIC' for this purpose. The `GLOBAL' directive applying to a symbol must appear _before_ the definition of the symbol. `GLOBAL' uses the same syntax as `EXTERN', except that it must refer to symbols which _are_ defined in the same module as the `GLOBAL' directive. For example: global _main _main: ; some code `GLOBAL', like `EXTERN', allows object formats to define private extensions by means of a colon. The `elf' object format, for example, lets you specify whether global data items are functions or data: global hashlookup:function, hashtable:data Like `EXTERN', the primitive form of `GLOBAL' differs from the user-level form only in that it can take only one argument at a time. 5.6. `COMMON': Defining Common Data Areas ========================================= The `COMMON' directive is used to declare _common variables_. A common variable is much like a global variable declared in the uninitialised data section, so that common intvar 4 is similar in function to global intvar section .bss intvar resd 1 The difference is that if more than one module defines the same common variable, then at link time those variables will be _merged_, and references to `intvar' in all modules will point at the same piece of memory. Like `GLOBAL' and `EXTERN', `COMMON' supports object-format specific extensions. For example, the `obj' format allows common variables to be NEAR or FAR, and the `elf' format allows you to specify the alignment requirements of a common variable: common commvar 4:near ; works in OBJ common intarray 100:4 ; works in ELF: 4 byte aligned Chapter 6: 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 *Note 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. 6.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 *Note Section 6.1.3::. Using the `bin' format puts NASM by default into 16-bit mode (see *Note Section 5.1::). In order to use `bin' to write 32-bit code such as an OS kernel, you need to explicitly issue the `BITS 32' 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'. 6.1.1. `ORG': Binary File Program Origin ---------------------------------------- The `bin' format provides an additional directive to the list given in *Note Chapter 5::: `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 *Note Section 10.1.3:: for further comments. 6.5. `elf': Executable and Linkable Format Object Files ======================================================= The `elf' output format generates `ELF32' (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'. 6.5.3. `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. 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: 6.8. `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 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'. 8.2. Writing NetBSD/FreeBSD/OpenBSD and Linux/ELF Shared Libraries ================================================================== `ELF' replaced the older `a.out' object file format under Linux because it contains support for position-independent code (PIC), which makes writing shared libraries much easier. NASM supports the `ELF' position-independent code features, so you can write Linux `ELF' shared libraries in NASM. NetBSD, and its close cousins FreeBSD and OpenBSD, take a different approach by hacking PIC support into the `a.out' format. NASM supports this as the `aoutb' output format, so you can write BSD shared libraries in NASM too. The operating system loads a PIC shared library by memory-mapping the library file at an arbitrarily chosen point in the address space of the running process. The contents of the library's code section must therefore not depend on where it is loaded in memory. Therefore, you cannot get at your variables by writing code like this: mov eax,[myvar] ; WRONG Instead, the linker provides an area of memory called the _global offset table_, or GOT; the GOT is situated at a constant distance from your library's code, so if you can find out where your library is loaded (which is typically done using a `CALL' and `POP' combination), you can obtain the address of the GOT, and you can then load the addresses of your variables out of linker-generated entries in the GOT. The _data_ section of a PIC shared library does not have these restrictions: since the data section is writable, it has to be copied into memory anyway rather than just paged in from the library file, so as long as it's being copied it can be relocated too. So you can put ordinary types of relocation in the data section without too much worry (but see *Note Section 8.2.4:: for a caveat). 8.2.1. Obtaining the Address of the GOT --------------------------------------- Each code module in your shared library should define the GOT as an external symbol: extern _GLOBAL_OFFSET_TABLE_ ; in ELF extern __GLOBAL_OFFSET_TABLE_ ; in BSD a.out At the beginning of any function in your shared library which plans to access your data or BSS sections, you must first calculate the address of the GOT. This is typically done by writing the function in this form: func: push ebp mov ebp,esp push ebx call .get_GOT .get_GOT: pop ebx add ebx,_GLOBAL_OFFSET_TABLE_+$$-.get_GOT wrt ..gotpc ; the function body comes here mov ebx,[ebp-4] mov esp,ebp pop ebp ret (For BSD, again, the symbol `_GLOBAL_OFFSET_TABLE' requires a second leading underscore.) The first two lines of this function are simply the standard C prologue to set up a stack frame, and the last three lines are standard C function epilogue. The third line, and the fourth to last line, save and restore the `EBX' register, because PIC shared libraries use this register to store the address of the GOT. The interesting bit is the `CALL' instruction and the following two lines. The `CALL' and `POP' combination obtains the address of the label `.get_GOT', without having to know in advance where the program was loaded (since the `CALL' instruction is encoded relative to the current position). The `ADD' instruction makes use of one of the special PIC relocation types: GOTPC relocation. With the `WRT ..gotpc' qualifier specified, the symbol referenced (here `_GLOBAL_OFFSET_TABLE_', the special symbol assigned to the GOT) is given as an offset from the beginning of the section. (Actually, `ELF' encodes it as the offset from the operand field of the `ADD' instruction, but NASM simplifies this deliberately, so you do things the same way for both `ELF' and `BSD'.) So the instruction then _adds_ the beginning of the section, to get the real address of the GOT, and subtracts the value of `.get_GOT' which it knows is in `EBX'. Therefore, by the time that instruction has finished, `EBX' contains the address of the GOT. If you didn't follow that, don't worry: it's never necessary to obtain the address of the GOT by any other means, so you can put those three instructions into a macro and safely ignore them: %macro get_GOT 0 call %%getgot %%getgot: pop ebx add ebx,_GLOBAL_OFFSET_TABLE_+$$-%%getgot wrt ..gotpc %endmacro 8.2.4. Exporting Symbols to the Library User -------------------------------------------- If you want to export symbols to the user of the library, you have to declare whether they are functions or data, and if they are data, you have to give the size of the data item. This is because the dynamic linker has to build procedure linkage table entries for any exported functions, and also moves exported data items away from the library's data section in which they were declared. So to export a function to users of the library, you must use global func:function ; declare it as a function func: push ebp ; etc. And to export a data item such as an array, you would have to code global array:data array.end-array ; give the size too array: resd 128 .end: Be careful: If you export a variable to the library user, by declaring it as `GLOBAL' and supplying a size, the variable will end up living in the data section of the main program, rather than in your library's data section, where you declared it. So you will have to access your own global variable with the `..got' mechanism rather than `..gotoff', as if it were external (which, effectively, it has become). Equally, if you need to store the address of an exported global in one of your data sections, you can't do it by means of the standard sort of code: dataptr: dd global_data_item ; WRONG NASM will interpret this code as an ordinary relocation, in which `global_data_item' is merely an offset from the beginning of the `.data' section (or whatever); so this reference will end up pointing at your data section instead of at the exported global which resides elsewhere. Instead of the above code, then, you must write dataptr: dd global_data_item wrt ..sym which makes use of the special `WRT' type `..sym' to instruct NASM to search the symbol table for a particular symbol at that address, rather than just relocating by section base. Either method will work for functions: referring to one of your functions by means of funcptr: dd my_function will give the user the address of the code you wrote, whereas funcptr: dd my_function wrt .sym will give the address of the procedure linkage table for the function, which is where the calling program will _believe_ the function lives. Either address is a valid way to call the function. 10.1.1. NASM Generates Inefficient Code --------------------------------------- We sometimes get `bug' reports about NASM generating inefficient, or even `wrong', code on instructions such as `ADD ESP,8'. This is a deliberate design feature, connected to predictability of output: NASM, on seeing `ADD ESP,8', will generate the form of the instruction which leaves room for a 32-bit offset. You need to code `ADD ESP,BYTE 8' if you want the space-efficient form of the instruction. This isn't a bug, it's user error: if you prefer to have NASM produce the more efficient code automatically enable optimization with the `-On' option (see *Note Section 2.1.16::). 10.1.2. My Jumps are Out of Range --------------------------------- Similarly, people complain that when they issue conditional jumps (which are `SHORT' by default) that try to jump too far, NASM reports `short jump out of range' instead of making the jumps longer. This, again, is partly a predictability issue, but in fact has a more practical reason as well. NASM has no means of being told what type of processor the code it is generating will be run on; so it cannot decide for itself that it should generate `Jcc NEAR' type instructions, because it doesn't know that it's working for a 386 or above. Alternatively, it could replace the out-of-range short `JNE' instruction with a very short `JE' instruction that jumps over a `JMP NEAR'; this is a sensible solution for processors below a 386, but hardly efficient on processors which have good branch prediction _and_ could have used `JNE NEAR' instead. So, once again, it's up to the user, not the assembler, to decide what instructions should be generated. See *Note Section 2.1.16::. 10.1.3. `ORG' Doesn't Work -------------------------- People writing boot sector programs in the `bin' format often complain that `ORG' doesn't work the way they'd like: in order to place the `0xAA55' signature word at the end of a 512-byte boot sector, people who are used to MASM tend to code ORG 0 ; some boot sector code ORG 510 DW 0xAA55 This is not the intended use of the `ORG' directive in NASM, and will not work. The correct way to solve this problem in NASM is to use the `TIMES' directive, like this: ORG 0 ; some boot sector code TIMES 510-($-$$) DW 0xAA55 The `TIMES' directive will insert exactly enough zero bytes into the output to move the assembly point up to 510. This method also has the advantage that if you accidentally fill your boot sector too full, NASM will catch the problem at assembly time and report it, so you won't end up with a boot sector that you have to disassemble to find out what's wrong with it. Полный архив NASM info можно взять тут (180 кб) .
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье