在 x86 平台中使用 -mcmodel=kernel 标志

use of -mcmodel=kernel flag in x86 platform

我正在尝试交叉编译为 x86 架构构建的设备驱动程序以用于 arm 平台。它编译没有任何错误,但我不认为所有功能都可用。所以我检查了 makefile 并找到了这个特定部分。

ifeq ($(ARCH),x86_64)
    EXTRA_CFLAGS += -mcmodel=kernel -mno-red-zone

这似乎是唯一依赖于体系结构的部分。在 google 上一段时间后,我发现 -mcmodel=kernel 用于内核代码模型,-mno-red-zone 用于避免在内存中使用红色区域,它们都是用于 x86_64。但我不清楚,将 cmodel 设置为内核有什么影响?

(对 arm 问题的任何见解也非常感谢。)

The x86 Options section of the GCC manual 说:

-mcmodel=kernel

Generate code for the kernel code model. The kernel runs in the negative 2 GB of the address space.

(即上部 2GiB,地址如 0xfffffffff0001234

在内核代码模型中,静态符号地址不适合 32 位 zero-extended 常量(不同于默认的小代码模型,其中 mov eax, imm32(5 字节)是最有效的方式将符号地址放入寄存器)。

但是它们 适合 sign-extended 32 位常量,这与 large 代码模型不同。所以 mov rax, sign_extended_imm32 (7 个字节)可以工作,并且大小相同但可能比 lea rax, [rel symbol].

效率稍高

但更重要的是 mov eax, [table + rdi*4] 有效,因为 disp32 位移是 sign-extended 到 64 位。 -mcmodel=kernel 告诉 gcc 它可以做到这一点但 mov eax, table.


RIP-relative 寻址也可以从任何代码地址到达任何符号(具有 rel32 +-2GiB 偏移量),因此 -fPIC-fPIE 也将使您的代码工作,在在有用的情况下不利用 32 位绝对寻址的小代价。 (例如索引静态数组)。

如果没有 -mcmodel=kernellike these), you probably have a gcc that makes PIE executables by default(在最近的发行版中很常见),那么它就避免了绝对寻址。