直接将C程序与ld链接失败,未定义引用`__libc_csu_fini`

15 c linker gcc glibc ld

我正在尝试在Linux下编译一个C程序.然而,出于好奇,我正在尝试手动执行一些步骤:我使用:

  • gcc前端生成汇编代码
  • 然后运行GNU汇编程序以获取目标文件
  • 然后将其与C运行时链接以获得可运行的可执行文件.

现在我被连接部分困住了.

该程序是一个非常基本的"Hello world":

#include <stdio.h>
int main() {
   printf("Hello\n");
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

我使用以下命令来生成汇编代码:

gcc hello.c -S -masm=intel
Run Code Online (Sandbox Code Playgroud)

我告诉gcc在编译后退出并使用Intel语法转储汇编代码.

然后我使用GNU汇编程序来生成目标文件:

as -o hello.o hello.s
Run Code Online (Sandbox Code Playgroud)

然后我尝试使用ld生成最终的可执行文件:

ld hello.o /usr/lib/libc.so /usr/lib/crt1.o -o hello
Run Code Online (Sandbox Code Playgroud)

但我不断收到以下错误消息:

/usr/lib/crt1.o: In function `_start':
(.text+0xc): undefined reference to `__libc_csu_fini'
/usr/lib/crt1.o: In function `_start':
(.text+0x11): undefined reference to `__libc_csu_init'
Run Code Online (Sandbox Code Playgroud)

符号__libc_csu_fini/init似乎是glibc的一部分,但我无法在任何地方找到它们!我尝试/usr/lib/libc.a使用相同的结果静态链接libc(反对).

问题是什么?

Mat*_*ery 34

/usr/lib/libc.so是一个链接器脚本,它告诉链接器引入共享库/lib/libc.so.6和非共享部分/usr/lib/libc_nonshared.a.

__libc_csu_init并且__libc_csu_fini从何而来/usr/lib/libc_nonshared.a.它们未被发现,因为非共享库中符号的引用需要出现链接器行上定义它们的归档之前.在你的情况下,/usr/lib/crt1.o(引用它们)出现 /usr/lib/libc.so(将它们拉入)之后,因此它不起作用.

修复链接线上的订单会让你更进一步,但是你可能会遇到一个新问题,在哪里__libc_csu_init__libc_csu_fini(现在找到的)无法找到_init_fini.为了调用C库函数,您还应该链接/usr/lib/crti.o(在C库之后crt1.o C库之前)和/usr/lib/crtn.o( C库之后),其中包含初始化和最终化代码.

添加它们应该为您提供成功链接的可执行文件 它仍然无法工作,因为它使用动态链接的C库而不指定动态链接器是什么.您还需要告诉链接器,例如-dynamic-linker /lib/ld-linux.so.2(至少32位x86;标准动态链接器的名称因平台而异).

如果你做了所有这些(基本上按照Rob的回答),你会得到一些在简单情况下有效的东西.但是,您可能会遇到更复杂代码的问题,因为GCC提供了一些自己的库例程,如果您的代码使用某些功能,可能需要这些例程.这些将被埋在GCC安装目录的深处......

您可以gcc通过-v选项(它将显示它在运行时调用的命令)或-###选项(它只是打印它将运行的命令,以及所有参数引用,但不会运行它)来查看正在执行的操作.实际上运行任何东西).除非你知道它通常ld通过它自己的一个组件间接调用collect2(它用于在正确的点上粘合C++构造函数调用),否则输出会令人困惑.

  • 辉煌.清楚地解释,简洁,并削减了基本要素.我一直在浏览ld的丛林,将一个直接链接的可执行文件从Solaris移植到Linux并最终在这里,因为当我试图解决"Permission denied"错误时,我被简化为交换链接器行上对象的顺序执行刚刚链接的可执行文件时.对于在编译或链接可执行文件后遇到"权限被拒绝"的任何其他人,该票证可能正如马修解释的那样指定动态链接器.这对我来说. (2认同)

Rob*_*obᵩ 6

我发现另一篇文章包含了一个线索:-dynamic-linker /lib/ld-linux.so.2

尝试这个:

$ gcc hello.c -S -masm=intel
$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o hello.o -lc /usr/lib/crtn.o
$ ./hello
hello, world
$ 
Run Code Online (Sandbox Code Playgroud)


Mic*_*urr 5

假设正常调用gcc -o hello hello.c产生一个工作构建,运行以下命令:

gcc --verbose -o hello hello.c
Run Code Online (Sandbox Code Playgroud)

gcc 会告诉你它是如何链接事物的。这应该让您对在链接步骤中可能需要考虑的所有事情有一个很好的了解。