0

jmp在流行的 x86 架构上,可以使用-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不能直接读取指令指针寄存器。到目前为止,我所见过的所有获得eipall use价值的“技巧” 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?
}

[这不是一个深奥的问题;知道函数不仅是高级编程语言引入的抽象,而且实际上是硬件固有的,我只是觉得在情感上很令人满意。]

4

1 回答 1

9

机器指令集可能非常琐碎;参见Wolfram 的 2 态 3 符号图灵机。问题是这样的机器很难编程,也很难快速运行。

您可以使用其他指令完全模拟呼叫返回:

    ;  Simulate "call abc":
    push    offset next_location
    jmp     abc
 next_location:

    ; Simulate "ret"
    pop    eax
    jmp    eax

您显然可以使用 mov 指令模拟推送/弹出,并通过添加您在问题中提到的常量来调整寄存器。

人们将指令添加到指令集中以使通用序列高效。因此,“调用”的存在是因为它执行了一项通常有用的任务(并且“调用/调用”对可以通过硬件使用返回地址的内部堆栈进行优化,以避免指令流水线中断;这是真正的性能优势)。

所以,是的,您可以使用计算机提供的最小指令集来实现您的汇编语言目的。但是正确的附加说明在实践中确实有帮助。(您可以出于良好的意图添加您认为可能有用的说明。它们通常无济于事,这是最初的 RISC/CISC 辩论的来源)。

傻瓜最小机器:

  • 1970年代生产的真正的小型机(“GRI”)只有一条指令:MOV LOC1 to LOC2;目标位置很神奇,这就是实际工作的完成方式。通过将某些东西移动到位置 33(组成),一个副作用是该值被添加到可以从位置 32 读取的累加器中。它有很多位置可以做有趣、方便的事情,所以本质上添加了一个新的有趣寄存器只是添加有用指令的奇怪变体。我怀疑 JMP 指令包括将常量移动到充当程序计数器的位置。(如果您觉得这很奇怪,那么您还没有遇到过 PDP-11)。

  • 理论机器是具有单指令“SUB LOC1 from LOC2 jmp to LOC3 ifnegative”的机器。这台机器是通用的,但在您遇到第一个玩具问题后编程并不有趣。

有趣的是,这两个指令集都没有操作码位或寻址模式位。指令解码器确实很简单。

于 2013-06-30T19:35:06.597 回答