在“重定位具有无效符号索引"期间发生什么?错误? [英] What happens during a "relocation has invalid symbol index" error?
问题描述
以下是重现该问题的测试:
Here is a test reproducing the problem:
$ echo "void whatever() {}" > prog.c
$ gcc prog.c
这会在GCC 4.8.4上产生以下错误:
This produces the following error on 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上,与此问题相关的错误消失了,而是产生了:
Note that on GCC 6.2.0 the errors related to this question disappear, and it instead produces just:
/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和其他地方对此进行了多次报道.
This has been reported a number of times by a number of users, on Stack Overflow, and elsewhere.
我想理解这个错误,而不是解决它(已经解决了).
I would like to understand this error, not solve it (it is already solved).
在gcc-4.8 prog.c
中没有main()
函数的情况下执行gcc-4.8 prog.c
时,会发生此错误.
This error happens when doing gcc-4.8 prog.c
without a main()
function inside prog.c
.
我已经在binutils-source软件包上针对此错误进行了文本搜索.繁琐的谷歌搜索仅给了我一个有用的链接,可以帮助我更好地理解搬迁处理的概念.
I have done a text search for this error on the binutils-source package. A tedious googling gave me only one useful link helping me better understanding the concept of relocation handling.
错误的数量似乎并不取决于程序,这表明所考虑的重定位不是起源于此文件,而是由于缺少main()
函数的直接结果.我假设这些索引错误的重定位中的3个可能是针对main()
,argc
和argv
的,但仍有很多,这只是一个未经证实的假设.
The number of errors does not seem to depend on the program, which suggests the relocations in consideration do not originate in this file, but as a direct result of the missing main()
function. I have hypothesized that 3 of these relocations with wrong indexes might be for main()
, argc
and argv
, but many remain, and this is just an unproven hypothesis.
这是我的头等大事,我们将热情欢迎您提供任何有助于我更好地理解它的信息,或在以后版本的GCC中进行的更改.
This is quite above my head, and any information that helps me better understand it, or what changed in later versions of GCC, would be warmly welcome.
推荐答案
C程序功能(类似于Unix)
- 每个程序都分别编译为elf格式
- c程序可以使用外部变量/函数引用,稍后将对其进行链接
-
main
不是您最初认为的程序的开始,c lib具有一个启动程序(crt1.o
),该程序具有一个_start
程序,该程序将调用我们的main
并在main
之后执行清理工作 - 在上述结论中,我们可以知道,即使一个非常简单的程序(如OP所示)也需要链接
- every program is compiled separately into elf format
- c program can use external variable/function reference, which is linked later
main
is not the start of program as you originally thought, c lib has a starter program (crt1.o
) which has a_start
program which will invoke ourmain
and do cleaning job aftermain
- concludes above statement, we can know that even a very simple program as OP showed need to be linked
- 节标题-用于链接多个小精灵以制作过程映像
- 程序头-用于加载过程映像
C Program Features (Unix-like)
ELF有两个标头,如下所示:
ELF has two headers, as following shows:
在这里,我们仅关注节标题结构:
Here we only focus on section header structure:
mapping<var_name, offset, size...>
// and special cases
mapping<external_var_name, offset, size...>
每个程序都是单独编译的,这意味着地址分配是相似的(在linux的早期版本中,每个编译程序都以相同的虚拟地址-0x08000000
开头,许多攻击都可以利用此地址,因此它更改为添加一些随机增量来解决该问题),因此可能存在一些重叠区域.这就是为什么需要地址重定位的原因.
Every program is compiled separately, which means address allocation is similar (In the early version of linux, every compiled program start with same virtual address -- 0x08000000
, and many attacks can make use of this, so it changes to adding some random delta to address to alleviate the problem), so there may exists some overlay area. This is why address relocation needed.
重定位信息(偏移量,值等)存储在.rel.*
部分:
The relocation info (offset, value etc) is stored in .rel.*
section:
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文件中找不到符号,因此它抱怨并停止了链接过程.
When the linker want to set the address of main
in the process of relocation, it can't find a symbol in your compiled elf file, so it complains that and stop the linking process.
此处是os实现的简化版本,
Here is the simplified version of os implementations, start.c corresponds to crt1.o
's source code:
int entry(char *); // corresponds to main
void _start(char *args) {
entry(args);
exit();
}