C语言 直接与 ld 链接 C 程序失败,未定义对 `__libc_csu_fini` 的引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6656317/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:06:25  来源:igfitidea点击:

Linking a C program directly with ld fails with undefined reference to `__libc_csu_fini`

cgcclinkerglibcld

提问by Matthew Slattery

I'm trying to compile a C program under Linux. However, out of curiosity, I'm trying to execute some steps by hand: I use:

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

  • the gcc frontend to produce assembler code
  • then run the GNU assembler to get an object file
  • and then link it with the C runtime to get a working executable.
  • 生成汇编代码的 gcc 前端
  • 然后运行 ​​GNU 汇编程序以获取目标文件
  • 然后将其与 C 运行时链接以获取可运行的可执行文件。

Now I'm stuck with the linking part.

现在我被链接部分困住了。

The program is a very basic "Hello world":

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

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

I use the following command to produce the assembly code:

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

gcc hello.c -S -masm=intel

I'm telling gcc to quit after compiling and dump the assembly code with Intel syntax.

我告诉 gcc 在用 Intel 语法编译和转储汇编代码后退出。

Then I use th GNU assembler to produce the object file:

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

as -o hello.o hello.s

Then I try using ld to produce the final executable:

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

ld hello.o /usr/lib/libc.so /usr/lib/crt1.o -o hello

But I keep getting the following error message:

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

/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'

The symbols __libc_csu_fini/initseem to be a part of glibc, but I can't find them anywhere! I tried linking against libc statically (against /usr/lib/libc.a) with the same result.

这些符号__libc_csu_fini/init似乎是 glibc 的一部分,但我在任何地方都找不到它们!我尝试/usr/lib/libc.a以相同的结果静态地(针对)链接 libc 。

What could the problem be?

可能是什么问题?

采纳答案by Rob?

I found another postwhich contained a clue: -dynamic-linker /lib/ld-linux.so.2.

我发现了另一个帖子,其中包含一个线索:-dynamic-linker /lib/ld-linux.so.2

Try this:

尝试这个:

$ 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
$ 

回答by Matthew Slattery

/usr/lib/libc.sois a linker script which tells the linker to pull in the shared library /lib/libc.so.6, and a non-shared portion, /usr/lib/libc_nonshared.a.

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

__libc_csu_initand __libc_csu_finicome from /usr/lib/libc_nonshared.a. They're not being found because references to symbols in non-shared libraries need to appear beforethe archive that defines them on the linker line. In your case, /usr/lib/crt1.o(which references them) appears after/usr/lib/libc.so(which pulls them in), so it doesn't work.

__libc_csu_init__libc_csu_fini来自/usr/lib/libc_nonshared.a. 它们没有被找到,因为对非共享库中符号的引用需要出现链接器行上定义它们的存档之前。在您的情况下,/usr/lib/crt1.o(引用它们)出现/usr/lib/libc.so(将它们拉入)之后,因此它不起作用。

Fixing the order on the link line will get you a bit further, but then you'll probably get a new problem, where __libc_csu_initand __libc_csu_fini(which are now found) can't find _initand _fini. In order to call C library functions, you should also link /usr/lib/crti.o(after crt1.obut beforethe C library) and /usr/lib/crtn.o(afterthe C library), which contain initialisation and finalisation code.

修复链接行上的顺序会让你更进一步,但是你可能会遇到一个新问题, where __libc_csu_initand __libc_csu_fini(现在找到了)找不到_initand _fini。为了调用 C 库函数,您还应该链接/usr/lib/crti.o(在C 库之后crt1.oC 库之后)和/usr/lib/crtn.oC 库之后),其中包含初始化和终止代码。

Adding those should give you a successfully linked executable. It stillwon't work, because it uses the dynamically linked C library without specifying what the dynamic linker is. You'll need to tell the linker that as well, with something like -dynamic-linker /lib/ld-linux.so.2(for 32-bit x86 at least; the name of the standard dynamic linker varies across platforms).

添加这些应该会给你一个成功链接的可执行文件。它仍然不起作用,因为它使用动态链接的 C 库而没有指定动态链接器是什么。您还需要告诉链接器,例如-dynamic-linker /lib/ld-linux.so.2(至少对于 32 位 x86;标准动态链接器的名称因平台而异)。

If you do all that (essentially as per Rob's answer), you'll get something that works in simple cases. But you may come across further problems with more complex code, as GCC provides some of its own library routines which may be needed if your code uses certain features. These will be buried somewhere deep inside the GCC installation directories...

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

You can see what gccis doing by running it with either the -voption (which will show you the commands it invokes as it runs), or the -###option (which just prints the commands it would run, with all of the arguments quotes, but doesn't actually run anything). The output will be confusing unless you know that it usually invokes ldindirectly via one of its own components, collect2(which is used to glue in C++ constructor calls at the right point).

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

回答by Michael Burr

Assuming that a normal invocation of gcc -o hello hello.cproduces a working build, run this command:

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

gcc --verbose -o hello hello.c

and gcc will tell you how it's linking things. That should give you a good idea of everything that you might need to account for in your link step.

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

回答by detys

This is how I fixed it on ubuntu 11.10:

这是我在 ubuntu 11.10 上修复它的方式:

apt-get remove libc-dev

Say yes to remove all the packages but copy the list to reinstall after.

说是删除所有软件包,但复制列表以重新安装。

apt-get install libc-dev

回答by Vinicius Kamakura

Since you are doing the link process by hand, you are forgetting to link the C run time initializer, or whatever it is called.

由于您正在手动执行链接过程,因此您忘记了链接 C 运行时初始值设定项或任何调用的内容。

To not get into the specifics of where and what you should link for you platform, after getting your intel asm file, use gcc to generate (compile and link) your executable.

为了不了解您应该为您的平台链接的位置和内容的细节,在获取您的 intel asm 文件后,使用 gcc 生成(编译和链接)您的可执行文件。

simply doing gcc hello.c -o helloshould work.

简单地做gcc hello.c -o hello应该工作。

回答by mwk

If you're running a 64-bit OS, your glibc(-devel) may be broken. By looking at thisand thisyou can find these 3 possible solutions:

如果您运行的是 64 位操作系统,您的 glibc(-devel) 可能已损坏。通过查看thisthis,您可以找到这3种可能的解决方案:

  1. add lib64 to LD_LIBRARY_PATH
  2. use lc_noshared
  3. reinstall glibc-devel
  1. 将 lib64 添加到 LD_LIBRARY_PATH
  2. 使用 lc_noshared
  3. 重新安装 glibc-devel