Я экспериментирую, статически компилируя минимальную программу и исследуя выполняемые системные вызовы:
$ 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. поэтому
и ld.so
в адресное пространство процесса, а ld.so
продолжит загрузку любых других разделяемых библиотек.
Но в этом случае, почему выдается так много системных вызовов, помимо execve
, write
и exit_group
?
Какого черта ] uname (2)
? Почему так много вызовов brk (2)
для получения и установки прерывания программы и вызовов arch_prctl (2)
для установки состояния процесса, когда кажется, что это должно были выполнены в пространстве ядра в execve
время?