assembly - 无法连续两次从变量中输出协处理器浮点数
问题描述
下午好!在这个例子中,我只是用逗号添加两个数字,将变量保存在tbyte中并在屏幕上连续两次显示相同的变量,但第一次得到11.1,应该是这样,第二次得到 4.667261 E-062。为什么会这样?
还有一个问题,是否可以在tbyte中以某种方式按数组类型保存和访问数字?例如,将数字存储在dd中,我只能以 4 为增量保存和读取它们,例如 ,result [0]
等result [4]
。是否可以将其与tbyte一起使用以及如何使用?如果我理解正确 - 它应该是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
解决方案
你为什么要把fstp qword
( double
) 变成 tbyte ( long double
)?
哦,这可能是你的错误。大概invoke
宏为每个result
宏参数推送 12 个字节。(因为一个 10 字节tbyte
填充到 4 字节堆栈槽的倍数是 12)。
但是您的格式字符串仅告诉 sprintf 查找double
8 个字节宽的 args。由于您只将 qword 存储double
到 的低 8 个字节result
,crt_sprintf
因此可以正确地将第一个可变参数 arg 读取为double
. (x86 是 little-endian,因此低 8 个字节位于 sprintf 正在查看的堆栈地址。)
但是第二次转换将在前一个 arg 结束后%G
立即寻找另一个转换。double
根据格式字符串应该是8个字节之后。 但是您invoke
实际推送的内容与此不符。所以第二个%G
读取与两个 12 字节推送重叠的 8 个字节。
它可能0
在高 4 个字节(包括指数和符号位)中,并且仅在尾数的低 31 位中非零,给你一个非常小的次正常数。您可以使用调试器将内存作为 a 进行检查,double
并查看它是否代表 sprintf 读取的值。
如果 long double
在那个 C 库中是 10 字节 x87 类型,请使用%LG
并使用fstp tbyte
.
如果sizeof(long double)
只有 8,那么它double
与您不能使用该 C 库 printf x87 tbyte 值相同。(除非它有一些非标准的扩展。) 在这种情况下,您只需更改result
为也是 a qword
,匹配您正在做的商店。
此外,您没有平衡 x87 堆栈;使用faddp
所以它在fstp
. (如果您的汇编程序需要操作数,请使用faddp st(1)
or st1
,但它喜欢拼写 x87 寄存器名称。)
通过使用非空的 x87 堆栈进行函数调用,您在技术上违反了调用约定,但显然 crt_sprintf 没有使用全部 8 个,st0..7
因此它不会从 x87 堆栈溢出中获得 NaN。
推荐阅读
- jquery - dataTable 参数在角度 6 中不起作用
- python - 将参数传递给 Python 线程时出现 TypeError
- java - Spring Boot 读取不带前缀的地图属性
- entity-framework - 使用实体框架(流利的 Api)的可选一对多关系
- c# - 如何将json响应日期字符串转换为c#日期格式?
- sql - SQL 将数据插入临时表并将结果另存为视图
- html - 如何从 Spring Boot genericResponse 方法重定向到 HTML 静态页面
- django - Fetch API 会导致 Django 中的 CSRF 错误,但不会导致 cURL?
- excel - 如何使用查找功能在列中统一值
- python - 不确定为什么异步任务在事件循环之外完成