execveとbrk(NULL)が常に最初の2つのシステムコールであるのはなぜですか?

execveとbrk(NULL)が常に最初の2つのシステムコールであるのはなぜですか?

私が試したとき

strace ping google.com

または

strace ls 

または

even strace curl <domain>

最初の2つのシステムコールは常に次のようになります。

execve("/usr/bin/curl", ["curl", "google.com"], 0x7ffecf1bc378 /* 61 vars */) = 0
brk(NULL)                               = 0x55f553c49000

誰かが私が何をするときにexecveが常に最初のシステムコールであるかを教えてもらえますか?

私はこのマニュアルページを読みました。https://linux.die.net/man/2/execveexecveしかし、システムコールか実行可能プログラムなのかわかりません。

答え1

Linuxでは、次の方法で新しいプロセスが作成されます。fork()、これは子プロセスを親プロセスとほぼ同じにします。プログラムは次のような新しいプロセスを作成します。その他新しいサブプロセスは、デフォルトexecve()では、「現在のプログラムを別のプログラムに置き換える」元のプロセスのプログラムと比較してすぐに呼び出されます。

brk(NULL)どこか尋ねるプロセスです。ヒープメモリ終わる。多くのプログラムはそれをすぐに使用するexecve()ため(または内部で使用するライブラリ呼び出し)、これを最初のシステム呼び出し(まもなく説明)と呼びます。それ以上は、プログラムとそのライブラリ呼び出しがしばらく呼び出される必要がない限り、2番目のシステム呼び出しになります。malloc()malloc()malloc()brk(NULL)

答え2

私はこのすべてのシステムコールが動的リンカーが実行前に設定したものにすぎないと思います。これを確認するために小さなテストプログラムを作成しました。

me@bar:~/foo$ cat main.c
#include <unistd.h>
void main(){
        syscall(60,0);
}

まず、静的にコンパイルしてから動的にコンパイルします。この-Wl,-emainパラメータは、gccにエントリポイントとして-emain設定されるリンカに渡すように指示します。mainもちろん、プログラムはすぐに終了しました。


me@bar:~/foo$ gcc -static main.c -Wl,-emain -o main
me@bar:~/foo$ strace ./main 2>&1 | head
execve("./main", ["./main"], 0x7fff6d7c4b40 /* 50 vars */) = 0
exit(0)                                 = ?
+++ exited with 0 +++

これで、-staticロゴがなくても一般的に見ているのと同じ結果が得られます。

me@bar:~/foo$ gcc main.c -Wl,-emain -o main
me@bar:~/foo$ strace ./main 2>&1 | head
execve("./main", ["./main"], 0x7fff06b48d20 /* 50 vars */) = 0
brk(NULL)                               = 0x558c61a90000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd68e8e950) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=77239, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 77239, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe55ed7e000
...

コードがmain

今、私はこれがlibcに固有のものかもしれませんし、それ自体を設定する必要があるかもしれないと思います。しかし、そうではありません。私はリンクし、straceに以下を表示する小さな動的ライブラリを作成しました。

$ ldd main
    linux-vdso.so.1 (0x00007fff9c8cd000)
    libfoo.so => /home/me/path/to/libfoo.so (0x00007f80ed20a000)


$ strace ./main
execve("./main", ["./main"], 0x7ffcdf5b5a70 /* 51 vars */) = 0
brk(NULL)
...
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/me/path/to/libfoo.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=13240, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f028541c000
mmap(NULL, 16384, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f0285418000
mmap(0x7f0285419000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7f0285419000
mmap(0x7f028541a000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f028541a000
mmap(0x7f028541b000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f028541b000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f028541d040) = 0
set_tid_address(0x7f028541d310)         = 6310
set_robust_list(0x7f028541d320, 24)     = 0
rseq(0x7f028541d960, 0x20, 0, 0x53053053) = 0
mprotect(0x7f028541b000, 4096, PROT_READ) = 0
mprotect(0x402000, 4096, PROT_READ)     = 0
exit(0)                                 = ?
+++ exited with 0 +++

ほとんどの呼び出しが何をしているのかはわかりませんが、明らかにlibfoo私の小さな関数(実際にはシャットダウンシステム呼び出しを実行する関数)をメモリにマッピングしているようです。したがって、これらのトレースは動的リンカーから来ているように見え、動的ライブラリをメモリにマップしてから(ファイル記述子3で開いた後)、プログラム自体に実行を渡します(この場合はすぐに終了します)。今、私は動的リンカーがプログラムが実行されたときにどのメモリレイアウトを持つかを知る必要があるので、その値に対して計算を実行する必要があるため、呼び出しが発生したと
思います。brkLinuxはフリーソフトウェアなので、おそらく動的リンカーのソースコードに記載されているでしょう。お役に立てば幸いです。

関連情報