我目前正在按照Kip Irvine的“汇编语言x86编程”书来学习汇编编程。

在书中,作者指出


MASM使用TBYTE指令声明打包的BCD变量。
常量初始化程序必须为十六进制,因为汇编程序
不会自动将十进制初始化程序转换为BCD。的
以下两个示例演示了有效和无效的方式
代表十进制-1234:

intVal TBYTE 80000000000000001234h ; valid
intVal TBYTE -1234 ; invalid


第二个示例无效的原因
是MASM将常量编码为二进制整数而不是
压缩的BCD整数。


我知道MASM汇编程序无法将十进制整数转换为BCD。但是我想出了下面的代码,它们可以很好地进行编译(注意,intVal3 TBYTE 1234应该是无效的,但它就像有效的代码一样被编译)

.386
.MODEL FLAT, STDCALL
.STACK 4096
ExitProcess PROTO, dwExitCode: DWORD

.DATA
intVal1 TBYTE 800000000000001234h
intVal2 TBYTE -1234h
intVal3 TBYTE -1234      ; compiled despite being invalid

.CODE
    main PROC


invoke ExitProcess, 0
main ENDP
END main


为什么无效代码会被汇编程序忽略?这是汇编器无法检测到的错误,需要程序员提高警惕吗?

==============编辑1 =================

我已经按照@PaulH的建议检查了清单文件,这是屏幕截图

assembly - intVal3 TBYTE 1234 —汇编器未注意无效的TBYTE变量声明-LMLPHP

从清单文件中的结果以及@PaulH所说的内容来看,我得出以下结论(虽然不确定完全正确):

TBYTE类型的变量将解释简单地将参数的二进制值(无论是80000000000000001234h,-1234h或-1234)存储到该变量中。由于假定TBYTE类型的变量用作BCD整数,因此确保正确使用TBYTE类型的变量完全取决于程序员。

最佳答案

TBYTE类型的存在理由应具有与x87 FPU内部寄存器相同的宽度,这意味着它可用于将其中一个寄存器的内容溢出到内存中而不会损失任何精度。

通常,将浮点值保存在内存中时,可以将其表示为单精度(32位; DWORD)或双精度(64位; QWORD)值。很好,除了会失去精度。如果要在计算过程中溢出临时中间值,则通常无法舍弃该值,因为精度高会影响最终结果。

名称TBYTE仅表示此类型的值的宽度为10个字节-与is used internally for floating-point values on the x87相同。 (默认情况下,至少,假设您没有降低FPU的精度。)

因此,TBYTE实际上与二进制编码的十进制(BCD)无关。我不知道基普·欧文(Kip Irvine)在说什么。您当然可以将BCD值存储在TBYTE中,但是也可以将较小的BCD值存储在QWORDDWORD中。顾名思义,BCD只是一种编码,允许您以二进制形式存储十进制数字。

之所以

intVal3 TBYTE -1234


之所以进行汇编,是因为,对于汇编器(MASM),您所做的只是声明一个初始化为-1234的10字节值。如十六进制转储所示,它隐式扩展了-1234以填充10个字节,从而产生值0xFFFFFFFFFFFFFFFFFB2E。与-1234h相同,不同之处在于h表示将值解释为十六进制而不是十进制。

请注意,如果您这样做,基本上会发生相同的事情

myValue QWORD -1234


因为汇编程序将-1234扩展为8个字节长。

正如Ped7g在评论中所说,使用汇编语言进行编程时首先要记住的是:


最后,在源中指定存储内容的方式都没有关系,……在该存储上运行的代码定义了其“含义”(类型)。


汇编器仅存储字节。使用TBYTE,它将存储10个。使用QWORD,它将存储其中的8个。使用DWORD,它将存储其中的4个。您得到图片。您的代码如何解释这些字节取决于您,因为您必须编写该代码。



Peter Cordes指出(请参阅注释),x87 FPU确实具有用于加载和存储BCD值的指令:FBLDFBSTP。这些can be used as a slow way to turn a binary integer into decimal digits

这两个指令都将m80bcd值用作其唯一的操作数,这是一个80位的BCD值,其长度与TYBTE相同。因此,Kip Irvine可能正在谈论TBYTE值的这种用法。

但是,我不相信MASM会将TBYTE初始值设定项隐式转换为BCD格式,因为如上所述,当您使用TBYTE存储扩展精度浮点值时,这将非常不便。使用MASM或任何其他汇编程序,您仍然可以自己将分配给TBYTE的值适当地表示为BCD或浮点数,无论您想要哪个。

而且,既然您已经听说过FBLDFBSTP,您几乎可以再次忘记它们。我认为它们从来都不是很常用的,并且现在肯定没有任何用处。即使在较旧的CPU(例如原始奔腾(P5)和奔腾II(P6))上,这些指令也要花费约150个时钟周期。在较新的CPU上,它们的运行速度甚至更慢(Skylake每266个周期的吞吐量为1 FBSTP)。因此,即使您确实想使用80位BCD值,也最好自己编写必要的指令。 (如果需要帮助,请询问一个新问题。)

10-04 11:08