是否可以在裸Linux内核之上运行通用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]我通过执行buildroot构建了根文件系统,默认情况下来自Ciro Santilli's linux-kernel-module-cheat。我编译了linux内核并获得了相应的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/
这感觉不对,我这样做是因为我没有找到直接在Guest Machine中编译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's linux-kernel-module-cheat获取的。 rootfs.ext2是系统启动的根文件系统,bzImage是我要启动客户机的内核映像。
5]客户机在shell中进行模拟。这是我的预期,因为我只虚拟化裸内核而不是整个操作系统映像。
我显示了buildroot登录,我以root身份登录并运行以下命令:
当我尝试运行我的hello程序时,我显示以下消息:
-sh: ./hello_world: not found
我想我的程序永远不会被执行,即使我已经通过调试看到它被作为elf文件加载到系统中。
如果我输入一个不存在的随机命令,我会得到同样的错误。
目标是让hello_world程序在用户空间中运行,在内核之上,我不希望它成为它的一部分。
我同意你们的意见,我可能会错过一些图书馆或基本的东西,但我不知道该怎么做。
答案 0 :(得分:1)
如果您打算这样做,基本上可以运行一个进程而不是init。要运行进程而不是系统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进程并让该进程启动您的应用程序。
我过去看过你的命令输出。您是否使用shell脚本来启动应用程序?如果是这样,它可能表示您当前缺少虚拟环境中的某些库。
修改强>
也许你可以改为创建一个静态链接的应用程序,这意味着将所有库编译到同一个文件中。在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 。
希望有所帮助。