execve와 brk(NULL)이 항상 처음 두 시스템 호출인 이유는 무엇입니까?

execve와 brk(NULL)이 항상 처음 두 시스템 호출인 이유는 무엇입니까?

내가 시도할 때

strace ping google.com

또는

strace ls 

또는

even strace curl <domain>

처음 두 시스템 호출은 항상 다음과 같습니다.

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()때문에 (또는 내부적으로 사용하는 라이브러리 호출) 이를 첫 번째 시스템 호출(곧 설명)이라고 부릅니다 . 그 이상의 것은 프로그램과 해당 라이브러리 호출이 당분간 호출될 필요가 없다면 두 번째 시스템 호출이 됩니다 .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는 무료 소프트웨어이므로 아마도 동적 링커의 소스 코드에 설명되어 있을 것입니다. 도움이 되었기를 바랍니다.

관련 정보