pop eip 是法律指令吗? [英] Is pop eip legal instruction?

查看:110
本文介绍了pop eip 是法律指令吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做大学时的理论考试,有人问我这个问题:经过一些指令,esp 增长了 4,eip 增长了 20,可能是什么指令?我标记了pop eip"和ret".nasm 32位汇编中是否可以执行pop eip指令?

解决方案

pop eip 不是真正的 x86 指令. 没有汇编程序会汇编它,AFAIK.

这是用于解释 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 位数字.或者作为隐式源或目标,如muldiv的EDX:EAX,或pushf隐式读取EFLAGS:它只是由该操作码隐含的,没有任何专门表示 EFLAGS 的位.

<小时>

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

有些初学者不理解这一点,认为ret会神奇地返回到最后的call,所以他们没有把ret上的错误联系起来 和他们的代码弄乱了堆栈.

我肯定写过类似ret 是我们在 x86 上为 pop eip 使用的名称"之类的内容,在许多 SO 答案和评论中次.

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

<小时><块引用>

esp 增长了 4,eip 增长了 20

是的,我认为 C3 ret 或 C2 00 00 ret0 是仅有的两个操作码可以做到这一点,并且都使用 ret 助记符.

如果 EIP 增长了 15 或更少,add esp, 4pop eax 的长编码可以解释它,例如带有多个冗余的 rep 和/或 fs 前缀和一个用于直接 4imm32 编码.

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

iret 几乎是可能的,但它会弹出 CS:IP 和一个 FLAGS 值:你不能让它只弹出 4 个字节.(尤其是在 32 位模式下.)

sysret 不会修改 ESP,并且只能被内核使用(ring 0).sysexit 从 RCX 和 RIP = RDX 设置 RSP,但我'我很确定这不是他们要找的答案.:P

I’m working on this theoretical test I got at university, and have been asked this question : After some instruction, esp grew by 4 and eip grew by 20, what can possibly be the instruction? I marked both "pop eip" and "ret". Is it possible in nasm 32 bit assembly to execute pop eip instruction?

解决方案

pop eip is not a real x86 instruction. No assembler will assemble it, AFAIK.

It's pseudocode for explaining what ret does. See the Operation section in the manual. Specifically a normal "near" ret; far jmp/call/ret are basically unused in "normal" 32-bit code.

ret has its own opcode separate from any of the encodings for pop, and x86 also chooses to give it a separate mnemonic. It would have been a valid design for pop eip to also be accepted as another name for the 0xc3 opcode. x86 does have the mov mnemonic overloaded for many different opcodes, including mov to/from control registers, mov to/from debug registers, as well as the standard mov between integer registers and/or memory or immediate. (That "standard" form of mov also has several different opcodes to choose from, though.)

But that would have been a bit weird because push eip doesn't exist except as call +0 which has the performance side-effect of being a jump.

EIP is not one of the 8 general-purpose integer registers, so the normal encodings of pop can't encode a ret. That's one reason why ret needs its own opcode, and why it makes sense for it to have a separate mnemonic in asm source. x86 instructions encode registers as 3-bit numbers, or optionally 4-bit on x86-64. Or as an implicit source or destination, like EDX:EAX for mul or div, or pushf implicitly reads EFLAGS: it's just implied by that opcode without any bits that specifically mean EFLAGS.


ret isn't magic: all it does is pop the stack and use the result as a jump target. It's up to the programmer to make sure ESP is pointing at an address you want to jump to, typically a return address.

Some beginners fail to understand this and think that ret will magically return to the last call, so they don't make the connection between faulting on ret and their code messing up the stack.

I've definitely written something like "ret is the name we use on x86 for pop eip" in SO answers and comments many times.

Fun fact: on ARM 32-bit, the program counter is one of the 16 integer registers, r15, so you really can pop {r4, pc} to restore a saved R4 and pop a saved lr (link register = return address) into the program counter all in one instruction. So ARM literally can do the equivalent of pop eip with the same opcode it uses for popping general-purpose integer registers.


esp grew by 4 and eip grew by 20

Yes, I think C3 ret or C2 00 00 ret 0 are the only 2 opcodes that could do this, and both use the ret mnemonic.

If EIP grew by 15 or fewer, a long encoding of add esp, 4 or pop eax could account for it, e.g. with multiple redundant rep and/or fs prefixes and an imm32 encoding for the immediate 4.

x86 instructions can be at most 15 bytes long; if decoding doesn't reach the end of an instruction before 15 bytes, the CPU takes a #UD exception, just like for other illegal instructions. So changing EIP by 20 bytes with one instruction is only possible with a jump. And the only jump that increases ESP is ret; jmp / jcc leave it unmodified, call pushes a return address.

iret is almost possible but it pops CS:IP and a FLAGS value: You can't get it to pop just 4 bytes. (Especially in 32-bit mode.)

sysret doesn't modify ESP, and is only usable by the kernel (ring 0). sysexit sets RSP from RCX and RIP = RDX, but I'm pretty sure that's not an answer they were looking for. :P

这篇关于pop eip 是法律指令吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆