Linux 的 binfmt_misc (binfmt) module 介紹
linux 透過 qemu 的動態轉譯(dynamic translation)模式, 能直接執行別架構的程式. 舉例: x86_64 中執行 arm64 架構的程式. 然而每次都必須透過 qemu-aarch64 [program] [args...] 的方式執行, 似乎有點瑣碎. 以下就介紹 linux 是如何使用 binfmt_misc kernel module 來化繁為簡...
qemu 與 binfmt 搭配
測試環境為 x86_64 架構, 使用 aarch64 toolchain 編譯下方 hello.c 為 static 的程式. 免去執行時候 link 尋找 libraries 的問題. 這邊透過 1) 直接執行. 2)藉由 qemu 執行. 3) qemu 搭配 binfmt_misc 來示範結果.
#include <stdio.h> int main() { printf("hello !!\n"); return 0; }
首先安裝 aarch64 的 toolchain 來編譯程式. 並確認編譯出來的格式為 aarch64
# 安裝 arm 版本的 toolchain yijyun@yijyun-VirtualBox:~$ sudo apt-get install gcc-aarch64-linux-gnu # 使用 arm-gcc 編譯 yijyun@yijyun-VirtualBox:~$ aarch64-linux-gnu-gcc -static hello.c # 查看編譯出來的格式 yijyun@yijyun-VirtualBox:~$ aarch64-linux-gnu-objdump -f a.out a.out: file format elf64-littleaarch64 architecture: aarch64, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x0000000000400cd8 # 顯示本機的架構 yijyun@yijyun-VirtualBox:~$ uname -i x86_64
1) 執行 aarch64 架構的程式
執行 aarch64 架構的程式, 直接顯示錯誤訊息...
# 執行 yijyun@yijyun-VirtualBox:~$ ./a.out -bash: ./a.out: cannot execute binary file: Exec format error
2) qemu-aarch64 執行 aarch64 架構的程式
安裝 qemu-user 模擬處理器套件, 藉由 qemu-aarch64 指令來間接執行 aarch64 架構的程式.
# 安裝 qemu-user yijyun@yijyun-VirtualBox:~$ sudo apt-get install qemu-user # 執行 yijyun@yijyun-VirtualBox:~$ qemu-aarch64 a.out hello !!
3) qemu 搭配 binfmt_misc 來執行 aarch64 架構的程式
先安裝 qemu-user-static 與 binfmt-support. 其中 qemu-user-static 是 qemu-user 的 static 版本. 主要是為了與 binfmt_misc 搭配. 這時候執行 aarch64 程式的時候, 已不需要以 qemu-aarch64 [program] [args...] 的方式. 直接執行也沒有錯誤發生, 是不是方便許多! 不過實際上系統實行的時候是呼叫 qemu-aarch64-static [program] [args...]. 使用者察覺不到而已 XD.
# 安裝相關套件 sudo apt-get install apt-get install qemu-user-static binfmt-support # 執行 yijyun@yijyun-VirtualBox:~$ ./a.out hello !!
binfmt_misc 介紹
binfmt_misc 分析
看過上方的執行後, 多少會有疑問. 究竟 kernel 是怎麼判斷的阿!!!
這時候就從 /proc/sys/fs/binfmt_misc 來一探究竟! 可以看到底下有許多不同的架構.
由於程式是基於 aarch64, 就輸出 qemu-aarch64 內容來看 !
# 查看 binfmt_misc 支援的格式 yijyun@yijyun-VirtualBox:~$ ls /proc/sys/fs/binfmt_misc/ jar qemu-aarch64 qemu-armeb qemu-microblaze qemu-mips64el qemu-ppc64 qemu-s390x qemu-sparc register python2.7 qemu-alpha qemu-cris qemu-mips qemu-mipsel qemu-ppc64abi32 qemu-sh4 qemu-sparc32plus status python3.5 qemu-arm qemu-m68k qemu-mips64 qemu-ppc qemu-ppc64le qemu-sh4eb qemu-sparc64 # 顯示 qemu-aarch64 yijyun@yijyun-VirtualBox:~$ cat /proc/sys/fs/binfmt_misc/qemu-aarch64 enabled interpreter /usr/bin/qemu-aarch64-static flags: OC offset 0 magic 7f454c460201010000000000000000000200b700 mask ffffffffffffff00fffffffffffffffffeffffff
經由 qemu-aarch64 的內容可以看出, 根據 binfmt_misc 設定檔來決定 kernel 是否可以直接執行某架構的程式
而這些架構就根據設定裡的 interpreter, magic 來判斷架構和使用對應的動態轉譯程式, 如qemu.
看到這就有種豁然開朗的感覺 XD
binfmt_misc 與 chroot
binfmt_misc, qemu 最適合的應用就是與 chroot 搭配. 藉由 chroot 切換 / (根目錄) 到另一種架構的 / (根目錄). 在使用 binfmt_misc 和 qemu, 就如同在特定架構運行程式
以下為範例為在 x86_64 架構下切換到 aarch64架構根目錄.
首先從 Ubuntu Base rootfs [2]下載 aarch64 的 rootfs 並解壓縮. 在複製 qemu-aarch64-static 到 aarch64 架構的 rootfs 裡面. 再藉由 chroot 切換到 aarch64的根目錄.
# 列出 base rootfs 內容 root@yijyun-VirtualBox:/home/yijyun/ubuntu-aarch64-rootfs# ls rootfs/ bin boot dev etc home lib media mnt opt proc root run sbin snap srv sys tmp usr var # 複製 /usr/bin/qemu-aarch64-static 到 rootfs/usr/bin/ # 1) qemu-aarch64 interpreter 的路徑為此 # 2) 這也是為什麼要編譯成 static 的原因 root@yijyun-VirtualBox:/home/yijyun/ubuntu-aarch64-rootfs# cp -fa /usr/bin/qemu-aarch64-static rootfs/usr/bin/ # 藉由 chroot 切換到 aarch64 的根目錄 root@yijyun-VirtualBox:/home/yijyun/ubuntu-aarch64-rootfs# chroot rootfs/ # 顯示 root@yijyun-VirtualBox:/# ls bin boot dev etc home lib media mnt opt proc root run sbin snap srv sys tmp usr var # 透過 objdump 驗證架構 root@yijyun-VirtualBox:/# objdump -f /bin/ls /bin/ls: file format elf64-littleaarch64 architecture: aarch64, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x0000000000404cd0
以上環境只要在設定好網路, 並把原本系統相關的掛載點(e.g. dev, proc, 等等) 給轉移到 aarch64 的根目錄底下. 再透過 ubuntu base 內建的 apt-get. 就可以客製化自己的 rootfs[3][4]. 只是需要注意圖形化桌面的套件選擇是否適用於 arm 平台下.
留言
張貼留言