istruc 使用结构时出错 "non-constant argument supplied to TIMES"

Error "non-constant argument supplied to TIMES" from istruc use of a structure

我最近开始备份我的项目,但在编译我的 nasm 程序时出现错误。我正在使用 nasm 2.15.05 并在 DOSBox 中编译,我也在 VirtualBox 中尝试过 FreeDOS,但我怀疑它与环境无关。产生的错误是:

non-constant argument supplied to TIMES.

我没有在源文件中使用 times,这让我很困惑,但我查看了清单,它是 istruc 宏。这是列表文件中的相关块:

     0                              <1> times %$strucname_size-($-%$strucstart) db 0
     0 00000066 <len 1>             <1>  ;;; times COORD_size-($-..@39.strucstart) db 0
     0          ******************  <1>  error: non-constant argument supplied to TIMES

这里是结构的来源:

    struc COORD
    .TopLeft:                   resw    2
    .BottomRight:               resw    2
    endstruc

下面是结构的实现:

section data
.draw_data:
    istruc  COORD
        at COORD.TopLeft,           dw  10, 20
        at COORD.BottomRight,       dw  50, 150
    iend

如有任何帮助,我们将不胜感激。我确实看到另一个 post 关于相同的错误,但这是由我在这种情况下看不到的区分大小写问题引起的。

此错误是由于在 istruc 宏使用后定义 struc 结构引起的。

首先,查看此测试以了解它在使用您的示例时如何正常工作,strucistruc 使用之前出现在源代码中:

$ nasm -v
NASM version 2.15.03 compiled on Dec 28 2020
$ cat testpass.asm

struc COORD
 .TopLeft:      resw 2
 .BottomRight:  resw 2
endstruc

section data
.draw_data:
istruc COORD
 at COORD.TopLeft,      dw 10, 20
 at COORD.BottomRight,  dw 50, 150
iend

$ nasm testpass.asm
$

接下来,如果我们交换两个代码块,我们就可以重现您的错误:

$ cat testfail.asm

section data
.draw_data:
istruc COORD
 at COORD.TopLeft,      dw 10, 20
 at COORD.BottomRight,  dw 50, 150
iend

struc COORD
 .TopLeft:      resw 2
 .BottomRight:  resw 2
endstruc

$ nasm testfail.asm
testfail.asm:7: error: non-constant argument supplied to TIMES
$

此外,让我们看一下列表文件。最近 NASM 提供了 -Lp 开关,即使在出现错误的情况下也能保留列表文件。使用这个,结果是这样的:

$ nasm testfail.asm -l testfail.lst -Lp
testfail.asm:7: error: non-constant argument supplied to TIMES
$ cat testfail.lst
     1
     2                                  section data
     3                                  .draw_data:
     4                                  istruc COORD
     5 00000000 <len 4h>                 at COORD.TopLeft,      dw 10, 20
     6 00000004 <len 4h>                 at COORD.BottomRight,  dw 50, 150
     6          ******************       error: TIMES value -4 is negative
     7 00000008 <len 1h>                iend
     7          ******************       error: non-constant argument supplied to TIMES
     8
     9                                  struc COORD
    10 00000000 <len 4h>                 .TopLeft:      resw 2
    11 00000004 <len 4h>                 .BottomRight:  resw 2
    12                                  endstruc
    13
$

我们可以看到实际上有两个错误。但是,“non-constant”错误似乎优先于“负数”错误。让我们看看 istruc 宏扩展成什么:

$ nasm testfail.asm -E > efail.asm
$ nasm efail.asm -l efail.lst -Lp
testfail.asm:8: error: non-constant argument supplied to TIMES
$ cat efail.lst
     1                                  %line 2+1 testfail.asm
     3                                  [section data]
     4                                  .draw_data:
     5                                  ..@2.strucstart:
     6                                  times (COORD.TopLeft-COORD)-($-..@2.strucstart) db 0
     7                                  %line 5+0 testfail.asm
     5 00000000 <len 4h>                dw 10, 20
     5                                  %line 6+1 testfail.asm
     7                                  times (COORD.BottomRight-COORD)-($-..@2.strucstart) db 0
     7          ******************       error: TIMES value -4 is negative
     8                                  %line 6+0 testfail.asm
     6 00000004 <len 4h>                dw 50, 150
     6                                  %line 7+1 testfail.asm
     8 00000008 <len 1h>                times COORD_size-($-..@2.strucstart) db 0
     8          ******************       error: non-constant argument supplied to TIMES
     9
    10                                  [absolute 0]
    11                                  %line 9+0 testfail.asm
     9                                  COORD:
     9                                  %line 10+1 testfail.asm
    11 00000000 <len 4h>                 .TopLeft: resw 2
    12 00000004 <len 4h>                 .BottomRight: resw 2
    13                                  COORD_size equ ($-COORD)
    14                                  %line 12+0 testfail.asm
    12                                  [section data]
    12                                  %line 13+1 testfail.asm
    14
$

导致错误的 times 重复从 iend 发出,旨在将结构实例填充到结构的完整大小。 NASM 结构标签,如 NASM 中的标签一般,没有“标签大小”的概念,因此在最后一个结构字段的起始标签之后,可以保留任意数量的 space。为了纪念这个 space,无论它的大小如何,NASM 都会在一个标签中记录结构的大小,该标签的名称类似于附加了 _size 的结构。 times 指令显然希望在使用前定义 COORD_size 标签。

In the manual it says that "[t]he operand to TIMES is a critical expression", and links to the section on critical expressions:

defined to be an expression whose value is required to be computable in the first pass, and which must therefore depend only on symbols defined before it. The argument to the TIMES prefix is a critical expression.

因此,在定义之前使用 COORD_size 会使关键表达式不可计算。

深入挖掘

只是为了好玩,让我们看看当我们注释掉违规指令时会发生什么:

$ cat e2.asm
[section data]
.draw_data:
..@2.strucstart:
times (COORD.TopLeft-COORD)-($-..@2.strucstart) db 0
dw 10, 20
times (COORD.BottomRight-COORD)-($-..@2.strucstart) db 0
dw 50, 150
; times COORD_size-($-..@2.strucstart) db 0

[absolute 0]
COORD:
 .TopLeft: resw 2
 .BottomRight: resw 2
COORD_size equ ($-COORD)
[section data]
$ nasm e2.asm
$

它通过了!这是为什么? COORD.TopLeft - COORD 形式的增量似乎实际上允许出现在 times 的关键表达式中。我认为这是 NASM 实际上是 multi-pass 汇编器的产物。它(正确地)猜测增量将计算为标量数。在较早的传递中,这被评估为零,导致“TIMES value -4 is negative”错误。但是,在随后的传递中 NASM 知道 标签值并插入它们,因此不会留下任何错误。老实说,我不确定为什么 COORD_size 使用没有发生这种情况,但我认为它与 NASM 有关,但我不知道它稍后会等同于标量。

只是为了确保,这里是相同的测试,但没有注释掉有问题的指令;它像以前一样失败了:

$ cat e3.asm
[section data]
.draw_data:
..@2.strucstart:
times (COORD.TopLeft-COORD)-($-..@2.strucstart) db 0
dw 10, 20
times (COORD.BottomRight-COORD)-($-..@2.strucstart) db 0
dw 50, 150
times COORD_size-($-..@2.strucstart) db 0

[absolute 0]
COORD:
 .TopLeft: resw 2
 .BottomRight: resw 2
COORD_size equ ($-COORD)
[section data]
$ nasm e3.asm
e3.asm:8: error: non-constant argument supplied to TIMES
$

最后,在结构末尾的附加标签的帮助下,修改示例以便对大小使用增量,使所有 times 指令按预期工作:

$ cat e4.asm
[section data]
.draw_data:
..@2.strucstart:
times (COORD.TopLeft-COORD)-($-..@2.strucstart) db 0
dw 10, 20
times (COORD.BottomRight-COORD)-($-..@2.strucstart) db 0
dw 50, 150
times (COORD_end-COORD)-($-..@2.strucstart) db 0

[absolute 0]
COORD:
 .TopLeft: resw 2
 .BottomRight: resw 2
COORD_end:
COORD_size equ ($-COORD)
[section data]
$ nasm e4.asm
$