NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: lfa on January 31, 2011, 05:58:53 PM
-
Hi all,
I'm trying to figure out a way of achieving the following (MASM snippet) in NASM:
link = 0
; ...
construct:
dd link
link = $
; ...
where the assignment of $ to link will be evaluated multiple times and employed in the construction of a linked list.
I initially thought that I could use %assign for this purpose, but read in the manual that
The expression passed to %assign is a critical expression (see section 3.8 ), and must also evaluate to a pure number (rather than a relocatable reference such as a code or data address, or anything involving a register).
Any ideas on how I might go about solving this in NASM?
Thanks in advance.
-
There are several ways to solve that, but I would probably do it like this:
%define link 0 ; or %assign, doesn't matter in this case
; ...
construct:
%define link construct
; ...
This assumes that your code really contains a label like "construct" each time that you want to re-define link. So, a second re-definition would have to look somewhat like this (as labels must be unique, you cannot re-use the label "construct"):
second_construct:
%define link second_construct
; ...
It might require less typing or be easier to implement in your code to use macro-local labels (http://www.nasm.us/xdoc/2.09.04/html/nasmdoc4.html#section-4.3.2) or context-local labels (http://www.nasm.us/xdoc/2.09.04/html/nasmdoc4.html#section-4.7.2). For example, using macros along the former:
%define link 0
%macro constructlabel 0
%%construct:
%define link %%construct
%endmacro
; ...
constructlabel
; ...
constructlabel
; ...
Notice how the macro is used multiple times, but in fact defines a different label each time. "link" is re-defined (in the preprocessor) to the last defined label's name. If you use a macro to create your constructs (the "; ..." parts) anyway, then you could include the two lines in my example's macro at the beginning of your macro instead of using two separate macros.
This mechanism could be implemented using context-local labels instead.
-
Thanks for your suggestions cm; here's what I've ended up with:
%define link 0
%macro update_link 0
%%update_link:
dd link
%define link %%update_link
%endmacro
Nice and compact.
-
Not quite, the masm code is using 'link = $' to set link to the address after the dd, so what you are actually creating is something like:
CPU 386
BITS 32
%macro StartList 1
%{1}:
%endmacro
%macro addNode 1+
%push
dd %[%%addr]
%{1}
%%addr:
%pop
%endmacro
%macro EndList 0
DD 0 ; NULL TERMINATOR
%endmacro
%macro for_each 1
%push _FOR_EACH_
pushad
mov edi, %{1}
%$start_of_for:
mov eax, [edi]
or eax, eax
jz %[%$end_of_for]
push edi
mov eax, [edi+4]
%endmacro
%macro end_for 0
pop edi
mov edi, [edi]
jmp %[%$start_of_for]
%$end_of_for:
popad
%pop
%endmacro
SECTION .data
StartList myList
addNode DD 1
addNode DD 7
addNode DD 5
addNode DD 8
addNode DD 12
addNode DD 32
EndList
strFmt DB "%d", 10
EXTERN printf
SECTION .text
GLOBAL _start
_start:
for_each myList
push eax
push strFmt
call printf ; display it
add esp, 8
end_for
xor eax, eax
xor ebx, ebx
inc eax
int 80h
The code which scans the linked list is Linux/GlibC dependent, but the macros should work on any platform.
[bkeller@localhost ~/temp] $ nasm -f elf -o LinkedList.o LinkedList.asm
[bkeller@localhost ~/temp] $ gcc -nostartfiles LinkedList.o -o LinkedList
[bkeller@localhost ~/temp] $ ./LinkedList
1
7
5
8
12
32
[bkeller@localhost ~/temp] $
WARNING: Not a whole lot of thought was put into this example, it's by no means meant to be optimized (in fact, for_each is down-right ugly). But at least it works! ;D
Regards,
Bryant Keller
-
Thanks for the suggestion Bryant.
I should have clarified that the caller has been reworked to point at the dword containing the link address rather than the following cell; this makes walking the list simpler (and creating the list in .text very straightforward with the update_link macro).