据我了解,ret
操作数为零的 imm16
(C2 imm16
) 指令与无操作数 ret
(C3
) 没有什么不同它的作用。但是,当我显式给出汇编器 ret 0 时,它是否应该将其编码为 ret imm16 指令,因为我显式提供了操作数?
如果我使用 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
然后用反汇编器打开可执行文件,我看到为ret
编码的指令是C3
:
00401000: 33 C0 xor eax,eax
00401002: C3 ret
我可以通过硬编码字节来手动执行 C2
指令:
.386
.MODEL FLAT, STDCALL
.CODE
stdMain PROC
xor eax, eax
db 0c2h, 0, 0 ; ret imm16=0
stdMain ENDP
END
现在我在反汇编输出中看到了 C2
指令:
00401000: 33 C0 xor eax,eax
00401002: C2 00 00 ret 0
汇编器这样“优化”是否正确?
最佳答案
您不需要 3 个单独的 db
行;一个带有 3 个操作数的 db
是等效的:
db 0c2h, 0, 0 ; ret imm16=0
Is it correct for an assembler to 'optimize' like that?
一般来说,可以接受的是,汇编器可以使用具有完全相同的架构效果和相同助记符的最短指令编码。
例如NASM 会将 mov rax, 123
优化为 mov eax, 123
,尽管其他一些(如 YASM 或 GAS)默认情况下不会这样做。 (GAS 有一个 -Os
选项,GCC 默认情况下不会传递给它)。此外,NASM 会将 lea eax, [rax*2 + 123]
优化为 lea eax, [rax + rax + 123]
,除非您使用 [NOSPLIT 123 + rax *2]
至 spend more code size on a disp32 for the benefit of avoiding a slower 3 component LEA .
NASM 不会将 xor rax,rax
优化为 xor eax,eax
;我想它不会使用 XOR 检查归零惯用法(两个规则相同)。
NASM 有一个 -O0
选项来不优化,但这非常糟糕,例如mov rax, -1
是 10 个字节 (imm64),而不是 7 (sign_extended_imm32),add ecx, 123
使用 imm32,jmp foo
即使标签在附近,也会使用 rel32 而不是 rel8。 (这曾经是旧 NASM 版本中的默认设置。 https://nasm.us/doc/nasmdoc2.html#section-2.1.24 )
MSVC 在 asm 列表中总是将 ret
发出为 ret 0
,因此,如果您曾经汇编过这样的代码,您肯定希望汇编器将其优化为正常ret
。显然,MS 认为这种优化是正常的依赖。
当你想要 ret
时,编写或发出 ret 0
似乎是一个愚蠢的设计,但这就是 MSVC 所做的。 (并不是说 MSVC 通过将 asm 提供给 MASM 来工作;除非您要求 asm 列表,否则它会直接发出机器代码。)
NASM 确实会将 ret 0
汇编为 ret imm16=0
,因此您可能更喜欢使用它。我知道只要我有选择,我都会选择 NASM 而不是 MASM;简单的语法和关于内存操作数的魔法规则意味着操作数的大小,有时 []
没有任何意义......
关于assembly - 汇编器是否应该不满足我对 ret imm16 的请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61996121/