我的问题涉及 64位模式中的 RET urn指令及其操作数大小,它指定从堆栈到RIP弹出多少信息以及RSP递增的字节数由
我注意到一些汇编程序离开Intel定义的默认操作数大小。即64位用于近返回,32位用于远返:
1 ; Assembled with NASM 2.12 command "nasm TestRET.asm -l TestRET.lst"
2 BITS 64
3 00000000 66CF IRETW ; Opsize 16.
4 00000002 CF IRETD ; Opsize 32.
5 00000003 48CF IRETQ ; Opsize 64.
6 00000005 66CF o16 IRET ; Opsize 16.
7 00000007 CF o32 IRET ; Opsize 32.
8 00000008 48CF o64 IRET ; Opsize 64.
9 0000000A CF IRET ; Opsize 32, default.
10
11 0000000B 66CB o16 RETF ; Opsize 16.
12 0000000D CB o32 RETF ; Opsize 32.
13 0000000E 48CB o64 RETF ; Opsize 64.
14 00000010 CB RETF ; Opsize 32, default.
15
16 00000011 66C3 o16 RETN ; Opsize 16.
17 00000013 C3 o32 RETN ; Opsize 32 should not be available, NASM error?
18 00000014 48C3 o64 RETN ; Opsize 64, REX.W ignored as RETN is promoted to 64 bits.
19 00000016 C3 RETN ; Opsize 64, default.
我没有编写调用门和任务门的经验,但我认为默认操作数大小应该与段大小相对应,在64位模式下为64。
当程序员在没有进一步规范的情况下使用IRET,RETF,RETN时,64位模式的汇编程序会期望什么操作数?
答案 0 :(得分:1)
假设在asm源文件中编写ret
将汇编为单字节指令。
IDK为什么有人会在64位代码中使用retf
,所以我对此没有意见。
在仔细阅读你的桌子后,我会看到你对NASM的操作数大小覆盖的看法。对于像o32
这样的指令,o64
/ RETN
修饰符并不特殊,导致像o64 retn
这样的伪造行为产生REX.W = 1前缀({{ 1}})。
我认为我们应该理解NASM的48 C3
前缀意思是“16位代码中的操作数大小前缀,否则没有”,无论它应用于哪个指令,并且从不暗示REX.W = 0(因为那对o32
/ push
)无效。
同样地,pop
实际上意味着应用REX.W = 1,无论它是什么指令。即它也不会在o64
或push
这样的insn上省略它,是吗?
ISA的设计使单字节pop
指令“正常工作”。普通ret
上不需要REX前缀。如the instruction set manual's ret
entry中所述:
在64位模式下,该指令的默认操作大小是堆栈地址大小,即64位。这适用于近回报,而不是回报; far返回的默认操作大小是32位。
这类似于ret
/ push
在长模式下默认为64位操作数大小的方式。 (并且,与手册中的含义相反,pop
无法编码32位推/弹)。
REX.W=0
需要一个REX前缀(否则它只是作为一个效率较低的movsxd r64, r/m32
运行),但对于非常常见的指令,如push / pop和ret,他们通过设计选项保存代码大小此