Armadilloフォーラム

ATDE9でクロスコンパイル

yamada_masa

2024年7月6日 1時03分

Armdilllo-840で作成したC言語プログラムをX2で動作させるためクロスコンパイルを試みています。

まず、シンプルなhellow woldプログラムでATDE9でクロスコンパイルを試してみましたが、Armadillo-X2で実行できませんでした。
コンテナ開発が推奨されていることは承知していますがクロスコンパイルすることはできないでしょうか。

●ATDE9でのクロスコンパイルと実行結果
arm-linux-gnueabihf-gcc 、aarch64-linux-gnu-gcc でクロスコンパイル
aarch64-linux-gnu-gcc でコンパイルしたバイナリが動作している。
arm64向けにビルドされているおりATDE9上では動作しない認識でしたが誤っていますでしょうか。

atmark@atde9:/mnt/hgfs/shared_atde9/hello$ arm-linux-gnueabihf-gcc -o eabihf.out hello.c 
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ls
eabihf.out  hello.c
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ aarch64-linux-gnu-gcc -o aarch64.out hello.c 
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ls
aarch64.out  eabihf.out  hello.c
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ./eabihf.out 
arm-binfmt-P: Could not open '/lib/ld-linux-armhf.so.3': No such file or directory
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ./aarch64.out 
hellow world x2

●Armdillo-X2での実行結果
not found とされる原因をご教授いただけると助かります。

armadillo:~/hello$ ls -al
total 28
drwxr-sr-x    2 atmark   atmark         100 Jul  6 00:29 .
drwxr-sr-x    1 atmark   atmark         120 Jul  6 00:29 ..
-rwxr-xr-x    1 atmark   atmark        9416 Jul  6 00:26 aarch64.out
-rwxr-xr-x    1 atmark   atmark        8264 Jul  6 00:26 eabihf.out
-rwxr-xr-x    1 atmark   atmark          66 Jul  6 00:26 hello.c
armadillo:~/hello$ ./eabihf.out
-ash: ./eabihf.out: not found
armadillo:~/hello$ ./aarch64.out
-ash: ./aarch64.out: not found
armadillo:~/hello$

●hellow woldプログラム

#include<stdio.h>
void main()
{
        printf("hellow world x2\n");
}
コメント

koga

2024年7月6日 6時22分

アットマークテクノの古賀(休日モード)です。

yamada_masaさん:
>Armdilllo-840で作成したC言語プログラムをX2で動作させるためクロスコンパイルを試みています。
>
>まず、シンプルなhellow woldプログラムでATDE9でクロスコンパイルを試してみましたが、Armadillo-X2で実行できませんでした。
>コンテナ開発が推奨されていることは承知していますがクロスコンパイルすることはできないでしょうか。

可能です。ただし、ATDE9 (: Debian) 上で普通にクロスコンパイルすると、X2 の OS である Armadillo Base OS (ABOS) とは標準 C ライブラリが違うため、クロスコンパイルしてできたバイナリが動作しないのです。
Debian の標準 C ライブラリは、一般的な Linux ディストリビューションで使われている glibc ですが、ABOS では musl libc であり、glibc の共有ライブラリは配置されていません。
 https://ja.wikipedia.org/wiki/Musl
そのため、glibc をリンクライブラリとしてビルドされた実行ファイルは Armadillo Base OS で動作しない、というわけです。

ATDE9 で、ABOS 上で直接動作する実行ファイルをビルドする方法については、このフォーラムで過去に何度か質問を頂いています。以下の質問スレッドのコメントをご覧になってみてください:

 C言語での開発について
 https://armadillo.atmark-techno.com/index.php/forum/armadillo/16379#com…

 ライブラリが見つからないエラー
 https://armadillo.atmark-techno.com/forum/armadillo/14009#comment-12363

 クロスコンパイルした実行ファイルをArmadilloで実行できない
 https://armadillo.atmark-techno.com/forum/armadillo/15163#comment-13067

ということで、以下の質問については、「実行ファイルが起動時リンクする glibc の共有ライブラリが、ABOS に存在しないから」というのが回答です:

>●Armdillo-X2での実行結果
>not found とされる原因をご教授いただけると助かります。

armadillo:~/hello$ ls -al
total 28
drwxr-sr-x    2 atmark   atmark         100 Jul  6 00:29 .
drwxr-sr-x    1 atmark   atmark         120 Jul  6 00:29 ..
-rwxr-xr-x    1 atmark   atmark        9416 Jul  6 00:26 aarch64.out
-rwxr-xr-x    1 atmark   atmark        8264 Jul  6 00:26 eabihf.out
-rwxr-xr-x    1 atmark   atmark          66 Jul  6 00:26 hello.c
armadillo:~/hello$ ./eabihf.out
-ash: ./eabihf.out: not found
armadillo:~/hello$ ./aarch64.out
-ash: ./aarch64.out: not found
armadillo:~/hello$

次に、aarch64-linux-gnu-gcc でクロスコンパイルした実行ファイルが ATDE9 で動作する件ですが、これは、「aarch64 の QEMU ユーザーモードエミュレーションで実行されるから」というのが回答です。
 
>●ATDE9でのクロスコンパイルと実行結果
>arm-linux-gnueabihf-gcc 、aarch64-linux-gnu-gcc でクロスコンパイル
>aarch64-linux-gnu-gcc でコンパイルしたバイナリが動作している。
>arm64向けにビルドされているおりATDE9上では動作しない認識でしたが誤っていますでしょうか。

以下のようにすると、ATDE9 上で動作しなくなります:

$ sudo /usr/libexec/qemu-binfmt/aarch64-binfmt-P /usr/libexec/qemu-binfmt/aarch64-binfmt-P.bak
$ sudo reboot

つまり、/usr/libexec/qemu-binfmt/aarch64-binfmt-P が存在しない状態で起動した ATDE9 では、aarch64-linux-gnu-gcc でクロスビルドしたバイナリは、(期待通り)動作しません。
/usr/libexec/qemu-binfmt/aarch64-binfmt-P が存在する状態で起動した場合は、このファイルにより、aarch64 用のバイナリが aarch64 の QEMU ユーザーモードエミュレーションで実行されるので、動作するのです。

atmark@atde9:/mnt/hgfs/shared_atde9/hello$ arm-linux-gnueabihf-gcc -o eabihf.out hello.c 
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ls
eabihf.out  hello.c
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ aarch64-linux-gnu-gcc -o aarch64.out hello.c 
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ls
aarch64.out  eabihf.out  hello.c
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ./eabihf.out 
arm-binfmt-P: Could not open '/lib/ld-linux-armhf.so.3': No such file or directory
atmark@atde9:/mnt/hgfs/shared_atde9/hello$ ./aarch64.out 
hellow world x2

>
>
>●hellow woldプログラム

#include<stdio.h>
void main()
{
        printf("hellow world x2\n");
}

ここで、/usr/libexec/qemu-binfmt/aarch64-binfmt-P を ls -l で見てみると、このファイルが /usr/bin/qemu-aarch64-static へのシンボリックリンクであることが分かります。/usr/bin/qemu-aarch64-static、つまり aarch64 の QEMU ユーザーモードエミュレータが aarch64 用のバイナリを実行した時に割り当てられるのは、Linux カーネルの binfmt_misc という機能によるものです:
 https://en.wikipedia.org/wiki/Binfmt_misc
 https://qiita.com/lnznt/items/c729d80d0800a8f78298

上記の hellow world プログラムで、printf() の後に sleep(10) などでスリープするようにしてみてください。
それを aarch64-linux-gnu-gcc でクロスビルドしてできたバイナリを、バックグラウンドで実行して ps T でプロセス表示すると、バイナリが /usr/libexec/qemu-binfmt/aarch64-binfmt-P (上述した通り、実体は /usr/bin/qemu-aarch64-static)によって実行されているのが分かると思います。

この QEMU ユーザーモードエミュレーションについては、以下のページも参考になるかと思います:

 Debian の qemu-user-binfmt パッケージ
 https://packages.debian.org/bullseye/qemu-user-binfmt

 QemuUserEmulation
 https://wiki.debian.org/QemuUserEmulation

 QEMUのもうひとつの使い方: ユーザーモードエミュレーションとbinfmtとchrootの組み合わせ
 http://blog.kmckk.com/archives/2342452.html

以上、参考になりましたら幸いです。

yamada_masa

2024年7月6日 16時21分

yamada_masaです。
古賀さん

休日にありがとうございます。
ATDE9上でコンパイルしたバイナリをArmadillo-x2上で実行することができました。

提示いただいた参考URLで下記のコメントがありましたので、ATDE9上にalpineのコンテナを作成しコンパイルしました。
https://armadillo.atmark-techno.com/forum/armadillo/15163#comment-13067
>ATDE で podman を使って docker.io/arm64v8/alpine のコンテナで(クロスではなくエミュレーション)のビルドもできます

Dockerfileや実行手順は下記となります。

●Dockerfile

#--------コンテナイメージA作成------------
#使用するコンテナイメージを記載する(A6Eの場合はarch=armv7と指定する)
#実際に使用するArmadillo本体で実行する場合は${arch}は省略も可能
#ここではコンテナイメージAを"tmp_image"とする
ARG arch=arm64v8
#FROM docker.io/${arch}/debian:bullseye As tmp_image
FROM docker.io/${arch}/alpine:3.19 As tmp_image
 
#コンテナ内にファイルをコピーする
#ここではDockerfileと同階層にある”hello.c”をコンテナ内の”/root/”にコピー
COPY hello.c /root/
 
#コンテナ内で実行するコマンドを記載する
#ここではコンパイルツールをインストールし、コンパイルまで行う
#RUN apt update && apt upgrade -y
RUN apk update && apk upgrade
#RUN apt install build-essential -y
RUN apk add alpine-sdk
RUN cd && gcc -o hello.exe hello.c

●コンテナイメージのビルドとコンテナの起動
コンテナ起動時にホスト側にhello.exeを取り出すために-vオプションでホスト側のディレクトリ/home/atmark/work/disk01をコンテナの/mntにマウントする。

atmark@atde9:~/work/dockerfile_alpinegcc$ pwd
/home/atmark/work/dockerfile_alpinegcc
atmark@atde9:~/work/dockerfile_alpinegcc$ ls
Dockerfile  hello.c
atmark@atde9:~/work/dockerfile_alpinegcc$ podman build -t localhost/alpinegcc:1.0.0 .
atmark@atde9:~/work/dockerfile_alpinegcc$ podman run  -it -v /home/atmark/work/disk01:/mnt localhost/alpinegcc:1.0.0

●Armadillo-x2実行結果
FTPで実行ファイルを実機に転送し実行。

armadillo:~$ ./hello.exe
hellow world x2