pop eip
不是真正的 x86 指令。AFAIK,没有汇编器会组装它。
这是伪代码解释 what ret
做。参见操作部分在手册中 https://www.felixcloutier.com/x86/ret。具体来说是正常的“附近”ret
; far jmp/call/ret 在“正常”32 位代码中基本上未使用。
ret
有自己的操作码,与任何编码分开pop
,而x86也选择给它一个单独的助记符。这本来是一个有效的设计pop eip
也被接受为0xc3
操作码。 x86确实有mov
许多不同操作码的助记符重载,包括mov
至/自控制寄存器 https://www.felixcloutier.com/x86/mov-1, mov
至/自调试寄存器 https://www.felixcloutier.com/x86/MOV-2.html,以及标准mov https://www.felixcloutier.com/x86/mov整数寄存器和/或内存或立即数之间。 (这种“标准”形式mov
不过,也有几种不同的操作码可供选择。)
但这有点奇怪,因为push eip
不存在,除了作为call +0
它具有跳跃的性能副作用。
EIP不是8个通用整数寄存器之一,因此正常编码pop
无法编码ret
。这就是原因之一ret
需要它自己的操作码,以及为什么它在 asm 源代码中有一个单独的助记符是有意义的。 x86 指令将寄存器编码为 3 位数字,或者在 x86-64 上选择 4 位数字。或者作为implicit源或目标,例如 EDX:EAXmul
or div
, or pushf
隐式读取 EFLAGS:它只是由该操作码暗示,没有任何专门表示的位mean EFLAGS.
ret
并不神奇:它所做的只是弹出堆栈并将结果用作跳转目标。由程序员来确保 ESP 指向您想要跳转到的地址,通常是返回地址。
有些初学者不明白这一点并认为ret
会神奇地回到最后call
,所以他们不会在故障之间建立联系ret
他们的代码弄乱了堆栈。
我肯定写过类似的东西“ret
是我们在 x86 上使用的名称pop eip
”在多次回答和评论中。
有趣的事实:在 ARM 32 位上,程序计数器is16 个整数寄存器之一,r15
,所以你真的可以pop {r4, pc}
恢复已保存的 R4 并弹出已保存的lr
(链接寄存器=返回地址)全部通过一条指令存入程序计数器。所以ARM实际上可以做相当于pop eip
使用与弹出通用整数寄存器相同的操作码。
esp 增长了 4,eip 增长了 20
是的,我认为C3 ret或 C2 00 00ret 0 https://www.felixcloutier.com/x86/ret是唯一可以做到这一点的两个操作码,并且都使用ret
助记符。
如果 EIP 增长 15 或更少,则长编码add esp, 4
or pop eax
可以解释它,例如具有多个冗余rep
and/or fs
前缀和imm32
立即编码4
.
x86指令最多可以有15个字节长;如果解码在 15 个字节之前没有到达指令末尾,则 CPU 采取#UD
例外,就像其他非法指令一样。因此,只有通过跳转才能用一条指令将 EIP 更改 20 个字节。唯一的跳跃增加 ESP is ret
; jmp / jcc 保持不变,call
推送返回地址。
iret
几乎有可能,但它会弹出CS:IP
、一个 FLAGS 值和一个新的SS:SP
:你无法让它只弹出 4 个字节。 (特别是在 32 位模式下。)
sysret
不修改 ESP,并且只能由内核(环 0)使用。sysexit https://www.felixcloutier.com/x86/sysexit从 RCX 和 RIP = RDX 设置 RSP,但我很确定这不是他们正在寻找的答案。 :P
16-bit retf
可以在非常特殊的情况下工作:如果 EIP 位于 32 位地址空间的低 16 位,并且当前 CS 值已经在堆栈中。 16位跳转,包括retf
,将EIP截断为IP。
我不是 100% 确定66h
操作数大小覆盖前缀retf
在 32 位模式下将只弹出 4 个字节而不是 6 个字节;中的伪代码https://www.felixcloutier.com/x86/ret https://www.felixcloutier.com/x86/ret says:
// retf in protected mode, not vm86, RETURN-TO-SAME-PRIVILEGE-LEVEL:
ELSE (* OperandSize = 16 *)
EIP := Pop();
EIP := EIP AND 0000FFFFH;
CS := Pop(); (* 16-bit pop *)
第一个 Pop() 被分配给一个 32 位寄存器;这会使其成为 32 位流行吗?但这部分伪代码即使在 16 位保护模式下也适用。