我们以这段代码为例:
.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”。我知道系统调用应该打印该消息,但它到底是如何做到的呢?它如何知道必须打印哪个寄存器?因为我没有在系统调用中的任何地方指示要打印的寄存器(例如,在 C 语言中,它会类似于 printf("%s",msg)),但它知道无论如何它都必须打印 $a0 而我不这样做知道如何以及为什么。
理论上,
syscall
指令只是将处理器(指令执行流)的控制权转移到系统/内核异常处理程序。 该异常处理程序具有执行每个特定 syscall
的所有操作的软件,然后返回到用户代码 - 正是该软件知道查看 $v0
和 $a0
。 它就像一个子例程调用,但调用的是内核代码而不是用户子例程。 硬件指令基本上“跳转”到那里,然后软件完成剩下的工作。
更具体地说,
syscall
指令调用异常机制。 它捕获正在执行的用户代码的PC,然后更改为特权模式,设置异常原因,并将PC更改为0x80000800,从而开始运行内核异常处理程序。
我说的是理论上,因为使用模拟器,它们的作用类似,但是
syscall
可以直接在模拟器本身内实现为软件(而不是作为模拟的异常处理程序);如果以这种方式实现,软件还知道每个特定的syscall
,哪些寄存器有哪些参数,以及运行操作后如何返回用户代码。