只有 EAX 的低半部分归零? (MASM 使用 .486 / .model flat,stdcall)

Posted

技术标签:

【中文标题】只有 EAX 的低半部分归零? (MASM 使用 .486 / .model flat,stdcall)【英文标题】:Only the low half of EAX is zeroed? (MASM using .486 / .model flat,stdcall) 【发布时间】:2021-10-05 22:50:33 【问题描述】:

在 VS2019 中运行下面的代码,令我惊讶的是寄存器 EAX 没有被指令 xor eax, eax 归零。

_text SEGMENT
.486
.model flat,stdcall
.stack 4096

.code
main PROC
    xor eax, eax    
    ret
main ENDP
_text ENDS
END

P.S.:我期望 EAX 寄存器在指令 xor eax, eax 之后为零。在ret 指令中使用断点调试代码我可以在Registers 窗口中看到只有AX 被归零。 EAX 中的 16-31 位没有任何反应。在 x64 中,指令 xor eax, eax 正确执行,按预期将整个 RAX 寄存器归零。

【问题讨论】:

如果该指令实际执行,肯定会如此。因此,我怀疑该指令实际上并未在您的测试中执行,或者您错误地观察了 eax 中的值。您正在做哪些确切的测试来得出结论? 您能解释一下您是如何构建和运行该程序的吗?听起来好像在途中某处可能存在 16/32 位模式不匹配。 同意@Nate,这听起来像是汇编器发出了66操作数大小前缀,因为它认为指令将以16位模式执行,但实际上它以32位模式执行该前缀使其成为xor ax,ax,即非默认操作数大小。将.486 放在 .model flat,stdcall 之后有帮助吗?在其他一些 SO 答案中,我隐约记得那些对 MASM 很重要的指令的顺序。您可以查看反汇编,并尝试像push eax 这样的指令(可能只会将 ESP 更改 2)。 @PeterCordes 关于66,您也是正确的。查看指令xor ax, ax 的地址,我看到了用于指令的编码字节66 33 C0。再次,很好的答案! 我对 MASM 不是很熟悉,但我见过的其他 32 位 MASM 程序示例不包含 SEGMENT 指令。如果你把它拿出来会发生什么? 【参考方案1】:

根据您的 cmets,SEGMENT 指令似乎以某种方式说服了汇编器,它正在汇编代码以在 16 位模式下运行。

在 16 位模式下,对 32 位寄存器(如 eax)进行操作的指令需要 66 操作数大小前缀,因此汇编器发出 66 33 C0。然而,程序实际上是在 32 位模式下运行的,其中 66 操作数大小前缀的含义是相反的:32 位操作数是默认值,66 选择 16 位操作数。所以当程序运行时,指令以xor ax, ax 执行,并且没有将eax 的高位归零。

您说删除 SEGMENT 指令修复了它。我不知道它为什么会产生这种效果,但是其他 32 位 MASM 程序的例子无论如何都不包含这个指令,所以它可能根本就不应该存在。

【讨论】:

我如何确定计算机在哪种模式下运行?我相信这与@Peter Cordes here 提供的链接有关,但这对我来说太高级了,无法理解。但是,例如,我想知道在给定的特定模式下我可以使用哪个指令来组装代码。我应该如何进行? 模式由可执行文件的格式和标题设置,因此您依赖汇编器和链接器(通过指令、命令行选项等)生成可执行文件,并在其中设置正确方式。我对 MASM 的了解也不够充分,无法完全解释该过程。但作为开始,我会说只是寻找 32 位或 64 位程序的示例,并在更改代码的同时使用它们的指令。我不确定现代 Windows 甚至可以在 16 位模式下运行程序,而且您可能也不想这样做。 来自 MASM 文档(强调我的):“SEGMENT 指令中的 use 类型指定了 80386/486 处理器上的段字长。段字长 确定段中所有项的默认操作数和地址大小。如果在.MODEL 指令之前指定.386.486 指令,则USE32 是默认值”。由于 OP 在 .486/.model 之前放置了 SEGMENT 指令并且没有指定 size 属性,这可能给了该段一个 USE16 属性。 无论如何,我不确定何时需要在平面模型程序中使用SEGMENT 指令。你已经得到了简化的段指令(.code.data.data? 等),这应该足够了。 @Michael 我在当前的 Microsoft Macro Assembler Reference.pdf 中找不到您提到的 above 的任何内容。

以上是关于只有 EAX 的低半部分归零? (MASM 使用 .486 / .model flat,stdcall)的主要内容,如果未能解决你的问题,请参考以下文章

带 masm 的寄存器 edx::eax 中的 mul 和内存分配

如果只需要结果的低部分,哪些 2 的补码整数运算可以在不将输入中的高位归零的情况下使用?

如何连接两个 SSE 寄存器的低半部分?

MASM:取消引用结构指针两次?

使用 MASM32 随机化装配中的数字

在保护模式下无法访问 32 位