NASM Forum > Summer of Code Ideas

Extending struc/istruc

(1/2) > >>

Rob Neff:
Built in support for nested structures and unions (named and/or unnamed).
The following is a rather simple example:


--- Code: ---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                     ;

--- End code ---

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.

Klod:
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.


--- Code: ---%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

--- End code ---


This example will compile with nasm -f and link with goasm

Regards,
Klod

cm:

--- Quote from: Rob Neff on August 16, 2010, 04:00:27 PM ---I have successfully implemented something similar within NASMX using macros, but - IMHO, this additional syntax support really belongs in Nasm proper.
--- End quote ---

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.


--- Quote ---[...] would provide multiple benefits as compared to the current implementation.
--- End quote ---

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.

Rob Neff:

--- Quote from: cm on October 06, 2010, 12:12:52 PM ---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.

--- End quote ---

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.

cm:
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.

Navigation

[0] Message Index

[#] Next page

Go to full version