编译 GAS 代码未检测到 -fPIC 选项

Compiling GAS code doesn't detect -fPIC option

我正在尝试使用 GCC gnu 编译器为项目编译一些 GAS 代码。以下是我的编译方式:

gcc -c boot.s -o boot.o -fPIC

在我使用 -fPIC 参数编译我的 kernel.c 文件后,我尝试使用此命令 link 它:

gcc -N -T linker.ld -o Slack\ Berry.bin -ffreestanding -nostdlib kernel.o boot.o -lgcc

结果是:

/usr/bin/ld: boot.o: relocation R_X86_64_32 against '.multiboot' can not be used when making a PIE object; recompile with -fPIC

这让我认为它没有用 -fPIC 编译我的 GAS 代码。我该如何解决这个问题?

首先你可能需要 -fPIE 而不是 -fPIC-fPIE 允许编译器生成更高效的代码,但只能用于作为主要可执行文件(而非共享库)一部分的代码。

现在 -fPIC-fPIE 都是编译器专用标志,不会传递给汇编程序。您需要在汇编代码中明确使用特定于 PIC 的助记符,而不是位置相关的调用和分支,例如,而不是

movq $bar, %rdx

使用

movq bar@GOTPCREL(%rip), %rdx

(通常为了获得我需要的语法,我只是 运行 gcc -fPIE -S -o- 在匹配的 C 片段上)。

Recompile with -fPIC 仅适用于 asm 由编译器生成,而不是手工编写的情况。它对 asm 如何汇编成机器代码没有影响。

问题是您的 PIE 可执行文件无法与 32 位绝对地址链接。 (您的意思是制作 PIE 而不是静态位置相关的可执行文件)?

您不需要完整的共享库内容来引用另一个库或主要可执行文件中的符号(如@yugr 的回答显示了如何做)。您的独立内核甚至可能 没有 GOT 或 PLT,绝对不应该将它们用于内部符号。

唯一需要的更改是 lea bar(%rip), %rdx,一个 RIP 相关的 LEA 而不是 mov $imm32, %r/m64。 (movabs 可以工作,但更大而且通常更慢。)

或者,如果您实际上打算使用 -static 构建并创建一个将加载到地址 space 低 32 位固定地址的可执行文件,您应该使用 mov $bar, %edx 以获得 5 字节 mov $imm32, %r32 编码而不是 7 字节 mov $sign_extended_imm32, %r/m64 或 7 字节 LEA。另见