pop eip法律指示吗?

时间:2019-06-19 22:46:56

标签: assembly x86 nasm 32-bit

我正在大学上这项理论考试,并且被问到以下问题: 经过一些指令后,esp增长了4,eip增长了20,这可能是什么指令? 我标记了“ pop eip”和“ ret”。 可以在nasm 32位汇编中执行pop eip指令吗?

1 个答案:

答案 0 :(得分:6)

pop eip不是真正的x86指令。 AFAIK不会编译任何汇编程序。

它是伪指令,用于解释ret的作用。请参阅“操作”一节in the manual。特别是正常的“附近” ret;到目前为止,jmp / call / ret基本上没有在“正常”的32位代码中使用。

ret有自己的操作码,与pop的任何编码都不同,并且x86还选择为其赋予单独的助记符。 pop eip作为0xc3操作码的另一个名称将是一个有效的设计。 x86确实为许多不同的操作码重载了mov助记符,包括movcontrol registers的往返,movdebug registers的往返,以及{ {3}}在整数寄存器和/或内存或立即数之间。 (不过,mov的“标准”格式也有几种不同的操作码可供选择。)

但这有点奇怪,因为push eip除了call +0以外,不存在,它具有跳跃的性能副作用。

EIP不是8个通用整数寄存器之一,因此pop的常规编码无法对ret进行编码。这就是ret需要自己的操作码的原因,也是为什么在asm源中使用单独的助记符才有意义。 x86指令将寄存器编码为3位数字,或者在x86-64上编码为4位。或作为隐式源或目标,例如muldiv的EDX:EAX,或pushf隐式读取EFLAGS:该操作码仅隐含EFLAGS专门表示的位。


ret并不是魔术:它所做的只是弹出堆栈并将结果用作跳转目标。程序员应确保ESP指向您要跳转到的地址,通常是返回地址。

一些初学者无法理解这一点,并认为ret将神奇地返回到最后一个call,因此他们不会在ret的错误和代码混乱之间建立联系。堆栈。

在SO问题中,我肯定写过类似“ ret是我们在x86上为pop eip 使用的名称”的答案。

有趣的事实:在ARM 32位上,程序计数器 是16个整数寄存器r15之一,因此您真的可以pop {r4, pc}恢复保存的R4并通过一条指令将保存的lr(链接寄存器=返回地址)弹出到程序计数器中。因此,ARM可以使用与弹出通用整数寄存器相同的操作码来实现pop eip的等效功能。


  

esp增长了4,eip增长了20

是的,我认为standard mov是唯一可以做到这一点的2个操作码,并且都使用ret助记符。

如果EIP增长了15或更少,则add esp, 4pop eax的长编码可能会造成这种情况,例如具有多个冗余rep和/或fs前缀,以及用于直接imm32的{​​{1}}编码。

x86指令的最大长度为15个字节;如果解码在15个字节之前没有到达指令的末尾,则CPU会发生4异常,就像其他非法指令一样。因此,只有一条跳转才能通过一条指令将EIP更改20字节。而增加 ESP的唯一跳是#UD; jmp / jcc保持不变,ret推送一个返回地址。

call几乎是可能的,但它会弹出iret和FLAGS值:您不能让它仅弹出4个字节。 (尤其是在32位模式下。)

CS:IP不会修改ESP,并且只能由内核(0环)使用。 C3 ret or C2 ret 0从RCX设置RSP,并且RIP = RDX,但是我很确定这不是他们想要的答案。 :P