assembly - intVal3 TBYTE 1234 -- 汇编器没有注意到无效的 TBYTE 变量声明

标签 assembly x86 masm

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

在书中,作者说

MASM uses the TBYTE directive to declare packed BCD variables. Constant initializers must be in hexadecimal because the assembler does not automatically translate decimal initializers to BCD. The following two examples demonstrate both valid and invalid ways of representing decimal -1234:

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

The reason the second example is invalid is that MASM encodes the constant as a binary integer rather than a packed BCD integer.



我知道 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 的建议检查了列表文件,这是一个屏幕截图

enter image description here

从列表文件中的结果和@PaulH 所说的来看,我得出了以下结论(虽然不确定完全正确):

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

最佳答案

TBYTE 的存在理由type 是具有与 x87 FPU 的内部寄存器相同宽度的东西,这意味着它可用于将这些寄存器之一的内容溢出到内存中而不会丢失任何精度。

通常,当您将浮点值保存在内存中时,您可以将其表示为单精度(32 位; DWORD )或 double (64 位; QWORD )值。这很好,只是它失去了精度。如果您想在计算期间溢出一个临时中间值,那么您通常无法通过截断该值而损失精度,因为这会影响最终结果。

姓名 TBYTE只是意味着这种类型的值是 10 字节宽——与 is used internally for floating-point values on the x87 的宽度相同. (默认情况下,至少,假设您没有降低 FPU 的精度。)

所以,TBYTE实际上与二进制编码的十进制 (BCD) 没有本质的关系。我不知道 Kip Irvine 在那里谈论什么。您当然可以将 BCD 值存储在 TBYTE 中。 ,但您也可以将较小的 BCD 值存储在 QWORD 中。或 DWORD .顾名思义,BCD只是一种允许您以二进制形式存储十进制数字的编码。

之所以

intVal3 TBYTE -1234

compiles assembles 是因为,对于汇编程序 (MASM),您所做的只是声明一个初始化为 -1234 的 10 字节值。 .它隐式扩展 -1234填充 10 个字节,得到值 0xFFFFFFFFFFFFFFFFFB2E ,正如您在十六进制转储中看到的那样。 -1234h 也是一样,除了 h表示该值被解释为十六进制,而不是十进制。

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

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

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

In the end, it doesn't matter how you specify the memory content in the source, … the code which operates upon that memory defines its "meaning" (type).



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

Peter Cordes 指出(见评论)x87 FPU 确实具有用于加载和存储 BCD 值的指令: FBLD FBSTP .这些 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 上,如最初的 Pentium (P5) 和 Pentium II (P6),这些指令也需要大约 150 个时钟周期。在较新的 CPU 上,它们变得更慢(Skylake 每 266 个周期的吞吐量为 1 FBSTP)。因此,即使您确实想使用 80 位 BCD 值,最好还是自己写出必要的指令。 (如果您需要帮助,请提出一个新问题。)

关于assembly - intVal3 TBYTE 1234 -- 汇编器没有注意到无效的 TBYTE 变量声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44793261/

相关文章:

arrays - 如何在ARM汇编中转置矩阵

case 值为reinterpret_cast(string) 的 C++ switch 语句

assembly - 用于在第二阶段引导实模式代码的旧版 BIOS 引导加载程序

汇编语言新行

string - 在 MASM 中使用汇编代码替换字符串中的字符

assembly - ASM:MASM,NASM,FASM?

assembly - 为什么 NASM 计划分为 3 个部分?

assembly - 如果不添加 start : and end start in EMU8086? 会发生什么

linux - NASM x86-32 Linux,从文件描述符访问特定字节

assembly - 8086多处理有什么标准吗?