fork() 대신 execve() 호출로 'ls'가 생성되는 이유

fork() 대신 execve() 호출로 'ls'가 생성되는 이유

제가 이해한 바에 따르면, 쉘에 "ls"와 같은 명령을 입력할 때마다 상위 프로세스(즉, 내 쉘)는 fork() 시스템 호출을 사용하여 자신을 복사한 다음 exec() 시스템 호출을 사용하여 대체합니다. 이 경우 "ls"가 종료되면 제어권이 내 쉘로 반환됩니다.

그러나 "ls"에서 strace를 실행하면 execve() 호출만 표시되고 포크는 표시되지 않으며 제어권은 여전히 ​​내 쉘에 다시 제공됩니다. 여기서 좀 헷갈림...

$ strace ls
execve("/usr/bin/ls", ["ls"], 0x7ffd938934e0 /* 25 vars */) = 0
brk(NULL)                               = 0x1134000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6ea9e38000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=23255, ...}) = 0

답변1

당신의 이해가 정확합니다. 실행할 때 strace ls두 개의 포크도 있습니다 . 쉘은 자체적으로 분기되어 exec()run 에 사용되며 stracestrace는 run 에 대해 동일한 작업을 수행합니다 ls.

strace는 다음에서 발생하는 모든 시스템 호출을 인쇄하므로 strace 출력에 분기가 표시되지 않습니다.strace의 하위 프로세스그때쯤에는 이미 포크가 발생했습니다.

  1. bash포크 앤 실행strace

  2. strace포크

  3. 상위 프로세스는 strace모든 시스템 호출을 가로채기 위해 하위 프로세스에 연결됩니다.

    이 시점부터는 시스템 호출만 볼 수 있습니다.

  4. 아이들이 달릴 stracels사용execve()

strace포크가 발생하는 것을 확인하는 한 가지 방법은 "외부에서" 연결하는 것입니다.

  • echo $$쉘의 프로세스 ID를 얻는 데 사용됩니다.
  • 실행 시 strace -f --attach=PID"PID"를 위의 프로세스 ID로 바꾸세요.다른 콘솔에서.
  • ls첫 번째 셸에서 실행
  • 다른 콘솔 창에는 쉘 및 분기된 하위 키에서 발생한 모든 시스템 호출( fork()/ clone()호출 포함) 이 표시됩니다.
  • strace를 중지하려면 두 번째 콘솔에서 CTRL+C를 사용하세요.

언급할 또 다른 점은 fork()현재 Linux 커널에서는 이것이 clone()시스템 호출을 사용하여 구현되므로 대신 strace 출력에서 ​​이를 볼 수 있다는 것입니다 clone(…).fork()

관련 정보