问题
Good afternoon! In this example, I simply add two numbers with a comma, save the variable in tbyte and display the same variable two times in a row on the screen, but the first time I get 11.1, as it should be, and the second time 4.667261E-062. Why is this happening?
And one more question, is it possible in tbyte to somehow save and access numbers by array type? for example, storing numbers in dd, I just could save and read them in increments of 4, for example, result [0]
, result [4]
, etc. Is it possible to use the same with tbyte and how? If I understand right - it should be a step of 10.
.386
.model flat,stdcall
option casemap:none
include \masm32\include\masm32rt.inc
.data
titletext db 'Title',0
frmt db 'Result1 = %.7G',10
db 'Result2 = %.7G',0
buff db 1024 dup (?)
result tbyte ?
num1 qword 5.5
num2 qword 5.6
.code
start:
finit
fld qword ptr [num1]
fld qword ptr [num2]
fadd
fstp qword ptr [result]
invoke crt_sprintf,addr buff,addr frmt, result, result
invoke MessageBox,0,addr buff,addr titletext,MB_OK
invoke ExitProcess,0
end start
回答1:
Why are you doing a fstp qword
(double
) into a tbyte (long double
)?
Oh, that's probably your bug. Presumably the invoke
macro pushes 12 bytes for each of the result
macro args. (Because a 10-byte tbyte
padded to a multiple of 4-byte stack slots is 12).
But your format string only tells sprintf to look for double
args, which are 8 bytes wide. Since you only stored a qword double
to the low 8 bytes of result
, crt_sprintf
can correctly read the first variadic arg as a double
. (x86 is little-endian so the low 8 bytes are at the stack address sprintf is looking at.)
But the 2nd %G
conversion will be looking for another double
right after the end of the previous arg. Which according to the format string should be 8 bytes later. But what your invoke
actually pushed didn't match that. So the 2nd %G
reads 8 bytes that overlap the two 12-byte pushes.
It's probably 0
in the upper 4 bytes (including exponent and sign bit), and non-zero only in the low 31 bits of the mantissa, giving you a very small subnormal number. You can use a debugger to examine memory as a double
and see that it represents the value sprintf read.
If long double
in that C library is the 10 byte x87 type, use %LG
and use fstp tbyte
.
If sizeof(long double)
is only 8, then it's the same as double
and you can't printf x87 tbyte values with that C library. (Unless it has some non-standard extension for it.) In that case You just change result
to also be a qword
, matching the store you're doing.
Also, you didn't balance the x87 stack; use faddp so it's empty after the fstp
. (If your assembler requires an operand, use faddp st(1)
or st1
, however it likes to spell x87 register names.)
You're technically violating the calling convention by making a function call with the x87 stack non-empty, but apparently crt_sprintf doesn't use all 8 of st0..7
so it doesn't get a NaN from overflowing the x87 stack.
来源:https://stackoverflow.com/questions/60887371/cant-output-coprocessor-float-from-variable-two-times-in-a-row