7.4.5. `c16.mac': Helper Macros for the 16-bit C Interface
----------------------------------------------------------
Included in the NASM archives, in the `misc' directory, is a file
`c16.mac' of macros. It defines three macros: `proc', `arg' and
`endproc'. These are intended to be used for C-style procedure
definitions, and they automate a lot of the work involved in keeping
track of the calling convention.
(An alternative, TASM compatible form of `arg' is also now built into
NASM's preprocessor. See *Note Section 4.9:: for details.)
An example of an assembly function using the macro set is given here:
proc _nearproc
%$i arg
%$j arg
mov ax,[bp + %$i]
mov bx,[bp + %$j]
add ax,[bx]
endproc
This defines `_nearproc' to be a procedure taking two arguments, the
first (`i') an integer and the second (`j') a pointer to an integer. It
returns `i + *j'.
Note that the `arg' macro has an `EQU' as the first line of its
expansion, and since the label before the macro call gets prepended to
the first line of the expanded macro, the `EQU' works, defining `%$i'
to be an offset from `BP'. A context-local variable is used, local to
the context pushed by the `proc' macro and popped by the `endproc'
macro, so that the same argument name can be used in later procedures.
Of course, you don't _have_ to do that.
The macro set produces code for near functions (tiny, small and
compact- model code) by default. You can have it generate far functions
(medium, large and huge-model code) by means of coding `%define
FARCODE'. This changes the kind of return instruction generated by
`endproc', and also changes the starting point for the argument
offsets. The macro set contains no intrinsic dependency on whether data
pointers are far or not.
`arg' can take an optional parameter, giving the size of the
argument. If no size is given, 2 is assumed, since it is likely that
many function parameters will be of type `int'.
The large-model equivalent of the above function would look like
this:
%define FARCODE
proc _farproc
%$i arg
%$j arg 4
mov ax,[bp + %$i]
mov bx,[bp + %$j]
mov es,[bp + %$j + 2]
add ax,[bx]
endproc
This makes use of the argument to the `arg' macro to define a
parameter of size 4, because `j' is now a far pointer. When we load
from `j', we must load a segment and an offset.