我想在没有(g)libc的情况下编译我的C代码。 我怎样才能停用它,哪些函数依赖于它?
我尝试了-nostdlib,但是它没有帮助:代码可以编译和运行,但我仍然可以在可执行文件的十六进制转储中找到libc的名称。
我想在没有(g)libc的情况下编译我的C代码。 我怎样才能停用它,哪些函数依赖于它?
我尝试了-nostdlib,但是它没有帮助:代码可以编译和运行,但我仍然可以在可执行文件的十六进制转储中找到libc的名称。
-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()
不可用。
asm("mov rax,60; mov rdi,0; syscall")
。 - sigalorgcc
进行编译,您需要使用 AT&T 语法,因此应该如下所示:asm(mov $60,%rax; mov $0,%rdi; syscall)
。 - lanoxx_start
时的对齐方式不同:堆栈上没有返回地址,因此它仍然对齐为 16 字节。但是 GCC 将假定它是一个正常的函数,所以当它调用其他函数时,将违反 ABI。使用 -mincoming-stack-boundary=2
选项(文档)来告诉 GCC,在函数进入时堆栈可能只对齐为 4 字节,或者在 _start
上使用 __attribte__((target("something")))
。 - Peter Cordesgcc -c
生成一些*.o
文件),然后直接使用链接器(ld
)将其链接起来。您将不得不使用一些额外的对象文件,例如/usr/lib/crt1.o
等,以获得工作可执行文件(在内核看到的入口点和main()
函数之间还需要一些工作)。要知道该链接什么,请尝试链接glibc,使用gcc -v
:这应该会向您展示通常包含在可执行文件中的内容。libgcc.a
中。还可能存在对memcpy()
、memmove()
、memset()
和memcmp()
的隐藏调用,它们在libc中,因此您可能需要提供自己的版本(只要您对性能没有太高要求,这并不难)。-S
标志),有时事情可能会变得更加清晰。gcc -v
命令,您会看到 gcc
给链接器一些对象文件(即 *.o
文件)。链接器将包含所有被给予的对象文件。"消失"仅出现在库文件(*.a
文件)中,因为它们是对象文件的存储库,链接器可自由使用或不使用它们。 - Thomas Pornin