[英]Are “functions” a fundamental part of the x86 hardware?
在流行的x86架构上,可以使用jmp
-type指令之一以及call
指令来控制执行流程。 但是,两者都是根本的,还是另一种?
例如, push
指令是语法糖: push eax
等效于mov [esp], eax
后跟sub esp, 4
。 因此mov
是唯一的基本数据操作。
但这也可以call
吗? 还有其他一些指令可以达到相同的目的吗?
在伪代码中,如果我可以访问指令指针,则可以使用jmp
编写函数调用:
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?
}
[这不是一个深层的问题; 知道函数不仅是高级编程语言引入的抽象,而且实际上是硬件固有的,这简直让我激动不已。
机器指令集可能微不足道; 请参阅Wolfram的2状态,3符号图灵机。 问题是这种机器很难编程,也很难快速运行。
您可以使用其他说明完全模拟呼叫返回:
; Simulate "call abc":
push offset next_location
jmp abc
next_location:
; Simulate "ret"
pop eax
jmp eax
显然,您可以使用mov指令和通过添加问题中提到的常量来调整寄存器来模拟push / pop。
人们将指令添加到指令集以使通用序列高效。 因此,“调用”之所以存在是因为它执行了通常有用的任务(“调用/返回”对可以由硬件使用内部返回地址堆栈来优化,以避免指令流水线中断;这是真正的性能优势)。
因此,是的,您可以使用计算机提供的最少指令集来实现汇编语言的目的。 但是正确的附加说明在实践中确实有帮助。 (您可以有意向地添加您认为可能有用的说明。它们通常无济于事,这是RISC / CISC最初的争论的源头 )。
Goofball最小机器:
1970年代生产了真正的微型计算机(“ GRI”),它只有一条指令:MOV LOC1至LOC2; 目标位置是魔术,这就是完成实际工作的方式。 通过将某物移动到位置33(组成),其副作用是将值添加到了可以从位置32读取的累加器中。它具有许多可以完成有趣且方便的操作的位置,因此,实质上是添加了一个新的有趣寄存器只是添加有用指令的一个奇怪的变体。 我怀疑JMP指令包含将一个常量移动到充当程序计数器的位置。 (如果您觉得这很奇怪,则说明您尚未达到PDP-11)。
一种理论上的机器就是单指令“如果为负,则从LOC2 jmp到LOC3的SUB LOC1”。 这是一台通用的机器,但是在您遇到第一个玩具问题后就很难编程。
有趣的是,这两个指令集都没有操作码位或寻址模式位。 指令解码器确实很简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.