The x86 选项GCC 手册的部分 https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html says:
-mcmodel=kernel
为内核代码模型生成代码。内核在负 2 GB 的地址空间中运行。
(即上面的 2GiB,地址如0xfffffffff0001234
)
在内核代码模型中,静态符号地址不适合 32 位零扩展常量(与默认的小代码模型不同,其中mov eax, imm32
(5 个字节)是将符号地址放入寄存器的最有效方法)。
但他们do适合符号扩展的 32 位常量,与large
例如代码模型。所以mov rax, sign_extended_imm32
(7 字节)可以工作,并且大小相同,但可能比lea rax, [rel symbol]
.
但更重要的是mov eax, [table + rdi*4]
可以工作,因为 disp32 位移已符号扩展为 64 位。-mcmodel=kernel
告诉 gcc 它可以做到这一点,但不能mov eax, table
.
RIP 相对寻址还可以从任何代码地址(具有 rel32 +-2GiB 偏移量)到达任何符号,因此-fPIC
or -fPIE
也将使您的代码正常工作,但代价是在有用的情况下不利用 32 位绝对寻址。 (例如索引静态数组)。
如果您没有收到链接错误-mcmodel=kernel
(像这些 https://wiki.osdev.org/Building_libgcc_for_mcmodel%3Dkernel),你可能有默认情况下生成 PIE 可执行文件的 gcc https://stackoverflow.com/questions/43367427/32-bit-absolute-addresses-no-longer-allowed-in-x86-64-linux(在最近的发行版中很常见),因此它避免了绝对寻址。