我的迷你操作系统的调度程序是用汇编编写的,我想知道为什么。我发现eret
C 编译器无法生成该指令,这是否可以推广到 Nios 以及 x86 和/或 MIPS 架构以外的其他平台?因为我相信 os 的一部分总是用汇编编写的,所以我正在寻找为什么系统程序员必须知道汇编才能编写操作系统。是否存在 C 编译器的内置限制,无法生成某些汇编指令,例如将eret
程序返回到中断后正在执行的操作?
4 回答
是的,就是这样。有些指令无法使用 C 语言生成。并且操作系统通常需要一个或一些指令,因此需要一些组装。几乎任何指令集、x86、arm、mips 等都是如此。C 编译器允许您为插入指令进行内联汇编,但语言本身无法真正处理每个指令集的细微差别并试图解释它们。一些编译器会添加编译器特定的东西,例如使用返回的中断风格返回函数。在需要的地方编写汇编比自定义语言或编译器要容易得多,所以那里真的没有需求。
通用答案是出于以下三个原因之一:
因为那种特定类型的代码不能用C编写。我认为
eret
是“从异常中返回”指令,所以没有C等效于此(因为页面错误,除以零或类似的硬件异常不是C /C++ 样式异常)。另一个例子可能是在任务切换时将寄存器保存到堆栈中,并将堆栈指针保存到任务控制块中。C 代码无法做到这一点,因为无法直接访问堆栈指针。因为编译器不会产生像聪明的汇编程序那样好的代码。一些专门的操作可能很难用 C 语言编写——编译器可能不会生成很好的代码,或者代码变得非常复杂以实现在汇编程序中很简单的东西。
C 代码的启动需要用汇编程序编写,因为 C 程序需要设置某些东西才能运行实际的 C 代码。例如配置堆栈指针和其他一些寄存器。
C 语言表达了它被指定表达的东西:基本的算术运算、对变量的赋值以及分支和函数调用。static
可以使用自动(本地)或动态(malloc)存储持续时间分配对象。如果你想要这个概念范围之外的东西,你需要纯 C 以外的东西。
C 语言可以任意扩展,许多平台都定义了语法,例如在特定地址定义函数或变量。
但是CPU的硬件关心很多细节,比如标志寄存器的值。切换线程的调度程序部分需要能够在执行任何操作之前将所有寄存器保存到内存中,因为覆盖任何寄存器都会丢失中断线程中的基本数据。
能够用 C 编写这样的东西的唯一方法是让编译器提供一个 C 函数来生成经过微调的程序集。然后你基本上回到了第 1 格,因为重要的细节仍然在汇编代码的级别。
拥有多个微控制器产品线的供应商有时会不遗余力地允许 C 源代码兼容性,即使在最低级别也是如此,以允许他们的客户移植代码(或者相反,防止他们在需要切换平台时转向其他供应商) . 但是,当您调用生成特定指令的伪函数(称为内在函数)时,C 和汇编之间的区别在某一点上变得模糊了。
一些不能在 C 中完成的事情,或者如果可以完成,最好在汇编中完成,因为它们更直接和/或可维护,包括:
- 执行异常返回和中断返回指令。
- 读取和写入特殊处理器寄存器(控制处理器状态、内存映射、缓存配置、异常管理等)。
- 对连接到硬件设备而不是内存的特殊地址执行原子读取和写入。
- 如上所述,对特殊地址执行特定大小或特性的加载和存储指令。(例如,写入特定设备可能只需要使用存储 16 位指令而不是常规存储 32 位指令。)
- 执行内存屏障或排序、缓存控制和内存映射刷新的指令。
通常,C 主要用于计算(读取输入、计算事物、写入输出)而不是控制机器(与机器中的所有控件和设备交互)。