베어 리눅스 커널 위에서 일반 C 프로그램을 실행할 수 있습니까?
Qemu와 함께 가상화 된 Linux 최소 시스템을 사용하고 있는데 여기에서 사용자 지정 커널과 루트 파일 시스템을로드하지만 사용자 공간 hello world 프로그램을 실행할 수없는 것 같습니다.
편집 1 : 질문을 더 자세하게 업데이트했습니다. 내가 따라온 단계는 다음과 같습니다.
1] 호스트 컴퓨터에서 다음 명령을 사용하여 hello_world 프로그램을 컴파일했습니다.
gcc hello_world.c -o hello_world
소스 코드는 다음과 같습니다.
#include <stdio.h>
int main(int argc, char const *argv[]) {
printf("Hello world!\n");
return 0;
}
내 호스트 컴퓨터에서 프로그램을 실행하면 제대로 작동합니다. @nexus가 프로그램이 빌드 된 라이브러리를 제안한대로 확인했으며 다음과 같습니다.
$ ldd hello_world
linux-vdso.so.1 => (0x00007ffc0dfc8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efd90658000)
/lib64/ld-linux-x86-64.so.2 (0x000055a57447f000)
2] Ciro Santilli의 linux-kernel-module-cheat 에서 기본적으로 제공되는 buildroot를 실행하여 루트 파일 시스템을 구축했습니다 . 나는 리눅스 커널을 컴파일하고 해당 bzImage를 얻었습니다.
3] 다음과 같이 루트 파일 시스템을 마운트하고 그 안에 컴파일 된 프로그램을 복사했습니다.
sudo mount -t ext2 rootfs.ext2 /home/andreww/Desktop/mountfile/
sudo cp hello_world /home/andreww/Desktop/mountfile/
sudo umount /home/andreww/Desktop/mountfile/
이것은 잘못된 느낌입니다. 게스트 머신에서 직접 C 프로그램을 컴파일하는 방법을 찾지 못했기 때문에 그렇게했습니다. 게스트 컴퓨터에는 gcc가 없습니다. 실제로 호출하려고하면 다음과 같이 표시됩니다.
# -sh: gcc: not found
4] 명령으로 에뮬레이트 된 시스템을 시작했습니다.
qemu-system-x86_64 \
-M pc \
-append 'root=/dev/vda $extra_append' \
-drive file=${images_dir}/rootfs.ext2,if=virtio,format=raw \
-kernel ${images_dir}/bzImage \
-m 256M \
-net nic,model=virtio \
-net user \
-enable-kvm \
-cpu host \
-smp threads=4
Ciro Santilli의 linux-kernel-module-cheat 에서 가져 왔습니다 . rootfs.ext2는 시스템이 시작되는 루트 파일 시스템이고 bzImage는 게스트 머신을 시작할 커널 이미지입니다.
5] 게스트 시스템은 셸 내에서 에뮬레이션됩니다. 이것은 전체 운영 체제 이미지가 아닌 베어 커널 만 가상화하기 때문에 예상했던 것입니다.
buildroot 로그인이 표시되고 root로 로그인하고 다음 명령을 실행합니다.
hello 프로그램을 실행하려고하면 다음 메시지가 표시됩니다.
-sh: ./hello_world: not found
내 프로그램이 시스템에 elf 파일로로드 된 것을 디버깅하여 본 적이 있어도 내 프로그램이 실행되지 않는다고 가정합니다.
존재하지 않는 임의의 명령을 입력하면 동일한 오류가 발생합니다.
목표는 hello_world 프로그램이 커널 위에있는 사용자 공간에서 실행되도록하는 것입니다. 저는 그것이 커널의 일부가되기를 원하지 않습니다.
나는 너희들과 동의한다. 나는 아마도 도서관이나 기본적인 것을 놓치고있을 것이다. 그러나 나는 무엇을 해야할지 모르겠다.
기본적으로 init 대신 프로세스를 실행할 수 있습니다. 시스템 초기화 애플리케이션 대신 프로세스를 실행하려면 원래 init를 바꾸거나 init = / path / to / you / application 을 커널 매개 변수로 VM에 전달할 수 있습니다.
그러나 명심해야 할 몇 가지 사항이 있습니다.
모든 라이브러리는 애플리케이션을 빌드 한 시스템과 동일한 위치에있는 VM에 있어야합니다. 여기에는 빌드 된 기본 c 라이브러리도 포함됩니다. 다음을 사용하여 모든 라이브러리 목록을 얻을 수 있습니다.
ldd hello_world
예를 들어 다음 프로그램을 컴파일하면
#include <stdio.h>
int main(int argc, char** argv) {
printf("hello world!\n");
return 0;
}
ldd의 결과로 이와 같은 것을 얻을 수 있습니다.
$ ldd test
linux-vdso.so.1 => (0x00007ffdba6ba000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8559f50000)
/lib64/ld-linux-x86-64.so.2 (0x000055fc58ece000)
init 프로세스를 교체하는 경우 콘솔 인터럽트를 처리하고 적절히 처리해야합니다. 그렇지 않으면 정말 나쁜 시스템 충돌의 위험이 있습니다. 결과적으로, 당신이 무엇을하고 있는지 정말로 모른다면 init 프로세스를 유지하고 그 프로세스가 당신의 애플리케이션을 시작하도록하는 것이 좋은 생각입니다.
나는 과거에 당신의 명령의 출력을 보았다. 애플리케이션을 시작하기 위해 셸 스크립트를 사용하고 있습니까? 그렇다면 현재 가상 환경에서 일부 라이브러리가 누락되었음을 나타낼 수 있습니다.
편집하다:
대신 모든 라이브러리를 동일한 파일로 컴파일하는 정적으로 연결된 애플리케이션을 만들 수 있습니다. gcc에서는 해당 -static 스위치를 사용할 수 있습니다 . 차이점보기 :
$ gcc -o test test.c
$ ldd test
linux-vdso.so.1 => (0x00007ffcd1f22000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f088d43a000)
/lib64/ld-linux-x86-64.so.2 (0x00005580f8a2b000)
$ gcc -static -o test test.c
$ ldd test
not a dynamic executable
이미 언급했듯이 ldd를 사용하여 필요한 라이브러리를 찾을 수 있습니다. 일반적으로 사용하는 또 다른 옵션 은 출력이 더 자세하므로 objdump 입니다.
따라서 내 응용 프로그램의 경우 다음과 같은 의미가 있습니다 (출력을 관련 섹션으로 줄였습니다).
$ objdump -p test
test: file format elf64-x86-64
[...]
Dynamic Section:
NEEDED libc.so.6
INIT 0x00000000004003c8
FINI 0x00000000004005c4
INIT_ARRAY 0x0000000000600e10
INIT_ARRAYSZ 0x0000000000000008
FINI_ARRAY 0x0000000000600e18
FINI_ARRAYSZ 0x0000000000000008
[...]
그래서 내 경우에는, 그게 내가 복사해야 libc.so.6으로입니다 /lib/x86_64-linux-gnu/libc.so.6 내 호스트에 /lib/x86_64-linux-gnu/libc.so.6은 가상 머신 내에서.
도움이되기를 바랍니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다