尝试与静态c标准库链接时出错

时间:2016-11-03 08:53:06

标签: c assembly linker static-libraries

我的操作系统是ubuntu 14.04 32位,我的源程序test.c是:

#include <stdio.h>
int main(int argc, char *argv[])
{
        printf("test.");
        return;
}

我用命令编译它:

gcc -S test.c

输出为test.s文件。我用命令组装它:

as -o test.o test.s

然后我想静态地将它与c标准库链接起来。我搜索了libc.a文件,该文件位于/usr/lib/i386-linux-gnu/libc.a。所以我试着用命令链接它:

ld test.o /usr/lib/i386-linux-gnu/libc.a

但是出现了很多错误消息:

ld: warning: cannot find entry symbol _start; defaulting to 0000000008048210
/usr/lib/i386-linux-gnu/libc.a(backtrace.o): In function `backtrace_helper':
(.text+0x20): undefined reference to `_Unwind_GetIP'
/usr/lib/i386-linux-gnu/libc.a(backtrace.o): In function `backtrace_helper':
(.text+0x45): undefined reference to `_Unwind_GetGR'
/usr/lib/i386-linux-gnu/libc.a(backtrace.o): In function `backtrace_helper':
(.text+0x50): undefined reference to `_Unwind_GetCFA'
/usr/lib/i386-linux-gnu/libc.a(backtrace.o): In function `__backtrace':
(.text+0xb1): undefined reference to `_Unwind_Backtrace'
/usr/lib/i386-linux-gnu/libc.a(iofclose.o): In function `_IO_new_fclose':
(.text+0x1b1): undefined reference to `_Unwind_Resume'
/usr/lib/i386-linux-gnu/libc.a(iofclose.o):(.eh_frame+0x167): undefined reference to `__gcc_personality_v0'
/usr/lib/i386-linux-gnu/libc.a(iofflush.o): In function `_IO_fflush':
(.text+0xd7): undefined reference to `_Unwind_Resume'
/usr/lib/i386-linux-gnu/libc.a(iofflush.o):(.eh_frame+0xdf): undefined reference to `__gcc_personality_v0'
/usr/lib/i386-linux-gnu/libc.a(iofputs.o): In function `_IO_fputs':
(.text+0xf9): undefined reference to `_Unwind_Resume'
/usr/lib/i386-linux-gnu/libc.a(iofputs.o):(.eh_frame+0xdf): undefined reference to `__gcc_personality_v0'
/usr/lib/i386-linux-gnu/libc.a(iofwrite.o): In function `_IO_fwrite':
(.text+0x139): undefined reference to `_Unwind_Resume'
/usr/lib/i386-linux-gnu/libc.a(iofwrite.o):(.eh_frame+0xdf): undefined reference to `__gcc_personality_v0'
/usr/lib/i386-linux-gnu/libc.a(iogetdelim.o): In function `_IO_getdelim':
(.text+0x285): undefined reference to `_Unwind_Resume'
/usr/lib/i386-linux-gnu/libc.a(iogetdelim.o):(.eh_frame+0xdf): undefined reference to `__gcc_personality_v0'
/usr/lib/i386-linux-gnu/libc.a(wfileops.o): In function `_IO_wfile_underflow':
(.text+0x5fc): undefined reference to `_Unwind_Resume'
/usr/lib/i386-linux-gnu/libc.a(wfileops.o):(.eh_frame+0x137): undefined reference to `__gcc_personality_v0'
/usr/lib/i386-linux-gnu/libc.a(fileops.o): In function `_IO_new_file_underflow':
(.text+0x40b): undefined reference to `_Unwind_Resume'
/usr/lib/i386-linux-gnu/libc.a(fileops.o):(.eh_frame+0x1b3): undefined reference to `__gcc_personality_v0'
/usr/lib/i386-linux-gnu/libc.a(strtof_l.o): In function `____strtof_l_internal':
(.text+0xbc6): undefined reference to `__divdi3'
/usr/lib/i386-linux-gnu/libc.a(strtof_l.o): In function `____strtof_l_internal':
(.text+0xc08): undefined reference to `__moddi3'
/usr/lib/i386-linux-gnu/libc.a(strtof_l.o): In function `____strtof_l_internal':
(.text+0x249d): undefined reference to `__divdi3'
/usr/lib/i386-linux-gnu/libc.a(strtod_l.o): In function `____strtod_l_internal':
(.text+0xcc9): undefined reference to `__divdi3'
/usr/lib/i386-linux-gnu/libc.a(strtod_l.o): In function `____strtod_l_internal':
(.text+0xd0b): undefined reference to `__moddi3'
...
...

我的问题是,为什么会出现这些错误消息?我正在努力学习编译系统是如何工作的,所以我不想知道如何解决这个问题,而是更希望知道它是如何实现的。似乎静态C库依赖于其他库,为什么以及这些库是什么?

编辑: 我这样做是因为我想知道事情是如何运作的,所以我宁愿避免使用gcc脚本。

2 个答案:

答案 0 :(得分:4)

您还需要crt0个启动对象文件(除了静态libc.a),它们特别定义_start入口点(在您的ELF可执行文件中)并包含ABI特定(prologue和epilog)代码,用于调用main(最后处理atexit(3)个注册处理程序和stdio刷新)。还需要低级libgcc。细节复杂且具体实现。要理解它们,请将测试代码编译为

gcc -v -static test.c -o mytest

(避免调用可执行文件test,因为它会与/usr/bin/test或shell的内置版本冲突)

在实践中,至少与gcc

链接起来更好

如果您感到好奇,请充分利用Linux free software并研究源代码(例如GCCC standard librarybinutils等。 ..)。您可能会发现musl-libc很有趣。

  

我宁愿避开gcc脚本

从技术上讲,gcc 不是脚本而是驱动程序(请参阅gcc/gcc.c源代码中的GCC)。但它会运行ld,它确实会运行一些linker scripts。实际编译由cc1完成,由gcc程序启动。

答案 1 :(得分:2)

您还必须链接gcc内在库。最简单的方法是使用gcc前端编译并链接-static选项:

gcc -static -o test test.c

如果你坚持从汇编编译,你可以这样做:

gcc -static -o test test.s

您的系统可能不支持静态链接。

编辑:给gcc -v选项会告诉你它执行了什么命令。