在“重定位具有无效符号索引”错误期间会发生什么?
这是一个重现问题的测试:
$ echo "void whatever() {}" > prog.c $ gcc prog.c
这会在GCC 4.8.4上产生以下错误:
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2 ... etc ... /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 21 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2 /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x20): undefined reference to `main' collect2: error: ld returned 1 exit status
请注意,在GCC 6.2.0上,与此问题相关的错误消失了,而它只产生:
/usr/lib/x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x20): undefined reference to `main' collect2: error: ld returned 1 exit status
许多用户,Stack Overflow和其他地方已经多次报告过这种情况。
我想了解这个错误,而不是解决它(它已经解决了)。
执行gcc-4.8 prog.c
而没有gcc-4.8 prog.c
的main()
函数时会发生此错误。
我在binutils-source包上对这个错误进行了文本搜索。 一个乏味的谷歌搜索只给了我一个有用的链接,帮助我更好地理解重定位处理的概念 。
错误的数量似乎并不依赖于程序,这表明考虑的重定位不是源于此文件,而是缺少main()
函数的直接结果。 我假设其中3个带有错误索引的重定位可能适用于main()
, argc
和argv
,但许多仍然存在,这只是一个未经证实的假设。
这完全超出了我的想象,任何有助于我更好地理解它的信息,或者在GCC的后续版本中发生了哪些变化,都将受到热烈欢迎。
C程序function(类Unix)
- 每个程序都分别编译成精灵格式
- c程序可以使用外部变量/函数引用,后面链接
-
main
不是你原先想到的程序的开始,c lib有一个启动程序(crt1.o
),它有一个_start
程序,它将在main
之后调用我们的main
和docrt1.o
工作 - 总结以上陈述,我们可以知道即使是一个非常简单的OP程序也需要联系起来
ELF格式
ELF有两个标题,如下所示:
- section header – 用于链接多个elf以制作流程图像
- 程序头 – 用于加载过程映像
这里我们只关注节头结构:
mapping // and special cases mapping
每个程序都是单独编译的,这意味着地址分配是相似的(在Linux的早期版本中,每个编译的程序都以相同的虚拟地址 – 0x08000000
,并且许多攻击可以利用这个,所以它改为添加一些随机增量到解决问题的地址),因此可能存在一些覆盖区域。 这就是需要重新定位地址的原因。
搬迁
重定位信息(偏移量,值等)存储在.rel.*
部分中:
Relocation section '.rel.text' at offset 0x7a4 contains 2 entries: Offset Info Type Sym.Value Sym. Name 0000000d 00000e02 R_386_PC32 00000000 main 00000015 00000f02 R_386_PC32 00000000 exit Relocation section '.rel.debug_info' at offset 0x7b4 contains 43 entries: Offset Info Type Sym.Value Sym. Name 00000006 00000601 R_386_32 00000000 .debug_abbrev 0000000c 00000901 R_386_32 00000000 .debug_str
当链接器想要在重定位过程中设置main
的地址时,它无法在已编译的elf文件中找到符号,因此它会抱怨并停止链接过程。
例
这是os实现的简化版本, start.c对应于crt1.o
的源代码:
int entry(char *); // corresponds to main void _start(char *args) { entry(args); exit(); }
参考
- ELF
- 搬迁
不是直接编译代码,而是经历编译的所有阶段以找出错误发生的位置(据我所知,在链接期间会发生这样的错误)。 以下gcc
参数将有所帮助:
-
-E
仅预处理; 不编译,汇编或链接 -
-S
仅编译; 不要组装或链接 -
-c
编译和汇编,但不要链接
现在:
gcc -E prog.c gcc -S prog.c gcc -c prog.c
使用您提到的程序/代码,所有这些步骤都适用于gcc 4.8.4。 但是,在链接期间,当您使用gcc prog.c
进行编译时,编译器无法链接到相应的库,因为它没有被提及。 另外,我们在prog.c
文件中没有main
函数。 所以,我们需要指明-nostartfiles
开关。 因此,您可以将prog.c
编译为:
gcc prog.c -lc -nostartfiles
这会产生警告:
/ usr / bin / ld:警告:找不到条目符号_start; 默认为00000000004002a3
这是因为序列。 即, init
调用_start
函数, _start
函数调用main
函数。 此警告意味着_start
函数无法找到main
函数,其中init
调用无法找到_start
。 请注意,这只是一个警告。 为了避免这种警告,我们需要将命令更改为编译而不发出警告,如下所示。
gcc prog.c -lc --entry whatever -nostartfiles
使用此命令,我们指示内核使用gcc
编译prog.c
方法是将libc.so
库与起始点链接为函数,其中此代码不包含main
函数。
这是我编译的gcc 4.8.4的上下文。
来到gcc 6.2.0的情况,我认为所有这些链接的东西都由编译器本身来处理。 因此,您可以简单地提及编译命令,如下所示。
gcc -c prog.c -nostartfiles
如果它产生任何其他错误或警告,您可以使用上面提到的开关。
另请注意,在init
调用_start
之前执行crt0
到crtN
( N
依赖于ELF文件),这会提供有关内存和其他机器相关参数的元数据。 链接错误显示为
/ usr / bin / ld:/usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info):重定位0具有无效的符号索引11
不提供纠正问题的完整信息,因为机器在识别错误点方面不如人类聪明。
这将生成完整的可执行文件。 请注意,当我们处理项目中的库/模块时,会使用这样的代码(没有main函数)。
提供的所有数据都是通过逐步分析完成的。 您可以重新创建所有提到的步骤。 希望这清除了你的怀疑。 美好的一天!
我们可以将其分为两部分:
对’main’的未定义引用
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x20): undefined reference to `main' collect2: error: ld returned 1 exit status
这只是因为C运行时库( crt1.o
)正在尝试调用您的(缺少的) main()
函数。 这里 / 这里有各种C运行时文件的概述。
重定位X具有无效的符号索引Y.
注意 :这对我来说是一个使命(学习机会) – 我花了几天时间在有限的空闲时间内进行研究和理解。 这是我长期以来一直想知道的事情,但从未考虑过……希望我的理解是正确的(虽然显然不完整 – 如果可以,我会更新它)。
这有点复杂,隐藏起来。
只需阅读消息,我们就可以发现它与调试信息有关(提到了crt1.o
调试文件的.debug_info
和.debug_line
部分)。 注意/usr/lib/debug/
path, crt1.o
包含调试信息,另一个crt1.o
是一个“ 剥离 ”文件…
格式字符串位于binutils
项目中,特别是bfd/elfcode.h
。 BFD是二进制文件描述符 – 在许多系统体系结构中处理目标文件的GNU方法。
BFD是用于二进制文件的中间格式 – GCC在最终写入a.out
, ELF
或其他二进制文件之前将使用BFD。
查看手册,我们可以找到一些有趣的知识片段:
[…]对于散列表中的每个条目,a.out链接器保留符号在最终输出文件中具有的索引(使用此索引号,以便在执行可重定位链接时,输出文件中使用的符号索引可以复制重定位时快速填写)。 [资源]
标准记录仅包含地址,符号索引和类型字段。 [资源]
这意味着由于与特定(缺少?)’符号’相关的重定位而发出这些错误。 在此上下文中的“符号”是任何命名的“事物” – 例如:函数和变量。
由于这些“无效符号”似乎是通过简单地声明main()
来解决的,我猜这些符号索引中的一些(全部?)是从main()
,它的调试信息和/或关系派生的。
我不能告诉你在提到的符号索引(2,11,12,13,21)应该是什么,但有趣的是我的测试产生了相同的符号索引列表。
单独使用crt1.o
运行ld
会给我们类似的输出:
$ ld /usr/lib/x86_64-linux-gnu/crt1.o ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 11 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 12 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 21 ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2 /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x12): undefined reference to `__libc_csu_fini' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x19): undefined reference to `__libc_csu_init' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x20): undefined reference to `main' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x25): undefined reference to `__libc_start_main'