概要
FreeBSDハンドブック 10.2. Linux® バイナリ互換機能の設定 を参照してLinuxバイナリ互換機能を有効化した上で、適当なLinuxバイナリを用意して動かしてみた。
目次
- Linuxバイナリ互換機能の準備
- Linuxバイナリの用意
- Linuxバイナリを実行する
- まとめ
Linuxバイナリ互換機能の準備
FreeBSDにはLinux用の実行バイナリに手を加えずにそのまま実行するLinuxバイナリ互換機能(Linuxulatorと呼ばれる)がある。ハンドブックを参照して、カーネルモジュールを読み込んでLinuxバイナリ実行用のライブラリをインストールする。
sudo kldload linux
sudo kldload linux64
sudo pkg install emulators/linux_base-c7
/etc/rc.conf に以下を記載しておけば再起動後もLinuxバイナリ互換機能が有効化される。
linux_enable="YES"
/etc/fstab に以下を記載し、マウントする。今回動かすプログラムでは利用しなくても大丈夫だが、/proc, /sys, /dev/shmを使うようなプログラムでも動作させることができるらしい。
linprocfs /compat/linux/proc linprocfs rw 0 0
linsysfs /compat/linux/sys linsysfs rw 0 0
tmpfs /compat/linux/dev/shm tmpfs rw,mode=1777 0 0
sudo mount /compat/linux/proc
sudo mount /compat/linux/sys
sudo mount /compat/linux/dev/shm
Linuxバイナリの用意
GoでLinux用のバイナリを用意する。環境変数の設定だけで簡単にクロスコンパイルできるので便利。
sudo pkg install go
main.go を用意する。
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
今回はFreeBSD/Linux用に32/64ビットのバイナリをそれぞれクロスコンパイルし、合計4種類のバイナリを作った。
GOOS=freebsd GOARCH=amd64 go build -o fbsd64 main.go
GOOS=freebsd GOARCH=386 go build -o fbsd32 main.go
GOOS=linux GOARCH=amd64 go build -o linux64 main.go
GOOS=linux GOARCH=386 go build -o linux32 main.go
用意した4つのバイナリ情報をfileコマンドで確認してみる。Linux用もFreeBSD用もどちらもELF。FreeBSD用は version 1 (FreeBSD)、Linux用は version 1 (SYSV) となっている。
$ file fbsd64
fbsd64: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), statically linked, Go BuildID=xykiihtRL-scj4GSy8TO/FjVgZBRW9niD_shI5R1O/FkbAyAK_QYuQ3TEUFh_l/9LvbDPm51xbB_lBWHVKZ, not stripped
$ file fbsd32
fbsd32: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), statically linked, Go BuildID=fOhR-AY5kFev4BcpCYeg/fcgG3V0uH6RYUjBnIIWb/mAmAODzKjUcnHQZtCy1T/_wK_cmGC3cE9lzrssCvn, not stripped
$ file linux64
linux64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=3YU53_PCF9Kf6dJNp_J3/ZVf_vs-V5DxzzYXii6Ja/BkGJrDeLhJvAZP7roVvj/rUTq6c3E2mZkul9tVqpL, not stripped
$ file linux32
linux32: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, Go BuildID=iyjpm6fSu-HqkhaKP-iH/uvELtFgAVuTgNbCYJqqu/KXC8dfX2tvgxegYR5ruF/shi8YgOLtzddgmysbwO0, not stripped
Linuxバイナリを実行する
FreeBSD用のバイナリは64ビット版、32ビット版ともに実行できるが、Linux用のバイナリはそのままでは実行に失敗する。
$ ./fbsd64
Hello, world!
$ ./fbsd32
Hello, world!
$ ./linux64
ELF binary type "0" not known.
bash: ./linux64: cannot execute binary file: Exec format error
$ ./linux32
ELF binary type "0" not known.
bash: ./linux32: cannot execute binary file: Exec format error
Linux用にクロスコンパイルした実行バイナリを、brandelfコマンドでバイナリタイプにLinuxを指定すると動くようになる。
brandelf -t Linux linux64
brandelf -t Linux linux32
$ ./linux64
Hello, world!
$ ./linux32
Hello, world!
fileコマンドでLinuxバイナリを見てみると、ELFバイナリであることに変わりはない。先程は version 1 (SYSV) となっていたが、brandelf実行後は version 1 (GNU/Linux) となっている。
$ file linux64
linux64: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, Go BuildID=3YU53_PCF9Kf6dJNp_J3/ZVf_vs-V5DxzzYXii6Ja/BkGJrDeLhJvAZP7roVvj/rUTq6c3E2mZkul9tVqpL, not stripped
$ file linux32
linux32: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, Go BuildID=iyjpm6fSu-HqkhaKP-iH/uvELtFgAVuTgNbCYJqqu/KXC8dfX2tvgxegYR5ruF/shi8YgOLtzddgmysbwO0, not stripped
まとめ
FreeBSDのLinuxバイナリ互換機能を利用して、Linux用のバイナリを実行した。用意したLinux用バイナリはそのままでは実行できず、brandelfコマンドでバイナリタイプをLinux指定することで実行できるようになった。