그것을 분해하겠습니다.
당신이 실행 파일을 실행하면 시스템 호출의 순서는, 특히 실행 fork()
및 execve()
:
fork()
호출 프로세스의 하위 프로세스를 작성합니다.이 프로세스는 (대부분) 부모의 정확한 사본이며, 둘 다 여전히 동일한 실행 파일을 실행합니다 (기록 중 복사 메모리 페이지 사용). 두 번 리턴합니다. 상위에서 하위 PID를 리턴합니다. 자식에서는 0을 반환합니다. 일반적으로 자식 프로세스는 즉시 execve를 호출합니다.
execve()
실행 파일의 전체 경로를 인수로 사용하고 호출 프로세스를 실행 파일로 바꿉니다. 이 시점에서 새로 생성 된 프로세스는 자체 가상 주소 공간, 즉 가상 메모리를 가져오고 실행은 시작점에서 시작합니다 (새 프로세스에 대한 플랫폼 ABI의 규칙에 의해 지정된 상태에서).
이 시점에서 커널의 ELF 로더는 실행 파일 의 텍스트 및 데이터 세그먼트 를 마치 마치mmap()
시스템 호출을 (공유 읽기 전용 및 개인 읽기-쓰기 매핑으로) 메모리에 매핑했습니다. BSS는 MAP_ANONYMOUS를 사용하는 것처럼 매핑됩니다. (BTW, 여기서는 단순성을 위해 동적 링크를 무시하고 있습니다. 동적 링커 는 주 실행 파일의 진입 점으로 점프하기 전에 모든 동적 라이브러리를 open()
s 및 mmap()
s합니다.)
새로 실행 된 () 사용자가 자체 코드를 실행하기 전에 실제로 디스크에서 메모리로 몇 페이지 만로드됩니다. 프로세스가 가상 주소 공간의 해당 부분에 닿으면 추가 페이지가 필요에 따라 페이징됩니다 . (사용자 공간 코드를 실행하기 전에 코드 또는 데이터 페이지를 미리로드하는 것은 성능 최적화 일뿐입니다.)
실행 파일은 하위 레벨의 inode로 식별됩니다. 파일이 실행되기 시작한 후에 커널은 열린 파일 디스크립터 나 파일 백업 메모리 매핑과 같이 파일 이름이 아닌 inode 참조에 의해 파일 내용을 그대로 유지합니다. 따라서 실행 파일을 파일 시스템의 다른 위치 나 다른 파일 시스템으로 쉽게 옮길 수 있습니다. 참고로 프로세스의 다양한 통계를 확인하려면 /proc/PID
(PID는 주어진 프로세스의 프로세스 ID) 디렉토리를 들여다 볼 수 있습니다 . /proc/PID/exe
디스크에서 연결이 해제되어 있어도 실행 파일을으로 열 수도 있습니다 .
이제 움직임을 파헤쳐 보자.
동일한 파일 시스템 내에서 파일을 이동할 때 실행되는 시스템 호출 rename()
은 파일 이름을 다른 이름으로 바꾸는 것만으로 파일의 inode는 동일하게 유지됩니다.
두 개의 서로 다른 파일 시스템 사이에서 두 가지 일이 발생합니다.
rm
실제로는 unlink()
디렉토리 트리에서 주어진 파일을 가져 오기 때문에 디렉토리에 대한 쓰기 권한이 있으면 해당 디렉토리에서 파일을 제거 할 수있는 충분한 권한을 얻게됩니다.
이제 재미있게, 두 파일 시스템간에 파일을 이동할 때 어떤 권한이 없는지 상상해보십시오. unlink()
하고 소스에서 파일 대한 .
파일은 처음에 대상 ( read()
, write()
) 에 복사 된 다음 unlink()
권한이 충분하지 않아 실패합니다. 따라서 파일은 두 파일 시스템 모두에 남아 있습니다 !!