【发布时间】:2013-06-27 23:04:01
【问题描述】:
在流行的 x86 架构上,可以使用jmp 类型指令之一以及call 指令来控制执行流程。但两者都是基本的,还是一种“语法糖”是另一种?
例如,push 指令是语法糖:push eax 等价于mov [esp], eax,后跟sub esp, 4。所以mov是唯一的基本数据操作。
但是call 也是这样吗?是否有其他一些指令可以达到相同的效果?
在伪代码中,如果我可以访问 指令指针:
bar:
push eip ;; pseudo-code! ;; call foo
jmp foo
foo:
pop eax ;; ret
jmp [eax]
这不是有效的 x86,因为不能直接读取指令指针寄存器 eip。到目前为止,我看到的所有获得eip 值的“技巧”都使用call。或者call 实际上是在 x86 上读取指令指针的规范方式?作为一个额外的问题,是否每个可以实现 C 的架构都需要一种读取指令指针的方法,以便可以实现函数指针?
int main(int argc, char * argv[])
{
int (*p)() = strtoul(argv[1]);
return p(); // how to implement without
// accessing the instruction pointer?
}
[这不是一个深奥的问题;知道函数不仅是高级编程语言引入的抽象,而且实际上是硬件固有的,我只是觉得在情感上令人满意。]
【问题讨论】:
-
push指令不是语法糖——是的,它与更长的指令序列具有相同的净效果,但执行所需的时间不同。实际涉及到不同的指令位序列。语法糖一般是指会生成完全相同的机器码位模式的东西,比如nop指令,和xchg eax,eax是一样的 -
@ChrisDodd:非常有趣,谢谢!随意在答案中扩展它!
-
顺便说一句,
lea reg, [rip]在 64 位模式下。实际上push eax通常不是作为mov [esp], eax \ sup esp, 4实现的,而是通过特殊的技巧使 esp 调整不需要时间(但是,当您以正常方式使用esp时,它确实需要一个特殊的重新同步操作)。通常无论如何。 -
@harold:是的,我注意到 x86_64 似乎允许这样做——为什么那是合法的?这是一个奇怪的小变化......
-
Only one instruction is fundamental。任何计算都可以使用一个减法和分支如果负指令来实现。