Author Topic: Error when using "istruc"  (Read 33806 times)

Offline Serge

  • Jr. Member
  • *
  • Posts: 26
  • Country: ru
Error when using "istruc"
« on: February 15, 2010, 11:13:07 AM »
Trying to use "istruc" inside macro I created the following code:

Code: [Select]
struc str
  .byte: resb 1
endstruc

%macro istr 0
istruc str
  at .byte, db 0
iend
%endmacro

label: istr

NASM reports the following error:

Code: [Select]
Test.asm:11: error: non-constant argument supplied to TIMES.
What's wrong? How to use istruc inside macro?
Without "label" it compiles OK. But I need that label.
« Last Edit: February 27, 2010, 05:16:36 PM by Serge »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: "istruc" inside macro
« Reply #1 on: February 15, 2010, 01:00:43 PM »
Weird, I thought, that "label:" should make a difference. What's happening, I think, is that the existance of a label breaks the "local label mechanism" for ".byte". If the member name in your struc is unique, rather than a "local label", it works. If we use the full name "str.byte" in the istruc, it works. Dunno if you can live with that...

Best,
Frank


Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: "istruc" inside macro
« Reply #2 on: February 15, 2010, 05:42:31 PM »
For istruc (an instance/declaration) you'll need full decoration...

Code: [Select]
istruc str
  at str.byte, db 0
iend

Offline Serge

  • Jr. Member
  • *
  • Posts: 26
  • Country: ru
Re: "istruc" inside macro
« Reply #3 on: February 16, 2010, 02:21:53 PM »
That works. But looks strange.
Thank you.

Offline Serge

  • Jr. Member
  • *
  • Posts: 26
  • Country: ru
Re: "istruc" inside macro
« Reply #4 on: February 24, 2010, 01:51:30 PM »
Hmmm. Even worse. This construction doesn't work even without any macroses. The following quite simple code also gives an error.

Code: [Select]
struc str
  .byte: resb 1
endstruc

label:
istruc str
  at .byte, db 0
iend

But even more. If I specify full decoration, I have no ability to address of the members of structure directly. The following construction:

Code: [Select]
struc str
  .byte: resb 1
endstruc

label:
istruc str
  at str.byte, db 0
iend

mov al, [label.byte]

also reports an error that `label.byte` is undefined.
So what's the use of istruc??

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: "istruc" inside macro
« Reply #5 on: February 24, 2010, 05:04:40 PM »
The use of "istruc" is to initialize an instance of a struc. :)

The so-called local label ".byte" is "valid" from the previous non-local label ("str", in this case) to the next non-local label (there's a mechanism, "..@label" which is neither local nor non-local - it won't break the "scope" - I don't think it will help here)

Outside of this "scope", Nasm's local labels (unlike "true" local labels) can be referred to by its "full name" - "str.byte" in this case.

Within the "scope" begun by "label:", there is no local label ".byte", so "label.byte" won't work. Outside of the "scope", begun by "str" and ended by "label", the only name recognized is "str.byte" - and it's value is the offset of ".byte" from the beginning of the struc. So you need:

Code: [Select]
mov al, [label + str.byte]

Note that the C syntax "strucname.membername" does something completely different (the full address) from "strucname.localname", which is merely the "full name" of the member (and evaluates to zero, in this case) - you'll have to add the offset of the beginning of the struc to get the "full address". This applies even if you don't use local labels as the names of your members - but it looks less like the C syntax, which may reduce confusion.

If you observe that this makes using local labels as element names less useful than it might be, I'd agree, but that's "the way it works", and I don't think it's fixable without a complete rework of the local label mechanism... which I don't see happening.

This all may seem somewhat strange - especially if you're expecting C-like syntax - but it's a pretty "workable" mechanism, I find, once you get used to it (YMMV).

As to working "without macroses", "struc" *is* a macro, so good luck with that! :)

If you can think of how this might be more clearly documented - help us out!

Best,
Frank


Offline Serge

  • Jr. Member
  • *
  • Posts: 26
  • Country: ru
Re: "istruc" inside macro
« Reply #6 on: February 27, 2010, 05:58:06 PM »
OK. Let it be the very strange syntax and behaviour. I still don't loose the hope to derive some degree of use from this construction. But my hope becomes less day by day.
I need to reserve space for future structures and i tried to declare "istruc" in .bss section. The code looks like following:

Code: [Select]
struc mytype
  .data: resb 1
endstruc

section .bss

mystruc:
    istruc mytype
    iend

On compilation I get the following warning: attempt to initialize memory in a nobits section: ignored.
This warning is not covered by "-w" scope. So I can't disable it. Or can? Anyway just disabling the warning is not the best solution.

By the way. The documentation must be fixed because in paragraph 4.11.11 it is used exactly the form that will not compile:
Code: [Select]
mystruc:
    istruc mytype
at mt_long, dd 123456
at mt_word, dw 1024
at mt_byte, db 'x'
at mt_str,  db 'hello, world', 13, 10, 0
    iend

If you can think of how this might be more clearly documented - help us out!
I'd be glad, but something tells me that the behaviour of this mechanism should be reworked before. I think that the best way is to move structures from "macro" to internal mechanism. This will open the broad way to enhance and to "polish" them.

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: "istruc" inside macro
« Reply #7 on: February 27, 2010, 09:47:49 PM »
I need to reserve space for future structures and i tried to declare "istruc" in .bss section.

In there lies your problem. istruc is used to declare an instance of a structure. Trying to initialize data in a .bss (uninitialized data section) should fail with a warning at best.

Uninitialized or dynamic (runtime allocated) memory needs to utilize pointer references.

By the way. The documentation must be fixed because in paragraph 4.11.11 it is used exactly the form that will not compile:
Code: [Select]
mystruc:
    istruc mytype
at mt_long, dd 123456
at mt_word, dw 1024
at mt_byte, db 'x'
at mt_str,  db 'hello, world', 13, 10, 0
    iend


I find that NASM does exactly what is documented in this case. The following "readable" code example demonstrates how to properly utilize initialized and uninitialized structs in NASM.



Code: [Select]
struc   mytype

  mt_long:      resd    1
  mt_word:      resw    1
  mt_byte:      resb    1
  mt_str:       resb    32

endstruc


[section .text]

;Access Initialized Struct
lea ebx,[mystruc]
mov eax,DWORD[ebx + mt_long]
mov cx,WORD[ebx + mt_word]
mov dl,BYTE[ebx + mt_byte]
lea esi,[ebx + mt_str]

;Populate Uninitialized Struct
lea ebx,[mystruc2]
mov DWORD[ebx + mt_long],eax
mov WORD[ebx + mt_word],cx
mov BYTE[ebx + mt_byte],dl
lea edi,[ebx + mt_str]

;Copy Initialized String to Uninitialized Struct
COPY:
mov bl,BYTE[esi]
cmp bl,0
je DONE
mov BYTE[edi],bl
inc esi
inc edi
jmp COPY
DONE:
ret

[section .data]

mystruc:
    istruc mytype
at mt_long, dd 123456
at mt_word, dw 1024
at mt_byte, db 'x'
at mt_str,  db 'hello, world', 13, 10, 0
    iend


[section .bss]

mystruc2: RESB mytype_size



You'll find that the way NASM implements structs may be more verbose, but I would expect no less access/control from an assembler. You can always use macros to abstract away if you need.

Offline Serge

  • Jr. Member
  • *
  • Posts: 26
  • Country: ru
Re: Error when using "istruc"
« Reply #8 on: February 27, 2010, 10:44:48 PM »
Oh, yes, I'm so sorry... I didn't read these two sections carefully enough and didn't see the clue - '_size' suffix that allows to declare uninitialized structures. This is due to lack of experience with NASM.
Thank you for your patience. Went to try to code my task...

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Error when using "istruc"
« Reply #9 on: February 27, 2010, 11:16:38 PM »
Oh, yes, I'm so sorry... I didn't read these two sections carefully enough and didn't see the clue - '_size' suffix that allows to declare uninitialized structures. This is due to lack of experience with NASM.
Thank you for your patience. Went to try to code my task...

Well, I think that qualifies for Frank's "If you can think of how this might be more clearly documented - help us out!" statement :)

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Error when using "istruc"
« Reply #10 on: February 27, 2010, 11:24:31 PM »
I don't really advise it, but if you want to play around with doing some structure emulation or enhancement stuff inside macros you might want to go to the source. STRUC/ISTRUC are little more than a bit of ABSOLUTE magic. For example, here is a structure:

Code: [Select]
[ABSOLUTE 0]
mytype:
.long resd 1
.short resw 1
.byte resb 1
mytype_size equ ($-mytype)
%ifdef __SECT__
__SECT__
%endif

Now we can create an instance of our structure:

Code: [Select]
SECTION .bss
mystruct: RESB mytype_size

And then use our structure somewhere in our code:

Code: [Select]
SECTION .text
...
    Xor Eax, Eax
    Mov [mystruct + mytype.long], Eax
    Inc Eax
    Mov [mystruct + mytype.short], Ax
    Inc Eax
    Mov [mystruct + mytype.byte], Al
...

Not bad huh. That's all STRUC's are really doing. We can even do union simulation with ABSOLUTE as well. Check out this snippet.

Code: [Select]
%imacro CODESEG 0
%if __BITS__ < 32
SEGMENT .text
%else
SECTION .text
%endif
%endm

%imacro DATASEG 0
%if __BITS__ < 32
SEGMENT .data
%else
SECTION .data
%endif
%endm

%imacro STACKSEG 0
%if __BITS__ < 32
SEGMENT .bss
%else
SECTION .bss
%endif
%ENDM

%imacro STRUCT 1-2 0
%push __STRUCT__
%define %$name %1
[ABSOLUTE %2]
%{$name}:
%endm

%imacro UNION 1-2 0
%push __UNION__
%define %$name %1
%assign %$base %2
%assign %$max 0
[ABSOLUTE %{$base}]
%{$name}:
%endm

%imacro SET 1+
%ifctx __STRUCT__
. %+ %1
%elifctx __UNION__
[ABSOLUTE %{$base}]
. %+ %1
%if %$max < ($-%{$name})
%assign %$max ($-%{$name})
%endif
%else
%1
%endif
%endm

%imacro ENDS 0
%ifctx __UNION__
%{$name}_size   EQU %$max
%pop
%elifctx __STRUCT__
%{$name}_size   EQU ($-%{$name})
%pop
%else
%define __SECT__ [SECTION .data]
%endif
%ifdef __SECT__
__SECT__
%endif
%endm

That's from my old BKMACROS.ASM that used to float around ASM Community back before NASM32 was written. It's not the prettiest implementation of unions/structures but it does handle the issue of calculating the union '_size' value based on a %$max variable. Take your time looking over it, it should give you some insight into how structures/unions are implemented on a deeper level as I'm seeing you trying to implement macro wrappers with them.

Regards,
Bryant Keller

About Bryant Keller
bkeller@about.me