我目前正在学习汇编编程,遵循Kip Irvine的"汇编语言x86编程"一书.
在书中,作者说
MASM使用TBYTE指令声明打包的BCD变量.常量初始值设定项必须为十六进制,因为汇编程序不会自动将十进制初始值设定项转换为BCD.以下两个示例演示了表示十进制-1234的有效和无效方式:
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)
为什么汇编程序没有注意到无效代码?这是汇编程序无法检测到的错误,需要程序员保持警惕吗?
=============== 编辑1 =================
我按照@PaulH的建议检查了列表文件,这是一个截图
从列表文件的结果和@PaulH所说的结果来看,我得出了以下结论(尽管不确定完全正确):
TBYTE类型的变量将解释简单存储参数的二进制值(无论是80000000000000001234h,-1234h还是-1234)到变量中.因为TBYTE类型的变量被认为是用作BCD整数,所以完全由程序员来确保TBYTE类型的变量被正确使用.
该TBYTE类型的存在理由是具有与x87 FPU的内部寄存器相同的宽度,这意味着它可以用于将其中一个寄存器的内容溢出到存储器而不会丢失任何精度.
通常,在内存中保存浮点值时,可以将其表示为单精度(32位; DWORD)或双精度(64位; QWORD)值.这很好,除了它失去精确度.如果要在计算期间溢出临时中间值,则通常不能通过截断值来降低精度,因为这会影响最终结果.
该名称TBYTE仅表示此类型的值为10字节宽 - 与x87上的浮点值内部使用的宽度相同.(默认情况下,至少假设您没有降低FPU的精度.)
因此,TBYTE二进制编码的十进制(BCD)实际上没有任何内在联系.我不知道Kip Irvine在那里谈论什么.您当然可以将BCD值存储在a中TBYTE,但您也可以在a QWORD或中存储较小的BCD值DWORD.顾名思义,BCD只是一种编码,允许您以二进制形式存储十进制数字.
之所以
intVal3 TBYTE -1234
Run Code Online (Sandbox Code Playgroud)
compiles assembles是因为,对于汇编程序(MASM),你所做的就是声明一个初始化为10字节的值-1234.它隐式扩展-1234为填充10个字节,从而产生值0xFFFFFFFFFFFFFFFFFB2E,如在十六进制转储中看到的那样.同样的事情-1234h,除了h意味着值被解释为十六进制,而不是十进制.
请注意,如果你这样做,这基本上是相同的
myValue QWORD -1234
Run Code Online (Sandbox Code Playgroud)
因为汇编程序将扩展-1234为8个字节长.
正如Ped7g在评论中所说的那样,在使用汇编语言进行编程时,首先要记住的是:
最后,如何在源中指定内存内容无关紧要......操作该内存的代码定义其"含义"(类型).
汇编程序只存储字节.随着TBYTE,它存储了10个.随着QWORD,它存储了其中的8个.随着DWORD,它存储了其中4个.你得到了照片.您的代码如何解释这些字节取决于您,因为您必须编写该代码.
Peter Cordes指出(见注释)x87 FPU确实有用于加载和存储BCD值的指令:FBLD和FBSTP.这些可以用作将二进制整数转换为十进制数字的慢速方法.
这两条指令都将m80bcd值作为唯一的操作数,这是一个80位的BCD值,其长度与a相同TYBTE.因此,Kip Irvine 有可能正在谈论这种用途TBYTE.
但是,我不认为MASM隐式地将TBYTE初始化器转换为BCD格式,因为当您用于存储扩展精度浮点值时,这将非常不方便TBYTE,如上所述.使用MASM或任何其他汇编程序,您仍然可以自己表示分配给TBYTE适当的BCD或浮点值,无论您想要哪个.
反正,现在你听说过FBLD和FBSTP,你几乎可以再次忘记他们.我不认为它们是非常常用的,现在它们肯定没有任何用处.即使在较旧的CPU上,如原始的Pentium(P5)和Pentium II(P6),这些指令也需要大约150个时钟周期.在较新的CPU上,它们变得更慢(Skylake的吞吐量为FBSTP每266个周期1 个).因此,即使你确实想要使用80位BCD值,你最好自己写出必要的指令.(如果你需要帮助,可以提出一个新的问题.)