当内核开发人员想要编写程序集时,他们是编写高级代码并使用编译器对其进行转换还是直接编写程序集?

时间:2018-08-16 06:43:07

标签: assembly kernel

我读到例如Linux的某些部分正在汇编中,我想它们是在汇编中编写的,以提高执行速度

但是,现代的内核开发人员实际上是在需要时直接用汇编语言直接编写,还是用高级语言编写并使用编译器将其转换为汇编语言,而是使用转换后的汇编代码?

哪种方法更好?考虑到编译器也对代码进行了优化,难道不是将高级转换为汇编的效率更高吗?我真的需要在汇编中编写内核的哪些部分?

2 个答案:

答案 0 :(得分:6)

  

我读到例如Linux的某些部分正在汇编中,我想它们是在汇编中编写的,以提高执行速度

通常不会,因为C语言不支持某些操作(例如,在x86 CPU上切换到保护模式需要写才能注册哪种C语言不知道的内容),所以它们会在汇编中编写[微小]的内核部分。 / p>

然后再说一次,C非常适合内核之类的东西(它是一种“低级”语言,尽管我编程的时间越长,这些类别对我来说就越混乱,这时我相信其中之一最高抽象级别的编程语言实际上是C ++,但是许多人不同意我的观点,但是如果需要,您可以很容易地在C ++中获得相当低的级别),因此大多数事情都可以直接用它编写,这只是非常会影响目标计算机某些特定功能的小部件,必须使用asm代码最终确定。

例如,考虑诸如内存管理器之类的东西。关于它的大多数事情(跟踪可用/已分配页面,用于不同进程的虚拟内存映射等)都是普通数据结构中的普通数字,并且可以轻松处理但是为特定进程设置最终的虚拟内存布局可能需要不同的指令,具体取决于目标计算机及其MMU设计,因此汇编中可能有一小部分会强制执行用C计算的内容。

答案 1 :(得分:3)

很少有Linux用asm编写以提高性能。请参阅@ Ped7g的答案,以获取更多有关内核为何将内联asm用于偶尔的特权指令(例如到控制寄存器的mov或将手写asm的整个文件用作入口点(例如中断)的更多信息的信息。  和分配给C函数的系统调用处理程序入口点。


在Linux中,也许只是RAID5 xor奇偶校验(在x86上使用SSE2或AVX)和RAID6纠错是为了提高性能而写在asm中的。

大概是直接用asm编写的,因为使用C进行内在函数手动矢量化并不容易。在那些Linux函数IIRC中,仍使用C进行循环。

(而且它使用的样式非常糟糕,有多个使用XMM或YMM寄存器的单独asm("")语句。这恰好起作用,尤其是在内核代码中,编译器将永远不会生成使用XMM寄存器的代码,但是使用单个asm块或矢量输出/输入操作数会更安全,请参见Linux's lib/raid6/sse2.c。还有asm/xor.h也具有一些通用的块异或功能,并且在asm中完成了循环,大概是内核的其他部分使用的。)这是它使用SIMD向量寄存器的少数几个地方之一,因为保存/恢复FPU状态非常昂贵。

如果可能,Linux可能会使用内联asm来提高x86 CRC32指令的性能;有些东西使用了x86加速的CRC32C多项式。


对于您问题的更一般情况,使用编译器生成的asm作为优化的起点通常是个好主意

但是,如果编译器已经发出了良好的asm,则您无需执行任何操作即可使用C。这甚至比内联asm更好,因为它可以通过常量传播等进行优化。或者,您可以调整C源代码以帮助编译器执行更有效的工作。

但是,如果您不能使编译器进行最佳循环,那么请确保可以采用它的asm并手动对其进行优化。只要您以原始版本为基准进行测试,就不会输给编译器。 (除非您的asm在进行内联时使优化失败,否则会使某些内容成为编译时常量。)

有关帮助与击败编译器的更多详细信息,请参见C++ code for testing the Collatz conjecture faster than hand-written assembly - why?

您只考虑对软件的非常关键的部分使用手写的asm循环,尤其是在像Linux这样的可移植代码库中,因为每个平台都需要不同的实现。

由于Skylake的最佳性能不是20年前P5 Pentium的最佳性能,而且从20年以后的某些未来x86可能不是最佳的性能。坚持使用可移植的C语言,可以使-march=skylake之类的调整选项发挥作用,并针对您要编译的特定微体系结构调整asm。 (或者让编译器中的更新默认调整多年来可以生效。)

更不用说大多数内核开发人员都不是asm调整专家,他们可以轻松地手工编写接近最佳的asm。人们通常不会这样做。如果您喜欢这样做,请使用gcc或clang使其从C生成更优化的代码。