运行时库对操作系统的依赖性

时间:2013-10-13 14:20:16

标签: c operating-system kernel osdev

我正在阅读有关如何编写极简主义内核的this教程。我在两者之间读到了这个:

  

运行时库

     

为您的操作系统编写代码的主要部分是重写运行时库,也称为libc。这是因为    RTL是编译器软件包中最依赖操作系统的部分:C   RTL提供了足够的功能,允许您编写便携式   程序,但RTL的内部工作依赖于操作系统   使用即可。事实上,编译器供应商通常使用不同的RTL   操作系统:Microsoft Visual C ++为各种提供了不同的库   调试/多线程/ DLL和旧的MS-DOS的组合   编译器提供最多6个不同内存的运行时库   模型。

我对这部分感到困惑。假设我用C代码编写内核,并根据建议使用内置的printf()函数来打印内容。最后,我的代码将被翻译成机器代码。当它被执行时,处理器将直接运行它。为什么作者说:

RTL的内部工作依赖于正在使用的操作系统?

2 个答案:

答案 0 :(得分:3)

有两个不同的问题:

  1. 在内核中运行时printf()会做什么?因为用于开发内核的C编译器的RTL可能假设有一些运行时环境,包括控制台,操作系统等,所以很可能它会崩溃或什么都不做。即使您使用的是独立的C / C ++实现,运行时可能会接管串行端口或诸如此类的东西来执行输出。您可能不希望这样,因为您的内核驱动程序将控制I / O.因此,您需要从RTL重新实现基础文件I / O.

  2. 在运行在内核之上的用户进程中运行时printf()会做什么?如果内核保护对硬件资源的访问,则它无法执行任何操作。来自RTL的底层文件I / O代码必须知道如何与内核通信以打开标准输入/输出“文件”的任何传递并执行数据交换。

  3. 您需要了解您是使用C / C ++编译器+ RTL的独立或托管实现,以及所有含义。对于内核开发,您将使用独立的实现。对于用户空间开发,您需要托管实现(可能是交叉编译器),但运行时库必须编写为托管实现。请注意,在这两种情况下,您都可以使用相同的编译器,只需将其指向适当的头文件和库即可。例如,在Linux上,内核和用户空间开发可以使用完全相同的gcc编译器完成,具有不同的头文件和库。

    处理器不知道控制台是什么,或者内核是什么。有些代码必须实际访问硬件。当您从托管的C / C ++实现中获取printf()时,该实现(在其内部深处的某个位置)将调用它要运行的特定平台的系统调用。该系统调用旨在写入包含“控制台”的一些抽象。在此系统调用的另一端,调用是将此数据推送到某些硬件的内核代码。它甚至可能不是直接硬件,它可能是另一个进程的用户空间。

    例如,无论何时在Unix机器上运行基于GUI的终端(KDE的Konsole,X11 xterm,OS X终端等),调用printf()的用户空间进程都非常非常接近在任何东西击中硬件之前去。即(即使这是简化的!):

    1. printf()将数据写入缓冲区
    2. 将缓冲区刷新到(写入)文件句柄。调用write()库函数。
    3. write()库函数调用将控制权转移到内核的系统调用。
    4. 内核代码从用户空间页面复制数据,因为它们可以随时消失到内核端的非分页缓冲区。
    5. 内核代码调用给定文件句柄的写入处理程序 - 许多内核中的文件句柄用虚拟方法实现为类。
    6. 文件句柄恰好是pseudo-terminal (pty) slave。 write方法将数据传递给pty master。
    7. pty master填充给定伪终端的读缓冲区,并唤醒等待相关文件句柄的进程。
    8. 实现GUI终端的过程唤醒并read()文件句柄。这会通过库进入系统调用。
    9. 内核调用pty主文件句柄的读处理程序。
    10. 读取处理程序将其缓冲的数据复制到用户空间。
    11. 系统调用返回。
    12. 终端进程获取数据,解析控制代码,并更新代表模拟屏幕的内部数据结构。它还会在事件队列中对更新事件进行排队。 Control返回GUI库/框架的事件循环。这是通过事件完成的,因为这些事件通常是合并的。如果有大量可用数据,则会在重新绘制任何内容之前对其进行全部处理以更新屏幕数据结构。
    13. 事件调度程序将更新/重绘事件调度到“屏幕”窗口小部件/窗口。
    14. 窗口小部件/窗口中的事件处理程序代码使用内部数据结构在某处“绘制”。通常它是在位图后备存储上。
    15. GUI库/框架代码向操作系统的图形驱动程序发出信号,表明后备存储上有新数据。
    16. 同样,通过系统调用,控件被传递给内核。在内核中运行的图形驱动程序将在图形硬件上执行必要的魔术,以将支持位图传递到屏幕。它可以是显式内存副本,也可以是使用图形硬件对纹理副本进行简单排队。

答案 1 :(得分:1)

Printf()是一个独立于操作系统的高级功能。然而,这只是谜题的一部分,它本身就具有依赖性。它需要能够写入stdout。这将导致低级操作系统相关的系统调用,如create()打开stdout流和write()以发送printf输出。不同的操作系统有不同的系统调用,所以总有一个适应层,你的将会有。

当然,你可以让你的内核中的printf()工作。实际上看到对printf()的调用输出将是真正需要解决的问题。没有什么比内核模式中的终端窗口更好。