2

While searching for this error I found this question, but was not exactly my issue. After a while I figured out the problem and posted another answer in that question, but following the advice of @ecm, I decided to make a different question.

My problem was that some time ago I declared a nasm struc like this (Note that there is no .b):

struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .c:    resd 1
endstruc

And after some time I added a .b member:

struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .b:    resd 1
    .c:    resd 1
endstruc

But forgot to edit the actual use of the structure with istruc in another file:

section .bss
    first_ctx:
        istruc ctx_t
            at ctx_t.next, resd 1
            at ctx_t.prev, resd 1
            at ctx_t.a,    resd 1
            ; Missing b!
            at ctx_t.c,    resd 1
        iend

And the assembler was giving me these warnings (all on the ctx_t.c line):

src/file.asm:8: warning: attempt to initialize memory in BSS section `.bss': ignored [-w+other]
src/file.asm:8: warning: attempt to initialize memory in BSS section `.bss': ignored [-w+other]
src/file.asm:8: warning: attempt to initialize memory in BSS section `.bss': ignored [-w+other]
src/file.asm:8: warning: attempt to initialize memory in BSS section `.bss': ignored [-w+other]

Question: Why does this warning occur? Why four times? And how can it be avoided?

ecm
  • 2,583
  • 4
  • 21
  • 29
trxgnyp1
  • 317
  • 1
  • 10

2 Answers2

2

Here are some more solutions. First, a test case that reproduces your original problem (in one file that can be assembled as is):

struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .b:    resd 1
    .c:    resd 1
endstruc

section .bss
    first_ctx:
        istruc ctx_t
            at ctx_t.next, resd 1
            at ctx_t.prev, resd 1
            at ctx_t.a,    resd 1
            ; Missing b!
            at ctx_t.c,    resd 1
        iend

    resb 16

Then, my first solution. We use separate multi-line macros (mmacros) specialised for use in nobits sections, named bss_istruc and friends. (The bss_istruc mmacro itself is just an exact copy of NASM's istruc, but it is consistent to define it along the other two mmacros here.) This is the only solution that requires changes to your code, not just adding some macros.


%imacro bss_istruc 1.nolist
    %push
        %define %$strucname %1
        %$strucstart:
%endmacro

%imacro bss_at 1-2+.nolist
    %defstr %$member %1
    %substr %$member1 %$member 1
    %ifidn %$member1, '.'
        resb (%$strucname%1-%$strucname)-($-%$strucstart)
    %else
        resb (%1-%$strucname)-($-%$strucstart)
    %endif
    %2
%endmacro

%imacro bss_iend 0.nolist
        resb %{$strucname}_size-($-%$strucstart)
    %pop
%endmacro


struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .b:    resd 1
    .c:    resd 1
endstruc

section .bss
    first_ctx:
        bss_istruc ctx_t
            bss_at ctx_t.next, resd 1
            bss_at ctx_t.prev, resd 1
            bss_at ctx_t.a,    resd 1
            ; Missing b!
            bss_at ctx_t.c,    resd 1
        bss_iend

    resb 16

Next, my second solution. We undefine NASM's original istruc and friends and replace them by mmacros that check for the .bss section, by name, and will use resb 1 when it is detected, and otherwise db 0. Obviously, if you use nobits sections other than the one named .bss, you would have to modify the detection to make it work.

It also expects that the mmacros are only used after plain section .bss or segment .bss directives. If you want to specify section attributes (eg follows=, align=, etc), then you need to subsequently add another section directive that names only the section name without attributes. (This is good form anyway, as use of the __SECT__ macro will warn if your last section directive included attributes.)


%unimacro istruc 1.nolist
%unimacro at 1-2+.nolist
%unimacro iend 0.nolist

%imacro istruc 1.nolist
    %push
        %define %$strucname %1
        %$strucstart:
 %ifidni __SECT__, [section .bss]
    %define %$reservespace resb 1
 %elifidni __SECT__, [segment .bss]
    %define %$reservespace resb 1
 %else
    %define %$reservespace db 0
 %endif
%endmacro

%imacro at 1-2+.nolist
    %defstr %$member %1
    %substr %$member1 %$member 1
    %ifidn %$member1, '.'
        times (%$strucname%1-%$strucname)-($-%$strucstart) %$reservespace
    %else
        times (%1-%$strucname)-($-%$strucstart) %$reservespace
    %endif
    %2
%endmacro

%imacro iend 0.nolist
        times %{$strucname}_size-($-%$strucstart) %$reservespace
    %pop
%endmacro


struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .b:    resd 1
    .c:    resd 1
endstruc

section .bss
    first_ctx:
        istruc ctx_t
            at ctx_t.next, resd 1
            at ctx_t.prev, resd 1
            at ctx_t.a,    resd 1
            ; Missing b!
            at ctx_t.c,    resd 1
        iend

    resb 16

Next, a solution that does not work. The idea is to replace the use of db 0 in the mmacros by a macro that will expand to a number of resb directives. This does not work because times is an assembler directive, not a preprocessor directive, so the db 0 is never evaluated as an mmacro. Reproduced here for posterity.


struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .b:    resd 1
    .c:    resd 1
endstruc

section .bss
    first_ctx:

%imacro resb_for_every 1-*.nolist
 %rep %0
  %ifstr %1
   %strlen %%length %1
    resb %%length
  %else
    resb 1
  %endif
  %rotate 1
 %endrep
%endmacro

%idefine db resb_for_every

        istruc ctx_t
            at ctx_t.next, resd 1
            at ctx_t.prev, resd 1
            at ctx_t.a,    resd 1
            ; Missing b!
            at ctx_t.c,    resd 1
        iend

%undef db

    resb 16

Next, a revision of the above which makes it work, by using only a single-line macro (smacro) definition for the db. This is a super hack solution, but it does work if you take care to only ever replace db 0 using this trick. (ETA: Modified slightly to allow any db with a single number to work.)


struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .b:    resd 1
    .c:    resd 1
endstruc

section .bss
    first_ctx:

%idefine db resb 1 + 0 *

        istruc ctx_t
            at ctx_t.next, resd 1
            at ctx_t.prev, resd 1
            at ctx_t.a,    resd 1
            ; Missing b!
            at ctx_t.c,    resd 1
        iend

%undef db

    resb 16

Finally, another take on the non-working solution: Instead of the db directive, we replace the times directive by a special mmacro. This mmacro will check for a db 0 string at the end of its parameter, making it safer than the prior hack.

struc ctx_t
    .next: resd 1
    .prev: resd 1
    .a:    resd 1
    .b:    resd 1
    .c:    resd 1
endstruc

section .bss
    first_ctx:

%imacro times_resb 1+.nolist
 %defstr %%our_string %1
 %strlen %%our_string_length %%our_string
 %substr %%our_db_0 %%our_string %%our_string_length + 1 - 5,-1
 %ifidni %%our_db_0, " db 0"
  %substr %%our_number_string %%our_string 1,-6
  %deftok %%our_number_token %%our_number_string
    resb %%our_number_token
 %else
  %error Unexpected use of times_resb macro: %%our_string %%our_db_0
 %endif
%endmacro

%idefine times times_resb

        istruc ctx_t
            at ctx_t.next, resd 1
            at ctx_t.prev, resd 1
            at ctx_t.a,    resd 1
            ; Missing b!
            at ctx_t.c,    resd 1
        iend

%undef times

    resb 16
ecm
  • 2,583
  • 4
  • 21
  • 29
1

Adding the missing at ctx_t.b, resd 1 fixed it, so I didn't think much of the errors until @ecm answered and explained why.

Turns out that by not reserving the bytes myself, the assembler declares a zero byte N times (size of the member): Link.

So in this case, because .b was a dword, it was declaring 4 bytes as 0 using times 4 db 0. Obviously, the .bss section is not the right place for declaring bytes (since it's a nobits section, unlike, for example, .text which is progbits).

The solution would be to either add the resd for the missing member, or move the istruc to a progbits section (and obviously replace the resd's).

That's the reason why the compiler was not only giving a warning, but 4 (one for each db 0)

trxgnyp1
  • 317
  • 1
  • 10