RET默认的操作数大小是多少?

时间:2016-06-21 17:13:45

标签: assembly x86 64-bit nasm x86-64

我的问题涉及 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位模式的汇编程序会期望什么操作数?

1 个答案:

答案 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,无论它是什么指令。即它也不会在o64push这样的insn上省略它,是吗?

ISA的设计使单字节pop指令“正常工作”。普通ret上不需要REX前缀。如the instruction set manual's ret entry中所述:

  

在64位模式下,该指令的默认操作大小是堆栈地址大小,即64位。这适用于近回报,而不是回报; far返回的默认操作大小是32位。

这类似于ret / push在长模式下默认为64位操作数大小的方式。 (并且,与手册中的含义相反,pop无法编码32位推/弹)。

AMD一般都试图让解码变得简单。例如REX.W=0需要一个REX前缀(否则它只是作为一个效率较低的movsxd r64, r/m32运行),但对于非常常见的指令,如push / pop和ret,他们通过设计选项保存代码大小此