NASM - The Netwide Assembler
NASM Forum => Summer of Code Ideas => Topic started by: Rob Neff on August 16, 2010, 04:00:27 PM
-
Built in support for nested structures and unions (named and/or unnamed).
The following is a rather simple example:
struc MSG
.hwnd resq 1 ; MSG.hwnd equ 0, MSG.hwnd_size equ 8
.message resd 1 ; MSG.message equ 8 , MSG.message_size equ 4
.wParam resq 1 ; MSG.wParam equ 12 , MSG.message_size equ 8
.lParam resq 1 ; MSG.wParam equ 20 , MSG.message_size equ 8
.u union ; MSG.u equ 28 ( named union )
.time resd 1 ; MSG.u.time equ 28, MSG.u.time_size equ 4
struc ; unnamed nested struc
.time_l resw 1 ; MSG.u.time_l equ 28, MSG.u.time_l_size equ 2
.time_h resw 1 ; MSG.u.time_h equ 30, MSG.u.time_h_size equ 2
ends ; no size can be defined for unnamed struc or union
endu ; MSG.u_size equ 4
.pt struc ; MSG.pt equ 32 ( named nested struc )
.x resd 1 ; MSG.pt.x equ 32 , MSG.pt.x_size equ 4
.y resd 1 ; MSG.pt.y equ 36 , MSG.pt.y_size equ 4
ends ; MSG.pt_size equ 4
ends ; MSG_size equ 40
istruc MSG, message ; create label for message address
at MSG.hwnd dq 0
at MSG.u.time dd 0x0100 ;
at MSG.pt.x dd 64
iends ;
I have successfully implemented something similar within NASMX using macros, but - IMHO, this additional syntax support really belongs in Nasm proper. The syntax provides transparency such that it doesn't break pre-existing code and would provide multiple benefits as compared to the current implementation.
-
Hi Rob, I agree one hundred percent.
The NAsm struc/istruc mechanism is one area of Nasm that I have a hard time warming up to. For a while I used the old xstruc/ixstruc macros by Joergen Ibsen. But still... I had a look at the latest NASMX implementation to. I decided to try my hand at an implementation for two reasons: 1. to test the preprocessor in revision and secondly to test my "know how" of Nasm/preprocessor.
The following example is heavily influenced by Bryant Kellers OOP example. It is by no means complete, nesting needs to implemented and also init t,test_one,< etc> needs to be complete. For the time being, I decided to use the syntax t.test_one.z, (including the strucname) in the definition. This was done mainly for my sake of learning how to compose symbols for later reuse.
%imacro STRUCT 1-2 0
%push __STRUCT__
%define %$context __STRUCT__
%define %$name %1
%assign %$nItems 0
%assign %$size %2
%assign %$oset %2
[ABSOLUTE %2]
%{$name}:
%endm
%imacro UNION 1-2 0
%push __UNION__
%define %$context __UNION__
%define %$name %1
%assign %$nItems 0
%assign %$base %2
%assign %$max 0
[ABSOLUTE %{$base}]
%{$name}:
%endm
%imacro ENDS 1
%ifn (%{$name} <> %1)
%ifctx __UNION__
%assign %{$name}_size %$max
%assign %{$name}_noitems %{$nItems}
%define _UNION_%{$name}_defined %{$name}
%warning "number_of_items" %$nItems %{$name}'_size' %$max '_UNION_'%[%{$name}]_defined _UNION_%{$name}_defined %$context
%pop
%elifctx __STRUCT__
%assign %{$name}_size %$size
%assign %{$name}_noitems %{$nItems}
%define _STRUCT_%{$name}_defined %{$name}
%warning "number_of_items" %{$name}_noitems %{$name}'_size' %$size '_STRUCT_'%[%{$name}]_defined _STRUCT_%{$name}_defined %$context
%pop
%else
%define __SECT__ [SECTION .data]
%endif
%ifdef __SECT__
__SECT__
%endif
%else
%error we are in the wrong context
%endif
%endm
%imacro SET 1-3
%ifctx __STRUCT__
%assign %$nItems %$nItems +1
%xdefine %[%{$name}]_item_%[%{$nItems}]_iname .%{1}
%xdefine %[%{$name}]_item_%[%{$nItems}]_ofset %{$oset}
%{$name}%+.%1 equ %$oset
%define %[%{$name}]_item_%[%{$nItems}]_size %2
%assign %$size %$size+%2
%warning %[%{$name}]_item_%[%{$nItems}]'_size' %2 'and ofset' %{$name}_item_%[%{$nItems}]_ofset 'and ' %[%{$name}]_item_%[%{$nItems}]_
%assign %$oset %$size
%elifctx __UNION__
%assign %$nItems %$nItems +1
[ABSOLUTE %{$base}]
. %+ %1:
%xdefine %[%{$name}]_item_%[%{$nItems}]_size %2
%xdefine %[%{$name}]_item_%[%{$nItems}]_iname .%+ %{1}
%if %$max < %2
%assign %$max %2
%warning %[%{$name}]_item_%[%{$nItems}] size %$max %[%{$name}]_item_%[%{$nItems}]_
%endif
%endif
%endm
%macro init 1-3+
%push __INITIALIZE__
%define %$context __ISTRUCT__
%define %$tag %1
%define %$sname %2
%ifdef _STRUCT_%{$sname}_defined
%ifidni %{3}, <>
[Section .data]
align 4
%$tag: times %{$sname}_size db 0
%assign %$nItems 1
%rep %{$sname}_noitems
%{$tag}%+.%{$sname}%+%[%{$sname}]_item_%[%{$nItems}]_iname equ %{$tag}+%{$sname}_item_%{$nItems}_ofset
%warning %{$tag}%+.%{$sname}%+%[%{$sname}]_item_%[%{$nItems}]_iname %{$tag}+%{$sname}_item_%{$nItems}_ofset
%assign %$nItems %$nItems+1
%endrep
__SECT__
%else
%warning %2 is not an empty struct, handle argument initializing
%endif
%elifdef _UNION_%{2}_defined
%ifidni %{3}, <>
[Section .data]
align 4
%{$tag}: times %{2}_size db 0
%assign %$nItems 1
%rep %{$sname}_noitems
%{$tag}%+.%{$sname}%+%[%{$sname}]_item_%[%{$nItems}]_iname equ %{$tag}+%{$sname}_item_%{$nItems}_size
%warning %{$tag}%+.%{$sname}%+%[%{$sname}]_item_%[%{$nItems}]_iname %{$tag}+%{$sname}_item_%{$nItems}_size
%assign %$nItems %$nItems+1
%endrep
__SECT__
%else
%warning else clause%2
%endif
%else
%ERROR %2 not defined
%endif
%pop
%endm
struct test_one
set x,4
set y,2
set z,16
ends test_one
UNION union_one
set a,1
set b,2
set c,4
set d,8
ENDS union_one
EXTERN GetStdHandle
EXTERN GetConsoleMode
Extern SetConsoleTitleA
EXTERN WriteFile
EXTERN SetConsoleMode
EXTERN WaitForSingleObject
EXTERN ReadFile
Extern wsprintfA
[Section .data]
msg DB 'Press any key to continue...',13,10
.len
conTitle db "Test--- Struct testing ---tseT",0
strFmt DB `[t.test_one.x]: %d\n[t.test_one.y]: %d\n[t.test_one.z]: %d\ntest_one_size: %d\nt.test_one.x: %d\nt.test_one.y: \
%d\nt.test_one.z: %d\n[union_one.c]: %d\nunion_one_size: %d\n`,0
strBuf TIMES 1025 DB 0
[Section .bss]
hStdIn RESD 1
hStdOut resd 1
hBuffer RESD 1
hNum RESD 1
hMode RESD 1
[Section .text]
Start:
init t,test_one,<>
;init p,test_two,<> ;ERROR, test_two is not defined
init q,union_one,<>
push -11
call GetStdHandle
mov [hStdOut],eax
push -10
call GetStdHandle
mov dword[hStdIn], eax
push dword[hStdIn]
push dword hMode
call GetConsoleMode
push conTitle
call SetConsoleTitleA
mov dword[q.union_one.c],0xfffffff
push dword union_one_size
push dword[q.union_one.c]
mov dword [t.test_one.x], 0x1
mov word [t.test_one.y], 0xfff
mov dword [t.test_one.z], 0x3
mov dword [t.test_one.z], 0x3
mov dword [t.test_one.z+4], 0x4
push t.test_one.z
push t.test_one.y
push t.test_one.x
Push dword test_one_size
Push dword [t.test_one.z]
xor eax,eax
mov ax,word [t.test_one.y]
push eax
;Push word [t.test_one.y] ;don't work stack misaligned
Push dword [t.test_one.x]
Push DWORD strFmt
Push DWORD strBuf
Call wsprintfA
Add Esp, (9*4) ;c style function
push 0
push dword hNum
push DWORD 1024
push DWORD strBuf
push dword[hStdOut]
call WriteFile
push 0
push dword hNum
push DWORD msg.len-msg
push DWORD msg
push dword[hStdOut]
call WriteFile
push 0
push DWORD hNum
push dword 1
push DWORD hBuffer
push dword[hStdIn]
call ReadFile
push 0
EXTERN ExitProcess
call ExitProcess
This example will compile with nasm -f and link with goasm
Regards,
Klod
-
I have successfully implemented something similar within NASMX using macros, but - IMHO, this additional syntax support really belongs in Nasm proper.
NASMX's nested union or struc macro must be used in a different way than in your example, as there is currently no way to determine the label in front of a macro. Therefore, you're right in that this exact syntax would belong into NASM (the assembler or the preprocessor itself), because it currently can't be implemented by macros.
[...] would provide multiple benefits as compared to the current implementation.
Over all, it would make unions more readable. It can be implemented by macros, except for labels preceding the nested union or struc macro to name the nested union or struc.
-
Over all, it would make unions more readable. It can be implemented by macros, except for labels preceding the nested union or struc macro to name the nested union or struc.
Actually, when I originally wrote the NASMX struc macros I was unaware of an undocumented preprocessor feature %00 which does in fact provide access to the label preceeding the macro - provided said label appears on the same line during invocation of the macro. This feature is now being documented (along with a possible %: alias - Keith could better answer that). I "might" revisit this syntax for the next release to provide more consistency with nasm's istruc.
-
Ok.. so basically the syntax you proposed can be done with macros now (or so I would think). This could go into NASM's default macros, or it could be made available in a %use package. "Built-in support" sounds like you want to code it into the source, which isn't necessary for this.
Wait actually there is an issue: %00 or %: can be used to access the label, but it probably can't be re-defined this way. (Its definition can't be avoided.) This provides some obstacles for such struc and union macros and would likely result in the creation of unnecessary labels.
-
Ok.. so basically the syntax you proposed can be done with macros now (or so I would think). This could go into NASM's default macros, or it could be made available in a %use package. "Built-in support" sounds like you want to code it into the source, which isn't necessary for this.
The main reason for my proposal of including nested structs/unions directly into nasm source was two-fold:
1) To make nasm itself more programmer friendly such that macros wouldn't be needed to enable this capability if already built in;
2) Compilation speed.
As an example: currently, %include windows.inc brings the preprocessor to a crawl as most Windows structures have been defined within that one file. Not making all those macro calls (at least 4 per struc) and associated defines/equates would reduce compile time considerably. Another avenue of increasing speed is splitting out all those defines and structure definitions into a format more familiar with the SDK as separate header/include files. This is a monumental task but eventually doable. I've begun work on a program to help with converting SDK headers to nasm includes - h2incn ( a similar name/project previously attempted by another developer) but have been rather pre-occupied with other NASMX issues lately. If you're interested in helping with header conversions PM me - I'll glady accept any help I can get ;)
-
[120 Day BUMP, mov eax, dword [Sorry_About_That]]
I absolutely agree that a full blown struc, union should be implemented into nasm. It is cruicial. Let me explain why in few points:
1a. Implementing these basic things with the help of nasm macros is misuse of the macro system
1b. It is misuse because the amount of macroinstructions it takes, absolutely overloads the macro system
1c. If implemented directly into nasm, would produce perhaps a quarter of that (Much easier in code)
2. People should be using the extremely fine macro system inside nasm for other purposes than writing basic elements like structures.
3. The basic rule of any macro system. If it takes too much to macro'it, put it in code.