没有 libc 的编译

我想编译我的 C 代码没有(g) libc。我如何停用它和哪些函数依赖于它?

我试过-nostdlib,但是没有用: 代码是可编译的并且可以运行,但是我仍然可以在可执行文件的 hexdump 中找到 libc 的名称。

52223 次浏览

最简单的方法是将 C 代码编译成目标文件(gcc -c获得一些 *.o文件) ,然后将它们直接链接到链接器(ld)。您必须将目标文件与一些额外的目标文件(如 /usr/lib/crt1.o)链接起来,以获得一个可执行文件(在内核所看到的入口点和 main()函数之间,还有一些工作要做)。要知道要链接到什么,请尝试使用 gcc -v链接 glibc: 这将显示通常进入可执行文件的内容。

您将发现 gcc 生成的代码可能与一些隐藏函数有一些依赖关系。大部分是 libgcc.a。也可能有隐藏的对 memcpy()memmove()memset()memcmp()的调用,这些都在 libc 中,所以你可能需要提供自己的版本(这并不难,至少只要你对性能不太挑剔)。

如果您查看生产的组件(使用 -S标志) ,事情 也许吧有时会变得更清楚。

如果使用 -nostdlib编译代码,就不能调用任何 C 库函数(当然) ,但是也不能获得常规的 C 引导程序代码。特别是,Linux 上程序的真正入口点不是 main(),而是一个称为 _start()的函数。标准库通常提供一个这样的版本,运行一些初始化代码,然后调用 main()

尝试用 gcc -nostdlib -m32编译这个代码:

// Tell the compiler incoming stack alignment is not RSP%16==8 or ESP%16==12
__attribute__((force_align_arg_pointer))
void _start() {


/* main body of program: call main(), etc */


/* exit system call */
asm("movl $1,%eax;"
"xorl %ebx,%ebx;"
"int  $0x80"
);
__builtin_unreachable();  // tell the compiler to make sure side effects are done before the asm statement
}

_start()函数应该始终以对 exit的调用(或其他不返回的系统调用,如 exec)结束。上面的示例使用内联程序集直接调用系统调用,因为通常的 exit()不可用。