Linux 커널을 이해하면 순서대로 execve()
호출되는 do_execve( )
것이 무엇인지 알 수 있습니다.
파일 경로 이름, 명령줄 인수 및 환경 문자열을 새로 할당된 하나 이상의 페이지 프레임에 복사합니다.(결국 사용자 모드 주소 공간에 할당됩니다.)
execve()
성공적인 종료 후 프로세스가 호출하는 _start
루틴이 정확합니까 rt0.o
?
APUE에 따르면:
커널이 (exec 함수 중 하나를 통해) C 프로그램을 실행할 때, 메인 함수가 호출되기 전에 특별한 시작 루틴이 호출됩니다. 실행 가능한 프로그램 파일은 이 루틴을 프로그램의 시작 주소로 지정합니다. 이는 링크 편집기를 호출할 때 C 컴파일러에 의해 설정됩니다.이 시작 루틴은 커널에서 값(명령줄 인수 및 환경)을 가져와서 설정합니다.그런 다음 이전에 표시된 것처럼 main 함수가 호출됩니다.
루틴 __start
이 명령줄 인수와 환경도 다시 복사합니까?
do_execve()
복사 _start
명령줄 인수와 환경의 차이점은 무엇입니까? 두 번 복사하는 것은 낭비가 아닌가?
감사해요.
답변1
execve()가 성공적으로 종료된 후 프로세스가 crt0.o의 _start 루틴을 호출하는 것이 맞습니까?
불필요한. execve
시스템 호출이 반환 되면 바이너리 진입점(ELF에서는 e_entry
헤더의 필드)이 무엇이든 텍스트/코드 주소에서 프로세스 실행이 계속됩니다. 예:
echo 'void run(void){ printf("in run\n"); exit(0); }' |
gcc -Wl,-e,run -nostartfiles -include stdio.h -include stdlib.h -Wall -x c - -o /tmp/run
/tmp/run
in run
_start
많은(대부분?) Unix 시스템의 진입점 루틴에 대한 일반적인 이름입니다.
루틴
_start
이 명령줄 인수와 환경도 다시 복사합니까?
이 작업을 수행할 수 있지만 일반적으로 그런 작업은 수행하지 않습니다. 해야 할 유일한 일은 C 함수에 전달될 수 있도록 재정렬하는 것입니다 main
.
문제는 단순히 진입점을 C 함수로 선언할 수 없다는 것입니다.
_start(argc, ...)
그리고 get 매개변수를 사용하세요 va_args
. on 에서 x86_64
C 호출 규칙은 (처음 몇 개) 인수가 레지스터에 전달될 것으로 예상합니다.아니요어떻게 배달되나요 _start
?
_start
일반적으로 호출하기 전에 수행해야 할 다른 작업이 있습니다 main
. 매우 중요한 것은 정적 생성자를 실행하는 것입니다. 이는 C++
정적 생성자를 사용할 수 있습니다(사용하면 gcc
함수를 정의하여 프로그램에서 수행할 수 있음). C
그리고 __attribute__((constructor))
).
libc.so
glibc 기반 시스템의 표준 시작 코드는 정의된 함수(동적 링크)도 전달합니다. __libc_start_main()
이는 미리 로드된 동적 라이브러리에서 코드를 재정의하고 바이너리 문서를 수정하지 않고도 자신만의 초기화 항목을 추가할 수 있기 때문에 좋습니다. 바라보다여기예를 들어.