我认为您要问的问题是:“我知道函数类似于C 运行时库printf
并且scanf
由 C 运行时库实现。但是我可以在不告诉我的编译器和/或 IDE 将我的程序与 C 运行时库链接的情况下使用它们。为什么我不需要这样做?”</p>
这个问题的答案是:“不需要与 C 运行时库链接的程序非常非常罕见。即使您没有明确使用任何库函数,您仍然需要启动代码,并且编译器可能会在“幕后”发出对memcpy
、浮点仿真函数等的调用。因此,为方便起见,编译器会自动将您的程序与 C 运行时库链接,除非您告诉它不要这样做。”</p>
您必须查阅编译器的文档以了解如何告诉它不要链接到 C 运行时库中。GCC 使用-nostdlib
命令行选项。下面,我展示了你必须跳过的箍才能使这项工作......
$ cat > test.c
#include <stdio.h>
int main(void) { puts("hello world"); return 0; }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/usr/bin/ld: warning: cannot find entry symbol _start
/tmp/cc8svIx5.o: In function ‘main’:
test.c:(.text+0xa): undefined reference to ‘puts’
collect2: error: ld returned 1 exit status
puts
显然在 C 库中,但这个神秘的“入口符号_start
”也是如此。关闭 C 库,您也必须自己提供...
$ cat > test.c
int _start(void) { return 0; }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
Segmentation fault
139
它现在链接,但我们得到一个分段错误,因为_start
无处可返回!操作系统期望它调用_exit
. 好的,让我们这样做...
$ cat > test.c
extern void _exit(int);
void _start(void) { _exit(0); }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/tmp/ccuDrMQ9.o: In function `_start':
test.c:(.text+0xa): undefined reference to `_exit'
collect2: error: ld returned 1 exit status
...坚果,_exit
也是 C 运行时库中的一个函数!原始系统调用时间...
$ cat > test.c
#include <unistd.h>
#include <sys/syscall.h>
void _start(void) { syscall(SYS_exit, 0); }
^D
$ gcc -nostdlib test.c && { ./a.out; echo $?; }
/tmp/cchtZnbP.o: In function `_start':
test.c:(.text+0x14): undefined reference to `syscall'
collect2: error: ld returned 1 exit status
...不,syscall
也是C 运行时中的一个函数。我想我们只需要使用汇编!
$ cat > test.S
#include <sys/syscall.h>
.text
.globl _start
.type _start, @function
_start:
movq $SYS_exit, %rax
movq $0, %rdi
syscall
$ gcc -nostdlib test.S && { ./a.out; echo $?; }
0
最后,这有效。在我的电脑上。它不适用于不同的操作系统,系统调用具有不同的汇编级约定。
您现在可能想知道-nostdlib
,如果您为了进行系统调用而不得不使用汇编语言,这到底有什么用。它旨在用于编译完全独立的低级系统程序,如引导加载程序、内核和 C 运行时本身的(部分)——这些东西无论如何都必须实现自己的一切。
如果我们从头开始重新做一遍,那么分离出一个与语言无关的低级运行时可能是有意义的,只有系统调用包装器、与语言无关的进程启动代码以及任何语言的编译器可能会使用的函数需要调用“引擎盖下”(memcpy
, _Unwind_RaiseException
, __muldi3
, 之类的东西)。这个想法的问题是它很快就会遭受任务蠕变——你包括 errno
吗?通用线程原语?(哪些,具有哪些语义?)动态链接器?一个实现malloc
,上面的哪几个东西需要?Windows 是ntdll.dll
从这个概念开始的,在 Windows 10 中它的磁盘空间为 1.8MB,(略)大于libc.so
+ld.so
在我的 Linux 分区上。即使您是 Microsoft,编写仅使用的程序也很少且困难ntdll.dll
(我确定的唯一示例是csrss.exe
,它也可能是内核组件)。