커널은 리눅스에서 실행 가능한 바이너리 파일을 어떻게 얻습니까?
커널은 리눅스에서 실행 가능한 바이너리 파일을 어떻게 얻습니까?
간단한 질문 같지만, 누구든 제가 깊게 파도록 도와줄 수 있나요?파일을 메모리에 로드하는 방법과 실행 코드를 시작하는 방법은 무엇입니까?
누가 나를 도와서 상황을 차근차근 말해줄 수 있습니까?
최고의 순간들exec0 Linux 4.0에서
이 모든 것을 알아내는 가장 좋은 방법은 GDB 단계에서 QEMU로 커널을 디버그하는 것입니다. GDB와 QEMU로 리눅스 커널을 디버그하는 방법은 무엇입니까?
fs/exec.c시스템 호출을 정의합니다.SYSCALL_DEFINE3(execve다음으로 간단히 전달
do_execve.do_execve전달 대상
do_execveat_common.do_execveat_common다음 주요 기능을 찾으려면 반환 시점을 추적합니다.
retval마지막으로 수정됩니다.구축을 시작합니다.
struct linux_binprm *bprm프로그램을 설명하고 그것을 전달합니다.exec_binprm실행에 옮깁니다.exec_binprm다시 한 번 반환 값을 따라 다음 주요 통화 내용을 찾습니다.
search_binary_handler핸들러는 실행 파일의 첫 번째 매직 바이트에 의해 결정됩니다.
가장 일반적인 두 가지 핸들러는 해석된 파일에 대한 핸들러입니다.
#!및 법)및 ELF용(\x7fELFmagic), 그러나 커널에 내장된 다른 것들이 있습니다.a.out. 또한 사용자는 /proc/sys/fs/binfmt_misc를 통해 자신의 것을 등록할 수 있습니다.ELF 핸들러는 다음 위치에서 정의됩니다.
fs/binfmt_elf.c.참고 항목:왜 사람들은 파이썬 스크립트의 첫 줄에 #!/usr/bin/envpython shebang을 쓸까요?
formatslist는 모든 핸들러를 포함합니다.각 핸들러 파일에는 다음과 같은 내용이 포함되어 있습니다.
static int __init init_elf_binfmt(void) { register_binfmt(&elf_format); return 0; }그리고.
elf_formatㅇstruct linux_binfmt그 파일에 정의되어 있습니다.__init는 마법이며 커널이 시작될 때 호출되는 마법 섹션에 해당 코드를 입력합니다.리눅스 커널 코드에서 __init는 무엇을 의미합니까?링커급 의존성 주입!
인터프리터가 무한히 실행할 경우를 대비해 재귀 카운터도 있습니다.
시도해 보기:
echo '#!/tmp/a' > /tmp/a chmod +x /tmp/a /tmp/a다시 한 번 반환 값을 추적하여 다음 결과를 확인하고 다음 결과를 확인합니다.
retval = fmt->load_binary(bprm);어디에
load_binary구조체의 각 핸들러에 대해 정의됩니다: C-style polymorphism.
fs/binfmt_elf.c:load_binary실제 작동:
- ELF 사양에 따라 ELF 파일을 구문 분석합니다. ELF 파일 형식에 대한 개요는 다음과 같습니다.리눅스에서 hex 에디터를 사용하여 실행 가능한 ELF 파일을 만드는 방법은?
- 구문 분석된 ELF 파일을 기반으로 프로세스 초기 프로그램 상태를 설정합니다. 특히 다음과 같습니다.
- a에서 초기 레지스터 설정
struct pt_regs - 초기 가상 메모리 설정, ELF 세그먼트에 메모리가 지정됩니다.ELF 파일 형식에서 섹션과 세그먼트의 차이점은 무엇입니까?
- 불러
start_thread, 프로세스를 스케줄러가 예약할 수 있는 것으로 표시합니다.
- a에서 초기 레지스터 설정
결국 스케줄러는 프로세스를 실행하기로 결정하고, 그 다음에 저장된 PC 주소로 점프해야 합니다.
struct pt_regs또한 Ring 3 / EL0와 같은 덜 특권적인 CPU 상태로 이동: 운영 체제의 맥락에서 Ring 0 및 Ring 3은 무엇입니까?스케줄러는 커널이 이전에 구성한 인터럽트를 주기적으로 생성하는 클럭 하드웨어(예: 이전 x86 PIT 또는 ARM 타이머)에 의해 주기적으로 웨이크업됩니다.커널은 또한 타이머 인터럽트가 실행될 때 스케줄러 코드를 실행하는 핸들러를 등록합니다.
TODO: 소스 분석을 계속 진행합니다.다음에 일어날 일:
- 커널은 ELF의 INTERP 헤더를 파싱하여 동적 로더를 찾습니다(일반적으로 다음과 같이 설정됨).
/lib64/ld-linux-x86-64.so.2). - 존재하는 경우:
- 커널은 메모리에 실행될 동적 로더와 ELF를 매핑합니다.
- 동적 로더가 시작되어 메모리의 ELF로 포인터를 가져갑니다.
- 이제 사용자랜드에서 로더는 어떻게든 스스로 헤더를 파싱하고,
dlopen그들에게 dlopen구성 가능한 검색 경로를 사용하여 해당 라이브러리를 찾습니다(ldd그리고 친구들), 그들을 기억에 매핑하고, 어떻게든 ELF에게 그것의 사라진 상징을 어디서 찾을 것인지 알려줍니다.- 로더가 호출합니다.
_start엘프의
그렇지 않으면 커널은 동적 로더 없이 실행 파일을 메모리에 직접 로드합니다.
따라서 특히 실행 파일이 PIE인지 아닌지를 확인해야 합니다. 임의의 위치에 있는 메모리에 저장되어 있는지 여부를 확인해야 합니다.gcc 및 ld에서 위치 독립 실행 파일에 대한 -fPIE 옵션은 무엇입니까?
리눅스 커널에서 두 개의 시스템 호출이 관련되어 있습니다.포크 시스템 호출(또는 가능한 경우)vfork아니면clone)는 호출 프로세스와 유사한 새 프로세스를 만드는 데 사용됩니다(다음을 제외한 모든 Linux 사용자-랜드 프로세스).init에 의해 생성됩니다.fork또는 친구).execeve 시스템 호출은 프로세스 주소 공간을 새 것으로 대체합니다(본질적으로 ELF 실행 파일 및 익명 세그먼트에서 세그먼트를 정렬한 다음 스택 포인터를 포함한 레지스터를 초기화함).x86-64 ABI 보충판과 리눅스 어셈블리에서 자세한 정보를 제공하는 방법.
동적 연결은 다음에 발생합니다.execve그리고 관련된 것입니다./lib/x86_64-linux-gnu/ld-2.13.so파일, ELF의 경우 "인터프리터"로 간주됩니다.
이미 참조된 ELF 문서를 읽고 나면 실제로 실행되는 커널 코드만 읽으셔야 합니다.
코드를 이해하기 어렵다면 UML 리눅스를 구축하고 디버거에서 해당 코드를 살펴볼 수 있습니다.
ELF와 같은 실행 파일 형식을 이해하는 것부터 시작할 수 있습니다. http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
ELF 파일에는 이진 파일의 일부를 메모리에 로드하는 방법과 위치를 설명하는 헤더가 있는 여러 섹션이 있습니다.
그렇다면 바이너리를 로드하고 동적 링크인 ld-linux를 처리하는 linux 부분을 읽어보는 것을 추천합니다.ld-linux에 대한 좋은 설명이기도 합니다. http://www.cs.virginia.edu/ ~ dww4s/articles/ld_linux.
언급URL : https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux
'programing' 카테고리의 다른 글
| java 속성 파일의 HashMap을 Spring @Value로 채우는 방법 (0) | 2023.10.26 |
|---|---|
| ssh: 호스트 이름 github.com 을 확인할 수 없습니다. 이름이나 서비스를 알 수 없습니다. 치명적:리모트 엔드가 예기치 않게 끊어졌습니다. (0) | 2023.10.26 |
| CSS 배경 이미지를 너비에 맞게 조정하고 높이를 비례하여 자동으로 조정해야 함 (0) | 2023.10.26 |
| jQuery의 $.ajax URL 인코딩 문제 (0) | 2023.10.26 |
| RecyclerView 항목이 나타날 때 해당 항목을 애니메이션화하는 방법 (0) | 2023.10.26 |