assembly 汇编程序不应该荣誉我对ret imm16的请求吗?

erhoui1w  于 2023-02-04  发布在  其他
关注(0)|答案(1)|浏览(101)

我知道操作数为零的retimm16C2 imm16)指令与无操作数的retC3)指令在效果上没有区别,但是,当我显式给予汇编程序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

汇编程序这样“优化”是正确的吗?

jdzmm42g

jdzmm42g1#

您不需要3个单独的db行;具有3个操作数的一个db是等效的:

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

汇编程序这样"优化"是正确的吗?
一般来说,是的,汇编器可以使用最短的指令编码,它具有完全相同的体系结构效果,并具有相同的助记符。
例如,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;简单的语法和没有关于内存操作数的魔术规则意味着操作数大小,有时[]没有任何意义...

相关问题