需求来源于如何构建arm平台的Ubuntu文件系统。
我们希望在ARM开发板上使用Ubuntu系统,那么就需要构建一个Ubuntu的根文件系统,然后可基于该基础文件系统,进一步扩展开发。比如,可以使用不同的桌面版本,安装需要的arm源安装包等。
当然,也可能是,大部分的需求更多来源于如何在host系统上构建arm环境,编译arm程序。
殊途同归,问题都归结为一点,即如何在host系统上构建arm模拟环境。
从上述构建文件系统需求出发,查找资料。发现,搜索到的资料无一例外的都提到了chroot命令和qemu-arm-static安装包。
具体思路是,先安装qemu-arm-static安装包,然后构建一个目标平台的根文件系统(其实是根文件系统目录,包含有常规的一些可执行程序)。我们将该根文件系统作为基础裸根文件系统。这一基础根文件系统可从Ubuntu官网上下载。注意,这个基础根文件系统里面自带的arm平台程序,是在ubuntu官网上打包好的,我们只需要根据硬件平台特点,下载对应的包解压即可。比如是32位还是64位,是否支持硬件浮点计算等。如果你有自己待验证的程序,也可以放进去,只要保证是基于对应硬件平台的交叉工具链编译的。
https://ubuntu.com/
有了上述基础文件系统目录后,还需要将主机的proc sys dev pts等目录挂载到目标文件系统对应的路径下,最终实际切换到目标系统硬件上时,proc sys等是所在目标硬件上运行的内核生成的,设备目录也是目标硬件内核动态监测生成或者极少的是通过应用层udev工具生成。这些东西并不天然的包含在镜像文件中。
也就是到时候,这些目录下的系统信息和设备信息还是基于主机系统的,这样便于我们做一些操作,毕竟是模拟的。后面了解模拟器工作原理后,你就可以更深刻的理解这一点。
之后,将安装qemu-arm-static后下载的usr bin目录下的qemu-arm-static 或者qemu-aarch-static程序拷贝到目标文件系统对应目录下。
至此,我们在host上构建了一个目标平台的根目录,这个根目录包含三部分:
1 原始的ubuntu系统的基于arm平台的基础程序
2 主机host系统挂载过去的proc 和 sys等目录
3 下载的qemu-arm-static或aarch(64位)对应目录下的程序
上述工作准备好后,执行chroot切换到目标平台根目录。如此,即切换到arm环境,也就是qemu构建的模拟器环境。
按照上述流程执行,确实进入了arm模拟器环境。但是疑问来了,chroot是怎么就切换到arm模拟器环境了,这中间到底发生了什么?
chroot本身是一个命令,可以完成根文件目录的切换,也就是将新的目录作为根目录,挂载到系统中。
这样做,就构建了一个比较弱的隔离环境。说是比较弱的,是因为此时只是根目录相关的路径变换了,而系统的很多内部资源仍然是全局可见的。
当然,需求本身就是多样的,如果用户只是想在独立的目录下进行编译安装更新等操作,chroot的功能则很好的契合了这种需求,再多一些隔离操作,反而显得多余了。
但是,仅从切换根目录路径这一点来看,chroot似乎还不至于完成平台的切换。再多一点细节,chroot切换根目录后,会默认执行bash程序,构建新的交互环境。当然,调用者也可以指定要执行的程序。
那从这个逻辑思路来走的话,chroot只能完成将根目录切换到为arm环境准备的根目录,并执行arm环境根目录下的bash程序。且这个bash程序应该是基于arm指令的,不能够成功执行才对。
但是我们看到实际结果是成功切换到arm模拟器环境了。
这中间的中间发生了什么?一定是有一个纽带,完成了关联。
再回到原始流程上,除了chroot外,我们发现,需要安装qemu-arm-static并拷贝这个程序到目标平台的usr bin 目录下,即跟其安装目录一致。为什么会有这个要求?
再继续搜索资料。
https://blog.csdn.net/weixin_35511255/article/details/117550321中提到了binfmt_misc,
https://hblok.net/blog/posts/2014/02/06/chroot-to-arm/ 外部的一些资料也提到了,之前看资料时,对这些忽略了。
查看binfmt_misc的说明,大意是一个二进制格式的适配系统。类似windows平台上,根据后缀选择或者说匹配执行程序这样一个功能。
而linux下的这个系统,也具有这个功能,而且不仅可以通过后缀匹配,还可以根据文件魔术字段匹配。
查看系统下该目录下的相关信息
root@ubuntu:/proc/sys/fs/binfmt_misc# ls -l
total 0
-rw-r--r-- 1 root root 0 Nov 23 19:47 python2.7
-rw-r--r-- 1 root root 0 Nov 23 19:47 python3.6
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-aarch64
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-alpha
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-arm
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-armeb
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-cris
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-m68k
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-microblaze
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-mips
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-mips64
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-mips64el
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-mipsel
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-ppc
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-ppc64
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-ppc64abi32
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-ppc64le
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-s390x
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-sh4
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-sh4eb
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-sparc
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-sparc32plus
-rw-r--r-- 1 root root 0 Nov 23 19:47 qemu-sparc64
--w------- 1 root root 0 Nov 23 19:47 register
-rw-r--r-- 1 root root 0 Nov 23 19:47 status
root@ubuntu:/proc/sys/fs/binfmt_misc#
可以看到qemu注册到里面,所以qemu是使用了该系统。
那么现在可以猜测,qemu安装时应该是注册了对arm架构程序的支持。也就是,如果目标文件是arm架构的(通过可执行文件里的magic字段匹配),则使用其对应的程序来解释执行。
这里的register文件只能写,不能读,但是其他文件提供了注册的信息。我们来看看
root@ubuntu:/proc/sys/fs/binfmt_misc# cat qemu-arm
enabled
interpreter /usr/bin/qemu-arm-static
flags: OC
offset 0
magic 7f454c4601010100000000000000000002002800
mask ffffffffffffff00fffffffffffffffffeffffff
root@ubuntu:/proc/sys/fs/binfmt_misc# cat qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64-static
flags: OC
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff
root@ubuntu:/proc/sys/fs/binfmt_misc#
可以看到,这两个应该都是通过magic过滤的,并且enable了。我们记下这里的magic头几个字节内容,后面会用到。7f 45 4c 46
我们执行以下arm架构的程序看看
root@ubuntu:/proc/sys/fs/binfmt_misc# /home/work/Ubuntu/bin/bash
/lib/ld-linux-aarch64.so.1: No such file or directory
提示的是动态链接库找不到。
status文件提供了全局的使能功能,我们关闭所有匹配,再来看看
root@ubuntu:/proc/sys/fs/binfmt_misc# echo 0 > status
root@ubuntu:/proc/sys/fs/binfmt_misc#
root@ubuntu:/proc/sys/fs/binfmt_misc# cat status
disabled
root@ubuntu:/proc/sys/fs/binfmt_misc# /home/work/Ubuntu/bin/bash
bash: /home/work/Ubuntu/bin/bash: cannot execute binary file: Exec format error
root@ubuntu:/proc/sys/fs/binfmt_misc#
此时执行提示的是格式不对,不是库找不到了。到此,我们可以总结出,enable时,虽提示库找不到,但那是程序运行过程的错误,说明程序的格式匹配是成功了,只是在当前文件系统路径下,无法找到对应的动态库。而disable后,一开始就是可执行文件是无法运行的。
这就说明,chroot本身的功能并没有差异,当切换路径后,执行默认bash程序时,系统判断到是arm文件(通过qemu注册的匹配检测),就调用usr bin目录(上述注册信息中使用的,这也是为啥要拷贝到对应目录的原因)下的qemu模拟器程序来执行
最终,模拟器程序将arm指令翻译为host系统的x86指令,进行执行,从而完成模拟执行。
bash执行时及之后所有调用链上的程序都是由上述模拟器程序模拟后在主机系统中执行的。
如此,就完成了一种弱的平台环境暂时切换的功能。
为了进一步的验证,我们看看arm平台下bash程序的开头几十个字节
root@ubuntu:/proc/sys/fs/binfmt_misc# hexdump -n 64 /home/work/Ubuntu/bin/bash
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000010 0003 00b7 0001 0000 2610 0003 0000 0000
0000020 0040 0000 0000 0000 83a0 0012 0000 0000
0000030 0000 0000 0040 0038 0009 0040 001b 001a
0000040
可以看到 45 7f 46 4c等几个字节,跟前面注册里的magic可以匹配上,问题得到验证。
chroot应该只是切换当前的shell,甚至跟用户都非强绑定,当前shell切换到arm模拟器环境后,我们还可以继续登录原始host,在原始host的正常目录下进行正常的操作。
在当前shell中执行exit就退出chroot切换的环境,回到host系统。至此,进出模拟器的过程就通过chroot命令完成了。
有了上面的基础,我们就可以在arm模拟器中安装arm包,然后做出属于自己的定制跟文件系统,将其刷机到自己的开发板,实现自己的专属系统。
ENJOY......