programing

커널은 리눅스에서 실행 가능한 바이너리 파일을 어떻게 얻습니까?

subpage 2023. 10. 26. 21:04
반응형

커널은 리눅스에서 실행 가능한 바이너리 파일을 어떻게 얻습니까?

커널은 리눅스에서 실행 가능한 바이너리 파일을 어떻게 얻습니까?

간단한 질문 같지만, 누구든 제가 깊게 파도록 도와줄 수 있나요?파일을 메모리에 로드하는 방법과 실행 코드를 시작하는 방법은 무엇입니까?

누가 나를 도와서 상황을 차근차근 말해줄 수 있습니까?

최고의 순간들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_formatstruct 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

    실제 작동:

  • 결국 스케줄러는 프로세스를 실행하기로 결정하고, 그 다음에 저장된 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

반응형