Linux内核程序集和逻辑

时间:2014-03-02 01:50:47

标签: linux assembly kernel inline-assembly

我的问题有些奇怪,但我会尽力解释。

看看linux内核的语言,我得到了C和汇编,即使我读了一篇文章说[引用] Unix的第二次迭代完全用C语言编写[/ quote]

我认为这是误导性的,但当我说内核有汇编代码时,我有2个问题的开头

  1. 内核中有哪些汇编文件,它们的用途是什么?
  2. 程序集依赖于体系结构,因此如何在多个CPU体系结构上安装linux
  3. 如果Linux内核真的完全用C编写,那么它是如何获得编译所需的GCC的呢?

    我做了一个完整的find / -name *.s 并且在/ usr / src / linux-headers中的某个地方只有一个汇编文件(asm-offset.s) - `uname -r /

    我不认为这有助于GCC的工作,所以linux如何在没有组装的情况下工作,或者如果它使用汇编在哪里以及它如何在依赖于arch时稳定。

    提前致谢

5 个答案:

答案 0 :(得分:13)

<强> 1。为什么要使用装配?

因为某些事情只能在汇编中完成,因为汇编会产生更快的代码。例如,“您可以访问处理器的异常编程模式(例如16位模式,以便在Intel PC上连接启动,固件或遗留代码)”。 阅读here了解更多原因。

<强> 2。使用了什么汇编文件?

来自:https://www.kernel.org/doc/Documentation/arm/README

“初始进入内核是通过head.S,它使用机器   独立代码。通过'r1'的值选择机器   进入,必须保持独特。“

来自https://www.ibm.com/developerworks/library/l-linuxboot/

“当调用bzImage(对于i386映像)时,从开始汇编例程中的./arch/i386/boot/head.S开始(主流程见图3)。这个例程做了一些基本操作硬件设置并调用./arch/i386/boot/compressed/head.S中的startup_32例程。该例程设置一个基本环境(堆栈等)并清除符号开始(BSS)。然后内核通过调用一个名为decompress_kernel的C函数解压缩(位于./arch/i386/boot/compressed/misc.c)。当内核被解压缩到内存中时,它被调用。这是另一个startup_32函数,但是这个函数在./arch/i386/kernel/head.S。“

除了这些汇编文件之外,很多linux内核代码都使用inline assembly

第3。架构依赖?

你认为它是依赖于架构的,这就是为什么linux内核代码移植到不同的架构。

答案 1 :(得分:7)

主要在Linux中汇编的内容:

  • 启动代码:启动计算机并将其设置为可以开始执行C代码的状态(例如:在某些处理器上,您可能需要手动初始化缓存和TLB,在x86上你必须切换到保护模式,...)
  • 中断/异常/陷阱入口点/返回:您需要执行特定于处理器的事情,例如:保存寄存器和重新启用中断,最终还原寄存器并正确返回用户模式。有些例外可能完全由汇编处理。
  • 指令仿真:某些CPU型号可能不支持某些指令,可能不支持未对齐的数据访问,或者可能没有FPU。获取相应的异常时,选项是使用模拟。
  • VDSO: VDSO是内核映射到用户空间的虚拟库。它允许例如:为当前CPU选择最佳系统调用序列(在x86上使用sysenter/syscall而不是int 0x80,如果可用),并实现某些系统调用而不需要上下文切换(例如:{{1} })。
  • 原子操作和锁定:未来可能会使用C11支持原子操作来编写其中一些。
  • 从/向用户模式复制内存:除了使用优化副本外,还会检查越界访问。
  • 优化例程:内核优化了一些例程的版本,例如:crypto例程,memset,clear_page,csum_copy(校验和并在一次传递中复制到另一个地方的IP数据),... < / LI>
  • 支持暂停/恢复和其他ACPI / EFI /固件内容
  • BPF JIT :较新的内核包含用于BPF表达式的JIT编译器(例如用于gettimeofday(),secmode模式2,...)
  • ...

为了支持不同的体系结构,Linux为它支持的每个体系结构编写了汇编代码(重新编写)(有时,对于使用相同CPU体系结构的不同平台,有一些代码的实现)。只需查看tcpdump

下的所有子目录

答案 2 :(得分:4)

需要装配,原因有两个。

  1. 至少在大多数处理器上,操作系统操作所需的许多指令都没有C等价物。英特尔x86 / 64处理器的一个很好的例子是iret指令,它从硬件/软件中断返回。这些中断是处理硬件事件(如键盘按键)和旧处理器上程序的系统调用的关键。
  2. 计算机无法在立即准备执行C代码的状态下启动。对于Intel示例,当执行进入启动例程时,处理器可能不处于32位模式(或64位模式),并且C所需的堆栈也可能没有准备好。某些处理器中存在一些其他功能(如分页),这些功能也需要从程序集中打开。
  3. 但是,大多数Linux内核都是用C语言编写的,它通过标准化接口与一些特定于平台的C /汇编代码进行交互。通过以这种方式分离部分,Linux内核的大多数逻辑可以在平台之间共享。构建系统只是为特定平台编译平台独立和相关部分,这导致不同平台(以及内核配置)的不同可执行内核文件。

答案 3 :(得分:0)

Linux不是Unix的第二个版本(或者通常是Unix)。它与Unix兼容,但Unix和Linux具有单独的历史记录,并且在代码库(其内核)方面是完全独立的。 Linus Torvald的想法是编写一个开源的Unix。

一些较低级别的内容,例如内存管理的一些与体系结构相关的部分,都是在汇编中完成的。用于x86的旧(但仍可用)Linux内核API,int 0x80,在程序集中实现。内核中可能还有其他地方在汇编中实现,但我不知道其他任何地方。

编译内核时,选择要定位的体系结构。根据目标,该体系结构的正确程序集文件包含在构建中。

您找不到任何内容的原因是因为您正在搜索标题,而不是搜索来源。从kernel.org下载tar球并搜索。

答案 4 :(得分:0)

内核中的汇编代码通常用于无法直接从C完成的低级硬件交互。它们就像是一个特定于平台的基础,被内核的更高级别部分使用下进行。

内核源代码树包含各种系统的汇编代码。为特定类型的系统(例如x86 PC)编译内核时,只有该平台的相应汇编代码包含在构建过​​程中。