在“重定位具有无效符号索引”错误期间会发生什么?

时间:2021-01-18 15:28:54

Here is a test reproducing the problem:

这是一个重现问题的测试:

$ echo "void whatever() {}" > prog.c
$ gcc prog.c

This produces the following error on GCC 4.8.4:

这会在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

Note that on GCC 6.2.0 the errors related to this question disappear, and it instead produces just:

请注意,在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

This has been reported a number of times by a number of users, on Stack Overflow, and elsewhere.

许多用户,Stack Overflow和其他地方已经多次报告过这种情况。

I would like to understand this error, not solve it (it is already solved).

我想了解这个错误,而不是解决它(它已经解决了)。

This error happens when doing gcc-4.8 prog.c without a main() function inside prog.c.

执行gcc-4.8 prog.c而没有prog.c中的main()函数时会发生此错误。


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.

我在binutils-source包上对这个错误进行了文本搜索。一个乏味的谷歌搜索只给了我一个有用的链接,帮助我更好地理解重定位处理的概念。

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.

错误的数量似乎并不依赖于程序,这表明考虑的重定位不是源于此文件,而是缺少main()函数的直接结果。我假设其中3个带有错误索引的重定位可能适用于main(),argc和argv,但许多仍然存在,这只是一个未经证实的假设。

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.

这完全超出了我的想象,任何有助于我更好地理解它的信息,或者在GCC的后续版本中发生了哪些变化,都将受到热烈欢迎。

3 个解决方案

#1


4  

C Program Features (Unix-like)

  • every program is compiled separately into elf format
  • 每个程序都分别编译成精灵格式

  • c program can use external variable/function reference, which is linked later
  • c程序可以使用外部变量/函数引用,后面链接

  • 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 our main and do cleaning job after main
  • main不是你原先想到的程序的开始,c lib有一个启动程序(crt1.o),它有一个_start程序,它将在main之后调用我们的main和do clean工作

  • concludes above statement, we can know that even a very simple program as OP showed need to be linked
  • 总结以上陈述,我们可以知道即使是一个非常简单的OP程序也需要联系起来

ELF Format

ELF has two headers, as following shows:

ELF有两个标题,如下所示:

  • section header -- used to link multiple elf to make process image
  • section header - 用于链接多个elf以制作流程图像

  • program header -- used to load process image
  • 程序头 - 用于加载过程映像

Here we only focus on section header structure:

这里我们只关注节头结构:

    mapping<var_name, offset, size...>
    // and special cases
    mapping<external_var_name, offset, size...>

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.

每个程序都是单独编译的,这意味着地址分配是相似的(在Linux的早期版本中,每个编译的程序都以相同的虚拟地址 - 0x08000000开始,并且许多攻击可以利用这个,所以它改为添加一些随机增量到解决问题的地址),因此可能存在一些覆盖区域。这就是需要重新定位地址的原因。

Relocation

The relocation info (offset, value etc) is stored in .rel.* section:

重定位信息(偏移量,值等)存储在.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

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.

当链接器想要在重定位过程中设置main的地址时,它无法在已编译的elf文件中找到符号,因此它会抱怨并停止链接过程。

Example

Here is the simplified version of os implementations, start.c corresponds to crt1.o's source code:

这是os实现的简化版本,start.c对应于crt1.o的源代码:

    int entry(char *); // corresponds to main

    void _start(char *args) {
        entry(args);
        exit();
    }

Ref

#2


3  

Instead of compiling the code directly, go through all the stages of compilation to figure out where the error is arising (as far as I know, such errors occur during linking). Following gcc arguments will be helpful:

不是直接编译代码,而是经历编译的所有阶段以找出错误发生的位置(据我所知,在链接期间会发生这样的错误)。以下gcc参数将有所帮助:

  • -E Preprocess only; do not compile, assemble or link
  • -E仅预处理;不编译,汇编或链接

  • -S Compile only; do not assemble or link
  • -S仅编译;不要组装或链接

  • -c Compile and assemble, but do not link
  • -c编译和汇编,但不要链接

Now:

gcc -E prog.c
gcc -S prog.c
gcc -c prog.c

With the program/code you have mentioned, all these steps are working perfect with gcc 4.8.4. But, during linking, when you compile using gcc prog.c, the compiler is unable to link with respective library, as it was not mentioned. Also, we have no main function in the prog.c file. So, we need to indicate -nostartfiles switch. Hence, you can compile prog.c as:

使用您提到的程序/代码,所有这些步骤都适用于gcc 4.8.4。但是,在链接期间,当您使用gcc prog.c进行编译时,编译器无法链接到相应的库,因为它没有被提及。另外,我们在prog.c文件中没有main函数。所以,我们需要指明-nostartfiles开关。因此,您可以将prog.c编译为:

gcc prog.c -lc -nostartfiles

This produces the warning:

这会产生警告:

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 00000000004002a3

/ usr / bin / ld:警告:找不到条目符号_start;默认为00000000004002a3

This is because of the sequence. i.e., init calls _start function and the _start function calls main function. This warning means that the _start function is unable to locate main function, where the init call is unable to locate _start. Please note that this is just a warning. In order to avoid this warning, we need to change the command to compile without warnings as follows.

这是因为序列。即,init调用_start函数,_start函数调用main函数。此警告意味着_start函数无法找到main函数,其中init调用无法找到_start。请注意,这只是一个警告。为了避免这种警告,我们需要将命令更改为编译而不发出警告,如下所示。

gcc prog.c -lc --entry whatever -nostartfiles

With this command, we are instructing the kernel to compile prog.c using gcc by linking the libc.so library with the starting point as the function whatever, where this code contains no main function.

使用此命令,我们指示内核使用gcc编译prog.c,方法是将libc.so库与起始点链接为函数,其中此代码不包含main函数。

This is the context with gcc 4.8.4, which I've compiled on.

这是我编译的gcc 4.8.4的上下文。

Coming to the case of gcc 6.2.0, I think all these linking stuff is taken care by the compiler itself. Hence, you can simply mention the compiling command as shown below.

来到gcc 6.2.0的情况,我认为所有这些链接的东西都由编译器本身来处理。因此,您可以简单地提及编译命令,如下所示。

gcc -c prog.c -nostartfiles

If it produces any other errors or warnings, you can use the switches mentioned above.

如果它产生任何其他错误或警告,您可以使用上面提到的开关。

Also, note that crt0 through crtN (N depends on the ELF file) are executed before the init calls _start, which gives the metadata about the memory and other machine dependent parameters. The linking errors shown as

另请注意,在init调用_start之前执行crt0到crtN(N依赖于ELF文件),这会提供有关内存和其他机器相关参数的元数据。链接错误显示为

/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):重定位0具有无效的符号索引11

do not provide complete information for rectifying the issue, as machines are not as smart as human beings in identifying the point of error.

不提供纠正问题的完整信息,因为机器在识别错误​​点方面不如人类聪明。

This produces a complete executable file. Please do notice that such code (without main function) is used when we are working on libraries/modules within a project.

这将生成完整的可执行文件。请注意,当我们处理项目中的库/模块时,会使用这样的代码(没有main函数)。

All the data provided is done with step-by-step analysis. You can recreate all the steps mentioned. Hope this cleared your doubt. Good day!

提供的所有数据都是通过逐步分析完成的。您可以重新创建所有提到的步骤。希望这清除了你的怀疑。美好的一天!

#3


3  

We can break this down into two parts:

我们可以将其分为两部分:

Undefined reference to `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

This is simply because the C Runtime library (crt1.o) is trying to call your (missing) main() function. There is a good overview of the various C Runtime files here / here.

这只是因为C运行时库(crt1.o)正在尝试调用您的(缺少的)main()函数。这里/这里有各种C运行时文件的概述。

Relocation X has invalid symbol index Y

Note: This has been a bit of mission (learning opportunity) for me - I've taken a few days to research and understand in the limited free time that I have. It's something that I've wondered about for a long time but never looked into... Hopefully my understanding is correct (though clearly not complete - I'll update it if I can).

注意:这对我来说是一个使命(学习机会) - 我花了几天时间在有限的空闲时间内进行研究和理解。这是我长期以来一直想知道的事情,但从未考虑过......希望我的理解是正确的(虽然显然不完整 - 如果可以,我会更新它)。

This is a little more complex, and hidden away.

这有点复杂,隐藏起来。

Just by reading the message, we can gleen that it's related to debug information (the .debug_info and .debug_line sections of crt1.o's debug file is mentioned). Note the /usr/lib/debug/ path, which just contains debug information, the other crt1.o is a "stripped" file...

只需阅读消息,我们就可以发现它与调试信息有关(提到了crt1.o的调试文件的.debug_info和.debug_line部分)。注意/ usr / lib / debug / path,它只包含调试信息,另一个crt1.o是一个“剥离”文件...

The format string is found in the binutils project, specifically bfd/elfcode.h. BFD being Binary File Descriptor - the GNU way to handle object files across a number of system architectures.

格式字符串位于binutils项目中,特别是bfd / elfcode.h。 BFD是二进制文件描述符 - 在许多系统体系结构中处理目标文件的GNU方法。

BFD is an intermediate format used for binary files - GCC will employ BFD before it finally writes an a.out, ELF, or other binary.

BFD是用于二进制文件的中间格式 - GCC在最终写入a.out,ELF或其他二进制文件之前将使用BFD。

Looking into the manual, we can find some interesting snippets of knowledge:

查看手册,我们可以找到一些有趣的知识片段:

[...] with each entry in the hash table the a.out linker keeps the index the symbol has in the final output file (this index number is used so that when doing a relocateable link the symbol index used in the output file can be quickly filled in when copying over a reloc). [source]

[...]对于散列表中的每个条目,a.out链接器保留符号在最终输出文件中具有的索引(使用此索引号,以便在执行可重定位链接时,输出文件中使用的符号索引可以复制重定位时快速填写)。 [资源]

The standard records contain only an address, a symbol index, and a type field. [source]

标准记录仅包含地址,符号索引和类型字段。 [资源]

This means that these errors are issued due to relocations that are related to specific (missing?) 'symbols'. A 'symbol' in this context is any named 'thing' - e.g: functions and variables.

这意味着由于与特定(缺少?)'符号'相关的重定位而发出这些错误。在此上下文中的“符号”是任何命名的“事物” - 例如:函数和变量。

As these 'invalid symbols' appear to be resolved by simply declaring main(), I would guess that some (all?) of these symbol indexes are derived from main(), its debug information, and/or relations.

由于这些“无效符号”似乎是通过简单地声明main()来解决的,我猜这些符号索引中的一些(全部?)是从main(),它的调试信息和/或关系派生的。

I can't tell you what is supposed to be at the symbol indexes mentioned (2, 11, 12, 13, 21), but it is interesting that my tests yielded the same list of symbol indexes.

我不能告诉你在提到的符号索引(2,11,12,13,21)应该是什么,但有趣的是我的测试产生了相同的符号索引列表。

Running ld with crt1.o alone gives us similar output:

单独使用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'

#1


4  

C Program Features (Unix-like)

  • every program is compiled separately into elf format
  • 每个程序都分别编译成精灵格式

  • c program can use external variable/function reference, which is linked later
  • c程序可以使用外部变量/函数引用,后面链接

  • 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 our main and do cleaning job after main
  • main不是你原先想到的程序的开始,c lib有一个启动程序(crt1.o),它有一个_start程序,它将在main之后调用我们的main和do clean工作

  • concludes above statement, we can know that even a very simple program as OP showed need to be linked
  • 总结以上陈述,我们可以知道即使是一个非常简单的OP程序也需要联系起来

ELF Format

ELF has two headers, as following shows:

ELF有两个标题,如下所示:

  • section header -- used to link multiple elf to make process image
  • section header - 用于链接多个elf以制作流程图像

  • program header -- used to load process image
  • 程序头 - 用于加载过程映像

Here we only focus on section header structure:

这里我们只关注节头结构:

    mapping<var_name, offset, size...>
    // and special cases
    mapping<external_var_name, offset, size...>

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.

每个程序都是单独编译的,这意味着地址分配是相似的(在Linux的早期版本中,每个编译的程序都以相同的虚拟地址 - 0x08000000开始,并且许多攻击可以利用这个,所以它改为添加一些随机增量到解决问题的地址),因此可能存在一些覆盖区域。这就是需要重新定位地址的原因。

Relocation

The relocation info (offset, value etc) is stored in .rel.* section:

重定位信息(偏移量,值等)存储在.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

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.

当链接器想要在重定位过程中设置main的地址时,它无法在已编译的elf文件中找到符号,因此它会抱怨并停止链接过程。

Example

Here is the simplified version of os implementations, start.c corresponds to crt1.o's source code:

这是os实现的简化版本,start.c对应于crt1.o的源代码:

    int entry(char *); // corresponds to main

    void _start(char *args) {
        entry(args);
        exit();
    }

Ref

#2


3  

Instead of compiling the code directly, go through all the stages of compilation to figure out where the error is arising (as far as I know, such errors occur during linking). Following gcc arguments will be helpful:

不是直接编译代码,而是经历编译的所有阶段以找出错误发生的位置(据我所知,在链接期间会发生这样的错误)。以下gcc参数将有所帮助:

  • -E Preprocess only; do not compile, assemble or link
  • -E仅预处理;不编译,汇编或链接

  • -S Compile only; do not assemble or link
  • -S仅编译;不要组装或链接

  • -c Compile and assemble, but do not link
  • -c编译和汇编,但不要链接

Now:

gcc -E prog.c
gcc -S prog.c
gcc -c prog.c

With the program/code you have mentioned, all these steps are working perfect with gcc 4.8.4. But, during linking, when you compile using gcc prog.c, the compiler is unable to link with respective library, as it was not mentioned. Also, we have no main function in the prog.c file. So, we need to indicate -nostartfiles switch. Hence, you can compile prog.c as:

使用您提到的程序/代码,所有这些步骤都适用于gcc 4.8.4。但是,在链接期间,当您使用gcc prog.c进行编译时,编译器无法链接到相应的库,因为它没有被提及。另外,我们在prog.c文件中没有main函数。所以,我们需要指明-nostartfiles开关。因此,您可以将prog.c编译为:

gcc prog.c -lc -nostartfiles

This produces the warning:

这会产生警告:

/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 00000000004002a3

/ usr / bin / ld:警告:找不到条目符号_start;默认为00000000004002a3

This is because of the sequence. i.e., init calls _start function and the _start function calls main function. This warning means that the _start function is unable to locate main function, where the init call is unable to locate _start. Please note that this is just a warning. In order to avoid this warning, we need to change the command to compile without warnings as follows.

这是因为序列。即,init调用_start函数,_start函数调用main函数。此警告意味着_start函数无法找到main函数,其中init调用无法找到_start。请注意,这只是一个警告。为了避免这种警告,我们需要将命令更改为编译而不发出警告,如下所示。

gcc prog.c -lc --entry whatever -nostartfiles

With this command, we are instructing the kernel to compile prog.c using gcc by linking the libc.so library with the starting point as the function whatever, where this code contains no main function.

使用此命令,我们指示内核使用gcc编译prog.c,方法是将libc.so库与起始点链接为函数,其中此代码不包含main函数。

This is the context with gcc 4.8.4, which I've compiled on.

这是我编译的gcc 4.8.4的上下文。

Coming to the case of gcc 6.2.0, I think all these linking stuff is taken care by the compiler itself. Hence, you can simply mention the compiling command as shown below.

来到gcc 6.2.0的情况,我认为所有这些链接的东西都由编译器本身来处理。因此,您可以简单地提及编译命令,如下所示。

gcc -c prog.c -nostartfiles

If it produces any other errors or warnings, you can use the switches mentioned above.

如果它产生任何其他错误或警告,您可以使用上面提到的开关。

Also, note that crt0 through crtN (N depends on the ELF file) are executed before the init calls _start, which gives the metadata about the memory and other machine dependent parameters. The linking errors shown as

另请注意,在init调用_start之前执行crt0到crtN(N依赖于ELF文件),这会提供有关内存和其他机器相关参数的元数据。链接错误显示为

/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):重定位0具有无效的符号索引11

do not provide complete information for rectifying the issue, as machines are not as smart as human beings in identifying the point of error.

不提供纠正问题的完整信息,因为机器在识别错误​​点方面不如人类聪明。

This produces a complete executable file. Please do notice that such code (without main function) is used when we are working on libraries/modules within a project.

这将生成完整的可执行文件。请注意,当我们处理项目中的库/模块时,会使用这样的代码(没有main函数)。

All the data provided is done with step-by-step analysis. You can recreate all the steps mentioned. Hope this cleared your doubt. Good day!

提供的所有数据都是通过逐步分析完成的。您可以重新创建所有提到的步骤。希望这清除了你的怀疑。美好的一天!

#3


3  

We can break this down into two parts:

我们可以将其分为两部分:

Undefined reference to `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

This is simply because the C Runtime library (crt1.o) is trying to call your (missing) main() function. There is a good overview of the various C Runtime files here / here.

这只是因为C运行时库(crt1.o)正在尝试调用您的(缺少的)main()函数。这里/这里有各种C运行时文件的概述。

Relocation X has invalid symbol index Y

Note: This has been a bit of mission (learning opportunity) for me - I've taken a few days to research and understand in the limited free time that I have. It's something that I've wondered about for a long time but never looked into... Hopefully my understanding is correct (though clearly not complete - I'll update it if I can).

注意:这对我来说是一个使命(学习机会) - 我花了几天时间在有限的空闲时间内进行研究和理解。这是我长期以来一直想知道的事情,但从未考虑过......希望我的理解是正确的(虽然显然不完整 - 如果可以,我会更新它)。

This is a little more complex, and hidden away.

这有点复杂,隐藏起来。

Just by reading the message, we can gleen that it's related to debug information (the .debug_info and .debug_line sections of crt1.o's debug file is mentioned). Note the /usr/lib/debug/ path, which just contains debug information, the other crt1.o is a "stripped" file...

只需阅读消息,我们就可以发现它与调试信息有关(提到了crt1.o的调试文件的.debug_info和.debug_line部分)。注意/ usr / lib / debug / path,它只包含调试信息,另一个crt1.o是一个“剥离”文件...

The format string is found in the binutils project, specifically bfd/elfcode.h. BFD being Binary File Descriptor - the GNU way to handle object files across a number of system architectures.

格式字符串位于binutils项目中,特别是bfd / elfcode.h。 BFD是二进制文件描述符 - 在许多系统体系结构中处理目标文件的GNU方法。

BFD is an intermediate format used for binary files - GCC will employ BFD before it finally writes an a.out, ELF, or other binary.

BFD是用于二进制文件的中间格式 - GCC在最终写入a.out,ELF或其他二进制文件之前将使用BFD。

Looking into the manual, we can find some interesting snippets of knowledge:

查看手册,我们可以找到一些有趣的知识片段:

[...] with each entry in the hash table the a.out linker keeps the index the symbol has in the final output file (this index number is used so that when doing a relocateable link the symbol index used in the output file can be quickly filled in when copying over a reloc). [source]

[...]对于散列表中的每个条目,a.out链接器保留符号在最终输出文件中具有的索引(使用此索引号,以便在执行可重定位链接时,输出文件中使用的符号索引可以复制重定位时快速填写)。 [资源]

The standard records contain only an address, a symbol index, and a type field. [source]

标准记录仅包含地址,符号索引和类型字段。 [资源]

This means that these errors are issued due to relocations that are related to specific (missing?) 'symbols'. A 'symbol' in this context is any named 'thing' - e.g: functions and variables.

这意味着由于与特定(缺少?)'符号'相关的重定位而发出这些错误。在此上下文中的“符号”是任何命名的“事物” - 例如:函数和变量。

As these 'invalid symbols' appear to be resolved by simply declaring main(), I would guess that some (all?) of these symbol indexes are derived from main(), its debug information, and/or relations.

由于这些“无效符号”似乎是通过简单地声明main()来解决的,我猜这些符号索引中的一些(全部?)是从main(),它的调试信息和/或关系派生的。

I can't tell you what is supposed to be at the symbol indexes mentioned (2, 11, 12, 13, 21), but it is interesting that my tests yielded the same list of symbol indexes.

我不能告诉你在提到的符号索引(2,11,12,13,21)应该是什么,但有趣的是我的测试产生了相同的符号索引列表。

Running ld with crt1.o alone gives us similar output:

单独使用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'