我正在做我在大学里得到的这个理论测试,并被问到这个问题:在接受了一些教育之后,尤其是增长了4,eip增长了20,这可能是什么呢?我标记了“pop eip”和“ret”。在nasm 32位程序集中可以执行pop eip指令吗?
发布于 2019-06-20 00:57:48
pop eip 不是真正的x86指令,没有汇编程序会组装它。
它是用来解释ret所做的事情的伪代码。请参阅操作部分在手册中。具体来说,一个正常的“接近”ret;far jmp/call/ret在“普通”32位代码中基本上没有使用。
ret有自己的操作码,与pop的任何编码都是分开的,x86也选择给它一个单独的助记符。如果pop eip也被接受为0xc3操作码的另一个名称,这将是一个有效的设计。x86确实为许多不同的操作码重载了mov助记符,包括mov到/从控制寄存器、mov到/从调试寄存器,以及整数寄存器和/或内存或即时之间的mov。( mov的“标准”格式也有几种不同的操作码可供选择。)
但这可能会有点奇怪,因为push eip不存在,除非是作为call +0,它具有跳转的性能副作用。
EIP不是8个通用整数寄存器之一,因此pop的普通编码不能对ret进行编码。这就是为什么ret需要自己的操作码的原因之一,以及为什么在asm源代码中有一个单独的助记符是有意义的。x86指令将寄存器编码为3位数字,或者在x86-64上可选地编码4位.或者作为一个隐式源或目标,比如EDX:EAX用于mul或div,或者pushf隐式地读取EFLAGS:它只是在操作代码中隐含的,没有任何特定意思的位。
ret并不神奇:它所做的只是弹出堆栈并将结果用作跳转目标。这取决于程序员确保ESP指向要跳转到的地址,通常是返回地址。
有些初学者无法理解这一点,认为ret会神奇地返回到最后一个call,因此他们不会在ret上的错误与他们的代码破坏堆栈之间建立联系。
我肯定写过类似"ret 是我们在x86上为 pop eip“使用的名称,所以回答和评论很多次。
有趣的事实:在ARM 32位上,程序计数器是16个整数寄存器( r15 )之一,所以您真的可以在一条指令中pop {r4, pc}恢复保存的R4并弹出保存的lr (链接寄存器=返回地址)到程序计数器中。因此,ARM字面上可以用它用于弹出通用整数寄存器的相同操作代码来完成相当于pop eip的操作。
esp增长4,eip增长20。
是的,我认为ret 0是唯一能够做到这一点的两个操作码,它们都使用ret助记符。
如果EIP增长了15或更少,那么add esp, 4或pop eax的长编码就可以解释它,例如使用多个冗余的rep和/或fs前缀,以及用于直接4的imm32编码。
x86指令最多可以有15字节长;如果解码不能在15字节之前到达指令的末尾,CPU就会接受#UD异常,就像其他非法指令一样。因此,用一条指令将EIP更改为20个字节,只有跳转才能实现。增加ESP的唯一跳转是ret;jmp / jcc不修改它,call推送返回地址。
iret几乎是可能的,但是它会弹出CS:IP和一个标志值:您不能让它弹出4个字节。(特别是在32位模式下)
sysret不修改ESP,只对内核可用(环0)。sysexit从RCX和RIP = RDX设置RSP,但我很确定这不是他们想要的答案。:P
https://stackoverflow.com/questions/56676840
复制相似问题