I have recently started back up on my project and am getting an error when I compile my nasm program. I am using nasm 2.15.05 and am compiling in DOSBox, I have also tried FreeDOS in VirtualBox but I suspect it has nothing to do with the environment. The error that is produced is:
non-constant argument supplied to TIMES.
I am not using times
in the source file which threw me but I looked at the listing and it's the istruc
macro. Here is the relevant block from the listing file:
0 <1> times %$strucname_size-($-%$strucstart) db 0
0 00000066 <len 1> <1> ;;; times COORD_size-([email protected]) db 0
0 ****************** <1> error: non-constant argument supplied to TIMES
And here is the source of the structure:
struc COORD
.TopLeft: resw 2
.BottomRight: resw 2
endstruc
And here is the implementation of the structure:
section data
.draw_data:
istruc COORD
at COORD.TopLeft, dw 10, 20
at COORD.BottomRight, dw 50, 150
iend
Any help would be greatly appreciated. I did see another post about the same error but that was caused by a case-sensitivity issue which I do not see in this case.
CodePudding user response:
This error is caused by defining the struc
structure after its use by the istruc
macro.
First, look at this test to see how it works correctly when using your example, with the struc
occurring in the source before its use by istruc
:
$ 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
$
Next, we can reproduce your error if we swap the two blocks of code:
$ 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
$
Further, let's look at the listing file. Recent NASM provides the -Lp
switch to keep the listing file even in the case of errors. Use this and this is the result:
$ 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
$
We can see there's actually two errors. The "non-constant" error appears to take precedence over the "is negative" error however. Let's see what the istruc
macros expand to:
$ 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 [email protected]:
6 times (COORD.TopLeft-COORD)-([email protected]) 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)-([email protected]) 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-([email protected]) 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
$
The times
repetition causing the error is emited from iend
, and is intended to pad the instance of the structure up to the full size of the structure. NASM structure labels, like labels in NASM generally, have no concept of a "label size", so after the last structure field's start label there could be an arbitrary amount of space reserved. To honour this space, whatever its size, NASM records the size of the structure in a label named like the structure with _size
appended. The times
directive evidently wants the COORD_size
label to be defined before its use.
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.
So, using COORD_size
before it is defined makes the critical expression not be computable.
Digging deeper
Just for fun, let's look at what happens when we comment out the offending directive:
$ cat e2.asm
[section data]
.draw_data:
[email protected]:
times (COORD.TopLeft-COORD)-([email protected]) db 0
dw 10, 20
times (COORD.BottomRight-COORD)-([email protected]) db 0
dw 50, 150
; times COORD_size-([email protected]) db 0
[absolute 0]
COORD:
.TopLeft: resw 2
.BottomRight: resw 2
COORD_size equ ($-COORD)
[section data]
$ nasm e2.asm
$
It passes! Why is that? It appears that the deltas of the form COORD.TopLeft - COORD
are actually allowed in the critical expression for times
. I assume this is an artefact of NASM actually being a multi-pass assembler. It (correctly) guesses that the delta will evaluate to a scalar number. On an earlier pass, this is evaluated as zero, resulting in the "TIMES value -4 is negative" error. However, on a subsequent pass NASM knows the label values and inserts them so no error remains. I'm honestly not sure why this doesn't happen to the COORD_size
use, but I assume it is related to NASM not knowing it will be equated to a scalar number later.
Just to make sure, here's the same test with the offending directive not commented out; it fails as before:
$ cat e3.asm
[section data]
.draw_data:
[email protected]:
times (COORD.TopLeft-COORD)-([email protected]) db 0
dw 10, 20
times (COORD.BottomRight-COORD)-([email protected]) db 0
dw 50, 150
times COORD_size-([email protected]) 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
$
Finally, modifying the example so as to use a delta for the size, helped by an additional label at the end of the structure, makes all times
directives work as intended:
$ cat e4.asm
[section data]
.draw_data:
[email protected]:
times (COORD.TopLeft-COORD)-([email protected]) db 0
dw 10, 20
times (COORD.BottomRight-COORD)-([email protected]) db 0
dw 50, 150
times (COORD_end-COORD)-([email protected]) db 0
[absolute 0]
COORD:
.TopLeft: resw 2
.BottomRight: resw 2
COORD_end:
COORD_size equ ($-COORD)
[section data]
$ nasm e4.asm
$