汇编程序是否应该不满足我对 ret imm16 的请求?

Should the assembler not honor my request for ret imm16?

我明白 ret imm16 (C2 imm16) 操作数为零的指令与无操作数的 ret (C3) 没有什么不同在其效果中。但是,当我明确给出 assembler ret 0 时,由于我明确提供了操作数,它不应该将其编码为 ret imm16 指令吗?

如果我 assemble 下面的代码与 VS2019 附带的 ml.exe 版本和命令 ml file.asm /link /SUBSYSTEM:CONSOLE /ENTRY:stdMain

.386
.MODEL FLAT, STDCALL
.CODE
        stdMain PROC
                xor eax, eax
                ret 0
        stdMain ENDP
END

然后用 disassembler 打开可执行文件,我看到为 ret 编码的指令是 C3:

  00401000: 33 C0              xor         eax,eax
  00401002: C3                 ret

我可以通过硬编码字节来手动执行 C2 指令:

.386
.MODEL FLAT, STDCALL
.CODE
    stdMain PROC
        xor eax, eax
        db 0c2h, 00, 00
    stdMain ENDP
END

现在我在 disassembled 输出中看到 C2 指令:

  00401000: 33 C0              xor         eax,eax
  00401002: C2 00 00           ret         0

这样 assembler 到 'optimize' 是正确的吗?

您不需要 3 行单独的 db 行;一个有 3 个操作数的 db 等价于:

db  0c2h, 0, 0     ; ret  imm16=0

Is it correct for an assembler to 'optimize' like that?

一般来说是的,assemblers 可以使用具有完全相同架构效果和相同助记符的指令的最短编码。

例如NASM 会将 xor rax,rax 优化为 xor eax,eax,即使其他一些(如 YASM 或 GAS)不会。另外 NASM 会优化 lea eax, [rax*2 + 123]lea eax, [rax + rax + 123] 除非你使用 [NOSPLIT 123 + rax*2].


MSVC 始终将 ret 作为 ret 0 发出ret. 显然这个优化是 MS 认为正常依赖的优化。

当你想要 ret 时编写或发出 ret 0 似乎是一个愚蠢的设计,但这就是 MSVC 所做的。 (并不是说 MSVC 通过将 asm 提供给 MASM 来工作;它直接发出机器代码,除非您要求 asm 列表。)

NASM 确实发生在 assemble ret 0ret imm16=0 之间,因此您可能更喜欢使用它。我知道只要有选择,我就会选择 NASM 而不是 MASM;简单的语法和不受关于内存操作数的神奇规则暗示操作数大小,有时 [] 没有任何意义...