NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: isywum on January 24, 2012, 04:58:11 PM

Title: Variables in macros
Post by: isywum on January 24, 2012, 04:58:11 PM
Hi,

I'm beginner of programming NASM and got a little problem.
I wanna create a variable in a macro but I always get some errors.
Could anyone tell me how to create a variable in a macro?! :)

Thanks in advanve.
Title: Re: Variables in macros
Post by: Frank Kotler on January 24, 2012, 05:31:19 PM
It would probably be helpful to know what you tried, and what errors you got. Here's "an" example:

Code: [Select]
%macro say 1+
    section .data
    %%str db %1
    db 0
    section .text
    push %%str
    call putz ; must exist
%endmacro

That may not be any help, if you're trying to do something different... :)

Best,
Frank

Title: Re: Variables in macros
Post by: Mathi on January 24, 2012, 05:34:46 PM
Can you give more details on your problem.
May be a portion of the code which is causing the issue?

'creating a variable in macro' -  If you are doing something like

%macro INTEGER 1
%1: dd 0
%endmacro

you can use this macro in section .data like,

INTEGER X
INTEGER Y

We need to make sure the labels are not redefined.

For general documentation of Macros refer to,
http://www.nasm.us/doc/nasmdoc4.html#section-4.3 (http://www.nasm.us/doc/nasmdoc4.html#section-4.3)
Title: Re: Variables in macros
Post by: Bryant Keller on January 25, 2012, 01:55:58 AM
I would also like to suggest you make clear the term "variable". As Mathi and Frank assumed, a runtime variable can be declared more or less the same way as any other variable, by perpending %% to the label, you make the label local to the context of the macro. Another type of variable you might be referring to is a preprocessor variable. An example of that could be to use %assign or %define. The following example code might give you some info on preprocessor variables (designed for linux).

Code: (intarray.asm) [Select]
;; build with:
;; nasm -f elf intarray.asm
;; gcc -nostartfiles -o intarray intarray.o

%macro int_array 1
%push _int_array_
%assign %$index 0
%ifidni __SECT__,[SECTION .bss]
%define %$defint resd 1
%else
%define %$defint dd 0
%endif
%rep %1
.@%{$index}: %{$defint}
%assign %$index %{$index} + 1
%endrep
%pop
%endmacro

EXTERN printf

SECTION .data

strFormat: db "%d", 10, 0

myDataIntegers:
int_array 5

SECTION .bss

myBssIntegers:
int_array 11

SECTION .text

GLOBAL _start
_start:
xor eax, eax
mov [myDataIntegers.@0], eax
inc eax
mov [myDataIntegers.@1], eax
inc eax
mov [myDataIntegers.@2], eax
inc eax
mov [myDataIntegers.@3], eax
inc eax
mov [myDataIntegers.@4], eax
inc eax
mov [myBssIntegers.@0], eax
inc eax
mov [myBssIntegers.@1], eax
inc eax
mov [myBssIntegers.@2], eax
inc eax
mov [myBssIntegers.@3], eax
inc eax
mov [myBssIntegers.@4], eax
inc eax
mov [myBssIntegers.@5], eax
inc eax
mov [myBssIntegers.@6], eax
inc eax
mov [myBssIntegers.@7], eax
inc eax
mov [myBssIntegers.@8], eax
inc eax
mov [myBssIntegers.@9], eax
inc eax
mov [myBssIntegers.@10], eax

mov edi, myDataIntegers
mov ecx, 5
.@LoopFirst:
push ecx
push dword [edi]
push strFormat
call printf
add esp, 8
add edi, 4
pop ecx
dec ecx
or ecx, ecx
jnz .@LoopFirst

mov edi, myBssIntegers
mov ecx, 11
.@LoopSecond:
push ecx
push dword [edi]
push strFormat
call printf
add esp, 8
add edi, 4
pop ecx
dec ecx
or ecx, ecx
jnz .@LoopSecond

xor eax, eax
xor ebx, ebx
inc eax
int 0x80

Regards,
Bryant Keller
Title: Re: Variables in macros
Post by: isywum on February 02, 2012, 12:27:52 PM
Hi,
I'd like to do something like this (it doesn't work of course):
%macro MyMacro 5
res db ?
%%start:
mov ax, %1
add ax, %2
mov res, ax
%endmacro

I tried for example: %%res db ? or %local res db ? etc.

@Bryant Keller:
Unfortunately I don't understand your code. :(

Thanks for your help!
Title: Re: Variables in macros
Post by: Mathi on February 02, 2012, 03:59:08 PM
Looks like you are writing a macro to add two numbers and return the sum.
If that's the intent, I don't get your idea of defining a variable here.
You can return the sum in ax register itself.

For eg.

Code: [Select]
%macro MyMacro 2  ;; two parameters
        mov ax, %1
        add ax, %2
%endmacro

res db ?   looks like tasm syntax.

In NASM, we need to specify the size of the data or the data itself.

For uninitialized data
var resb 2  ;; reserve 2 bytes.

For initialized data,
var db "test",0
or
var dw 99

etc.
You might need to switch between sections if you still need to define read/write variables along with code.

eg.

Code: [Select]
%macro MyMacro 2  ;; two parameters
        ;;jmp additioncode     ;; As per nasmdoc this jmp statement is not needed.
        [section .bss]
        %%res db 2      ;; this variable cannot be used outside the macro.
        __SECT__         ;; switches to code section ( the previous section before switching).

    additioncode:
        mov ax, %1
        add ax, %2
        ;;Do something with [%%res]
%endmacro

org 100h

mov bx,1
mov cx,2

MyMacro bx,cx   ;;invoke the macro.

;; at this point ax will have the value 3. (1+2)




Title: Re: Variables in macros
Post by: isywum on February 02, 2012, 06:00:10 PM
Hi,
my code was just an example how I tried to create a variable.
In this case it wasn't usefull of course but in my application I really need local variables.
Unfortunately your code does't work: "error: symbol `dif' redefined"
I hope you can help me. :)
Thanks in advance.
Title: Re: Variables in macros
Post by: Frank Kotler on February 02, 2012, 11:36:55 PM
I don't see where "dif" occurs, but I can guess...
Code: [Select]
%macro my_macro 1
dif db %1
; more stuff?
%endmacro

The first time you use "my_macro", it shouldn't be a problem. The second time you use it, "dif" will be redefined.

One way to get around that is to use a "macro local" label/variable (they're the same thing, to Nasm)...
Code: [Select]
%macro my_macro 1
%%dif db %1
; more stuff?
%endmacro

The "%%" will cause Nasm to cook up a unique name every time you use "my_macro". This name will be somewhat "cryptic", and may be a problem if you try to reference the variable from outside the macro. (I don't know a solution to that)

Bryant shows a slightly different method, which he says works better for him - a "context-local" variable. Nasm uses the "%push" macro command to save a context on Nasm's internal "context stack" (don't confuse it with the regular "push" instruction). This context stays in place until you remove it with the "%pop" command.
Code: [Select]
%macro my_macro 1
  %push some_context
  %$myvar db 0
  ; other stuff?
  %pop
%endmacro

I find this most useful when you've got a couple of macros that need to "share" a variable - "proc" and "endproc", for example. You "%push proc" in the "proc" macro, and then (for example) count the number of parameters. When you get to "endproc", you check the context - if it isn't "proc", "error: endproc without proc". If it is in the right context, the "context local" variable - "$%param_count", say - is available in the "endproc" macro. You probably want to "%pop" the context in the "endproc" macro. That probably isn't too clear, but just "%%my_var" will probably work for you(?).

I see a couple of errors in your code that don't have anything to do with macros. Nasm doesn't use "db ?" as other assemblers do. Use "db 0", or if it's in an uninitialized section (.bss), use "resb 1". You can "%define ? 0" if you really want to. The other thing...
Code: [Select]
mov res, ax
is just plain wrong. Use:
Code: [Select]
mov [res], ax
These errors suggest that maybe you're used to using another assembler. Nasm has a few subtle but important differences! There's a section in the Friendly Manual that covers some of 'em:
http://www.nasm.us/xdoc/2.10rc8/html/nasmdoc2.html#section-2.2

If none of that helps, maybe you can explain more about what you're trying to do. There's probably "some solution"...

Best,
Frank



Title: Re: Variables in macros
Post by: isywum on February 03, 2012, 09:13:10 AM
Hi,

thanks for your great answer!
I tried this code
Code: [Select]
%%dif db 0

%%start:
and it works :) but when I try to work with this variable (e.g. mov %%dif, 1) I get this error:  "invalid combination of opcode and operands".
How can I work with this variable?

Thanks in advance!
Title: Re: Variables in macros
Post by: Frank Kotler on February 03, 2012, 11:09:08 AM
Code: [Select]
mov byte [%%dif], 1
?

Best,
Frank


Title: Re: Variables in macros
Post by: isywum on February 03, 2012, 11:32:04 AM
It works! :)
Thanks for your help!