我正在尝试交叉编译为 x86 架构构建的设备驱动程序以武装平台。它的编译没有任何错误,但我认为没有完整的功能可用。所以我检查了制作文件并找到了这个特定的部分。
ifeq ($(ARCH),x86_64)
EXTRA_CFLAGS += -mcmodel=kernel -mno-red-zone
这似乎是唯一依赖于架构的部分。在谷歌上呆了一段时间后,我发现 -mcmodel=kernel 用于内核代码模型,而 -mno-red-zone 是为了避免在内存中使用红色区域,它们都是用于x86_64的。但是我不清楚,将cmodel设置为内核有什么影响?
(对手臂问题的任何见解也非常感谢。
GCC 手册的x86 选项部分说:
-mcmodel=kernel
为内核代码模型生成代码。内核在负 2 GB 的地址空间中运行。
(即上部 2GiB,地址类似于0xfffffffff0001234
)
在内核代码模型中,静态符号地址不适合 32 位零扩展常量(与默认的小代码模型不同,其中mov eax, imm32
(5 字节)是将符号地址放入寄存器的最有效方法)。
但它们确实适合符号扩展的 32 位常量,这与large
代码模型不同。 所以mov rax, sign_extended_imm32
(7 字节)有效,大小相同,但可能比lea rax, [rel symbol]
效率略高。
但更重要的是mov eax, [table + rdi*4]
工作,因为disp32位移被符号扩展到64位。-mcmodel=kernel
告诉海湾合作委员会它可以做到这一点,但不能mov eax, table
。
RIP相对寻址也可以从任何代码地址(具有rel32 +-2GiB偏移量)到达任何符号,因此-fPIC
或-fPIE
也可以使您的代码正常工作,代价是在有用的情况下不利用32位绝对寻址。 (例如,索引静态数组)。
如果您在没有-mcmodel=kernel
的情况下没有收到链接错误(例如这些),您可能有一个 gcc 默认情况下使 PIE 可执行文件(在最近的发行版中很常见),因此它避免了绝对寻址。