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

soc*_*ser 5 c assembly linker static-libraries

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

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

我用命令编译它:

gcc -S test.c
Run Code Online (Sandbox Code Playgroud)

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

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

然后我想将它与 c 标准库静态链接。我搜索了libc.a文件,将其定位在/usr/lib/i386-linux-gnu/libc.a. 所以我试图将它与命令链接:

ld test.o /usr/lib/i386-linux-gnu/libc.a
Run Code Online (Sandbox Code Playgroud)

但出来了很多错误信息:

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'
...
...
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么会出现这些错误消息?我正在尝试了解编译系统的工作原理,因此与其知道如何解决这个问题,我更想知道它是如何以这种方式出现的。似乎静态 C 库依赖于其他库,为什么以及那些库是什么?

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

Bas*_*tch 5

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

gcc -v -static test.c -o mytest
Run Code Online (Sandbox Code Playgroud)

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

在实践中,最好至少与 gcc

如果您好奇,请利用 Linux 主要是免费软件并研究源代码(例如GCCC 标准库binutils等...)。您可能会发现musl-libc很有趣。

我宁愿避免gcc脚本

从技术上讲,gcc不是一个脚本,但驱动器程序(见GCC / gcc.c中的源代码GCC)。但它会运行ld它确实运行了一些链接器脚本。实际的编译是由程序启动的cc1完成的gcc