伙计,你必须支付 156 美元才能读完这本书。您可能会以不到 30 美元的价格获得一本 VMS 内部结构和数据结构的书籍。
也就是说,让我试着把那些乱七八糟的东西翻译成英文。
系统调用不使用与其他函数相同的链接(即传递参数和调用函数的方法)。
不是执行某种调用指令,而是执行系统服务,而是触发一个异常(在 Intel 中,它被称为中断)。 p>
CPU 期望操作系统创建一个 DISPATCH TABLE 并将其位置和大小存储在一个特殊的硬件寄存器中。调度表是一个指向异常和中断处理程序的指针数组。
异常和中断都有编号,因此,当异常或中断编号 #1 发生时,CPU 会在内核模式下调用调度表中的 2d 异常处理程序(不是 #0,而是 #1)。
其中包含的包装函数到底是什么?它们也是用汇编语言编写的吗?
操作系统通常为系统服务提供一个(但有时更多)异常。你需要用汇编语言做一些这样的事情来调用系统服务:
INT $80 ; Explicitly trigger exception 80h
因为您必须执行特定指令,所以它必须是汇编语言。也许您的 C 编译器可以在线执行汇编语言来调用这样的系统服务。但即使可以,每次您想调用系统服务时都必须这样做,这将是一个皇家 PITA。
另外我这里没有填写所有细节(只是对系统服务的实际调用)。通常,当您在 C(或其他)中调用函数时,参数会被压入程序堆栈。由于进入内核模式时堆栈通常会发生变化,因此系统调用的参数需要存储在寄存器中。
另外,您需要确定要执行的系统服务。通常,系统服务有编号。系统服务的编号被加载到第一个寄存器中(例如,R0 或 AX)。
需要调用系统服务时的完整流程是:
- 将要覆盖的寄存器保存在堆栈中。
- 将要传递给系统服务的参数加载到硬件寄存器中。
- 将系统服务的编号加载到最低的寄存器中。
- 触发异常进入内核模式。
- 从寄存器中卸载系统服务返回的参数
- 可能会做一些错误检查
- 恢复您之前保存的寄存器。
操作系统不是每次调用系统服务时都这样做,而是为高级语言提供包装函数以供使用。您可以像通常调用函数一样调用包装器。包装器(用汇编语言)为您完成上述步骤。
因为这些包装器几乎相同(通常唯一的区别是参数数量不同的结果),所以可以使用宏来创建包装器。一些汇编器具有强大的宏工具,允许单个宏定义所有包装器,即使参数数量不同。
Linux 提供了多个创建包装器的 _syscall C 宏。每个参数数量都有一个。请注意,这些宏仅适用于操作系统开发人员。一旦有了包装器,每个人都可以使用它。
宏如何调用汇编语言指令?
这些 _syscall 宏必须生成行内汇编代码。
最后,请注意,这些包装器并未定义实际的系统服务。这必须在调度表和系统服务异常处理程序中设置。