【问题标题】:How does the "syscall" instruction works on mips assembly?“系统调用”指令如何在 mips 程序集上工作?
【发布时间】:2021-07-18 12:14:56
【问题描述】:

让我们有例如这个代码:

.data
    msg: .asciiz "Hello world!" #message to be shown


.text
    li $v0, 4 #instruction for string printing
    la $a0, msg #indication of where the string is
    syscall #make it print

“li”将调用指令来准备打印,“la”将使变量 msg 转到寄存器“a0”,我知道 syscall 应该打印消息,但它究竟是如何做到的呢?它怎么知道它必须打印哪个寄存器?因为我没有在系统调用中的任何地方指出要打印的寄存器(例如在语言 c 中,它可能类似于 printf("%s",msg)),但它知道无论如何它必须打印 $a0 而我没有知道如何以及为什么。

【问题讨论】:

    标签: assembly mips


    【解决方案1】:

    理论上,syscall 指令只是将处理器的控制(指令执行流)转移到系统/内核异常处理程序。该异常处理程序具有执行每个特定syscall 的所有操作的软件,然后返回到用户代码——该软件知道查看$v0$a0。这就像一个子程序调用,但调用的是内核代码而不是用户子程序。硬件指令基本上“跳转”到那里,然后软件完成其余的工作。

    更具体地说,syscall 指令调用异常机制。它捕获执行用户代码的PC,然后切换到特权模式,设置异常原因,并将PC更改为0x80000800,开始运行内核异常处理程序。

    我在理论上说,因为使用模拟器,它们会做类似的事情,但syscall 可以作为直接在模拟器本身内的软件(而不是作为模拟异常处理程序)实现;如果这样实现,软件还知道每个特定的syscall,哪些寄存器有哪些参数,以及运行后如何返回用户代码。

    【讨论】:

    • 等等,所以系统调用总是会打印 $a0?
    • syscall 指令和异常处理程序都不知道您的代码最近刚刚加载了$v0$a0 寄存器。通过简单的定义,他们“知道”(即他们假设)查看那些特定寄存器中的值。 (他们不会在指令流中向后看以查看前面的指令。)
    • 这:查看商定的位置,是参数传递通常的工作方式。无需猜测在哪里可以找到参数;无需查看代码在调用之前做了什么:在某些特定寄存器中查找参数是事先达成的、已发布且众所周知的。因为它是基于位置(即什么寄存器)它们“通过”的顺序无关紧要,所以我们可以先设置$a0,然后设置$v0,在syscall中仍然会有同样的效果.
    • 但是系统调用到底想要打印什么?我知道系统调用将始终查看 $v0 以获取它应该做什么的指令,但是是否有它应该始终打印的定义?是否有系统调用将始终打印的寄存器?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多