对 _GLOBAL_OFFSET_TABLE_ 的未定义引用(仅在生成二进制文件时)

undefined reference to _GLOBAL_OFFSET_TABLE_ (only when generating binaries)

这是问题所在:
当我在 C 中使用 ld link 我的脚本时,当我在 ld 中生成 elf32-i386 文件作为输出格式时,将其作为 OUTPUT_FORMAT() 放在 ld 脚本中,我没有任何错误,但是如果我尝试输入最后一个 OUTPUT_FORMAT() "binary" 或尝试输出扩展名为 .bin 的文件,我会得到混合错误,例如:

kernel.o: In function `k_main':
kernel.c:(.text+0xe): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen':
kernelutils.c:(.text+0xc): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen_front':
kernelutils.c:(.text+0x56): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_printf':
kernelutils.c:(.text+0xa0): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_sleep_3sec':
kernelutils.c:(.text+0x152): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelmalloc.o:kernelmalloc.c:(.text+0xc): more undefined references to `_GLOBAL_OFFSET_TABLE_' follow

这不仅发生在编译特定脚本时,所有尝试使用 ld 到 link 或 gcc 的脚本,因为这会调用 ld,在尝试获取扩展名为 .bin 的二进制文件时失败。
当显示其中一个可执行文件的符号(上面输出中的 kernel.o )时,我看到符号 _GLOBAL_OFFSET_TABLE_ 未定义,最可怕的部分是所有在错误输出中返回错误的函数以上的符号已删除,这是 nm 输出:

cristian@mymethodman:~/Desktop/kernel/0.0.3/Archivos$ nm kernel.o
         U _GLOBAL_OFFSET_TABLE_
         U k_clear_screen
         U k_clear_screen_front
00000000 T k_main
         U k_malloc
         U k_printf
         U k_sleep_3sec
00000000 T __x86.get_pc_thunk.bx

我该如何解决这个问题?我将在下面留下 linker 脚本,以确保它是 .ld 文件的问题,具有 "to get elf" 和 "to get binary" 版本。提前致谢!

Ld 脚本:
获取二进制文件:

ENTRY(loader)
OUTPUT_FORMAT(binary)

SECTIONS {
   /* The kernel will live at 3GB + 1MB in the virtual
      address space, which will be mapped to 1MB in the
      physical address space. */
   . = 0xC0100000;

   .text : AT(ADDR(.text) - 0xC0000000) {
       *(.text)
       *(.rodata*)
   }

   .data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
       *(.data)
   }

   .bss : AT(ADDR(.bss) - 0xC0000000) {
       _sbss = .;
       *(COMMON)
       *(.bss)
       _ebss = .;
   }
}

获取ELF:

ENTRY(loader)
OUTPUT_FORMAT(elf32-i386)

SECTIONS {
   /* The kernel will live at 3GB + 1MB in the virtual
      address space, which will be mapped to 1MB in the
      physical address space. */
   . = 0xC0100000;

   .text : AT(ADDR(.text) - 0xC0000000) {
       *(.text)
       *(.rodata*)
   }

   .data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
       *(.data)
   }

   .bss : AT(ADDR(.bss) - 0xC0000000) {
       _sbss = .;
       *(COMMON)
       *(.bss)
       _ebss = .;
   }
}

如您所见,两者之间只更改了 OUTPUT_FORMAT() 行。

您的工具链可能默认生成与位置无关的可执行文件 (PIE)。尝试使用 gcc -fno-pie.

进行编译

如果出于安全原因想要保留 PIE,则需要更复杂的链接描述文件和执行初始重定位的东西(例如动态链接器,但也可以使用更简单的构造)。