Gcc 未定义的对_全局_偏移量_表的引用(仅在生成二进制文件时)

Gcc 未定义的对_全局_偏移量_表的引用(仅在生成二进制文件时),gcc,linker,linker-errors,ld,osdev,Gcc,Linker,Linker Errors,Ld,Osdev,这就是问题所在: 当我使用ld在C中链接脚本时,当我在ld中生成elf32-i386文件作为输出格式时,将其作为ld脚本中的output_format(),我没有任何错误,但是如果我尝试将最后一个output_format()“binary”或尝试输出一个扩展名为.bin的文件,我会遇到如下错误: kernel.o: In function `k_main': kernel.c:(.text+0xe): undefined reference to `_GLOBAL_OFFSET_TABLE_'

这就是问题所在:
当我使用ld在C中链接脚本时,当我在ld中生成elf32-i386文件作为输出格式时,将其作为ld脚本中的output_format(),我没有任何错误,但是如果我尝试将最后一个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-to-link或gcc(因为它调用ld)的脚本都会在尝试获取扩展名为.bin的二进制文件时死亡。
当显示其中一个可执行文件的符号(上面的输出中的kernel.o)时,我看到符号_GLOBAL_OFFSET_TABLE_uu未定义,最可怕的是,在上面的错误输出中返回错误的所有函数都删除了它们的符号,这是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
我怎样才能解决这个问题?我将保留下面的链接器脚本,以确保它不是.ld文件的问题,同时具有“togetelf”和“togetbinary”版本。提前谢谢

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 = .;
   }
}

正如你所看到的,两者之间只会更改输出格式()行。

你的工具链可能默认为生成位置独立的可执行文件(PIE)。尝试使用
gcc-fno pie
编译


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

看起来像您的主机GCC环境(可能是Ubuntu 16.04+或Debian 9+之类的更新版本)正在生成与位置无关的代码。使用GCC编译时,您可能希望尝试使用
-fno pic
编译所有文件。这是在操作系统开发中使用GCC交叉编译器的一个很好的理由。您可以在这里阅读关于创建一个的内容:谢谢,我将在旁注上构建交叉编译器-为什么要生成二进制文件?我知道您以前使用的是多引导兼容加载程序。使用二进制文件可能会导致问题,除非您现在正在编写自己的引导加载程序,或者您已经更改了多重引导头以支持a.out kludge。@MichaelPetch我也遇到了类似的问题,我正在尝试调试。我将
-fpie
与GCC一起使用,但链接器正在发出get相对重定位条目。我确信我使用了一组不正确的输入标志来实现这一点(即使将二进制文件输入到IDA Pro中,它也会向我报告二进制文件使用了“非标准”重定位!)。有什么想法吗?与OP类似,
\u GLOBAL\u OFFSET\u TABLE\u
未定义,并且没有
.get
部分。事实上,从参数集中删除
-fpic
可以防止get相对重定位(现在是ABS)(但仍然没有
.get
部分)。你能帮我理解一下吗?我遇到了类似的问题。我已经为ARM目标编写了一个运行时ELF重定位程序,链接器将发出GET相对重定位条目。与此处所示的方式相同,这里有一个符号
\u GLOBAL\u OFFSET\u TABLE\u
,但它未定义且未与任何节关联(因为没有发出
.get
节)。我明确地将代码编译为PIE(.e.g.
-fpie
)。在生成饼图代码时,需要以何种方式使用更复杂的链接器脚本?如果有必要的话,他也在使用GCC。删除
-fpie
阻止了这种情况的发生。为什么呢?