【发布时间】:2011-11-30 06:06:37
【问题描述】:
我正在尝试静态编译一个最小程序并检查发出的系统调用:
$ cat hello.c
#include <stdio.h>
int main (void) {
write(1, "Hello world!", 12);
return 0;
}
$ gcc hello.c -static
$ objdump -f a.out
a.out: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00000000004003c0
$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 39 vars */]) = 0
uname({sys="Linux", node="ubuntu", ...}) = 0
brk(0) = 0xa20000
brk(0xa211a0) = 0xa211a0
arch_prctl(ARCH_SET_FS, 0xa20880) = 0
brk(0xa421a0) = 0xa421a0
brk(0xa43000) = 0xa43000
write(1, "Hello world!", 12Hello world!) = 12
exit_group(0) = ?
我知道,当非静态链接时,ld 会发出启动代码以将libc.so 和ld.so 映射到进程的地址空间,而ld.so 将继续加载任何其他共享库。
但是在这种情况下,除了execve、write和exit_group之外,为什么会发出这么多系统调用?
为什么是uname(2)?为什么这么多调用brk(2) 来获取和设置程序中断,以及调用arch_prctl(2) 来设置进程状态,而这似乎应该在内核空间中完成,在execve 时间?
【问题讨论】:
-
brk大致是一个低级的malloc所以它被启动代码调用并不奇怪。如果你真的很好奇为什么要调用它们,为什么不在调用相关函数时使用调试器中断? -
省略 -static 以便它使用共享库,然后使用
ltrace -S ./a.out查看在它最终调用您的 main() 之前完成的全部工作。当我输入 a.out 时:你的 linux 系统是旧系统? -
@ott--,
a.out是 GCC 的默认输出文件名(当你不通过-o时),即使在 ELF 系统上也是如此。 -
@bdolan:是的,我想到了可执行格式。
标签: c linux static-linking libc system-calls