这里还有一些解决方案。首先,一个重现原始问题的测试用例(在一个可以按原样组装的文件中):
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
然后,我的第一个解决方案。我们使用单独的多行宏(mmacros)专门用于nobits
部分,命名为bss_istruc
和朋友。 (这bss_istruc
宏本身只是 NASM 的精确副本istruc
,但与此处的其他两个 mmmacros 一起定义它是一致的。)这是唯一需要更改代码的解决方案,而不仅仅是添加一些宏。
%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
接下来是我的第二个解决方案。我们取消了 NASM 的原始定义istruc
和朋友,并用检查的 mmacros 替换它们.bss
部分,按名称,并将使用resb 1
当它被检测到时,否则db 0
。显然,如果你使用nobits
除了指定的部分之外的其他部分.bss
,您必须修改检测才能使其工作。
它还期望 mmmacros 仅在普通之后使用section .bss
or segment .bss
指令。如果您想指定部分属性(例如follows=
, align=
等),那么您需要随后添加另一个section
仅命名不带属性的节名称的指令。 (无论如何,这是一个很好的形式,因为使用__SECT__
宏会警告您是否最后一次section
指令包含属性。)
%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
接下来,一个解决方案not work。这个想法是替换使用db 0
在 mmacros 中,通过一个宏将扩展为多个resb
指令。这不起作用,因为times
是汇编器指令,而不是预处理器指令,因此db 0
从未被评估为 mmmacro。谨在此转载,供后人参考。
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
接下来,对上述内容进行修订,通过使用only单行宏 (smacro) 定义db
。这是一个超级黑客解决方案,但如果你注意只替换它,它确实有效db 0
使用这个技巧。 (ETA:稍微修改以允许任何db
只需一个号码即可工作。)
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
最后,另一种非工作解决方案:db
指令,我们替换times
由特殊的宏指令。该宏将检查 db 0
字符串位于其参数末尾,使其比之前的黑客更安全。
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