ぷるぷるの雑記

低レイヤーがんばるぞいなブログ. 記事のご利用は自己責任で.

ARM用のNewlibをビルドする方法

Armマイコン(Cortex-M0)でNewlibを使いたいので自分でビルドしてみました.

たいていツールチェーンにバイナリとして付属してるけどね.

実行環境

項目 説明
OS Ubuntu 20.04 LTS
コンパイラ・バイナリツール (Toolchain) Arm GNU Toolchain 12.3Rel1
(x86_64 Linux hosted cross toolchains AArch32 bare-metal target (arm-none-eabi))

ツールチェーンの取得

Linuxで動くArch32用のクロスコンパイラを入手します. Arm公式から圧縮ファイルを入手し解凍しましょう.

developer.arm.com


ディレクトリを短い名前にリネームし、ユーザーフォルダ直下に置きます.

#クロスパイルツールチェーンをリネームしてユーザーフォルダ直下に配置

 ~/ ---  /arm-gcc   


このツールチェーン内のコマンドが置かれたディレクトリへのパスを通すため.bashrcを編集します. 必要であれば.bashrcを読み込みなおします.

# ~/.bashrc

#追記
export PATH=$PATH:path_to_arm_gnu_toolchain/bin
$ source ~/.bashrc

arm-none-eabi用のビルドの流れ

まずはNewlibのソースコードを入手します. 面倒なのでミラーからサクッと手に入れました. 公式から入手したい場合ははFTPかhttpを使えと書いてありました.

# ミラーからNewlibのソースを入手
$ git clone https://github.com/bminor/newlib.git

公式 https://sourceware.org/newlib/download.html

ミラー https://github.com/bminor/newlib.git


解凍しユーザー直下に置きましょう. ついでにout-of-sourceビルド用にbuildディレクトリも作っておきましょう.

# out-of-sourceビルドのための配置

 ~/ ---  /arm-gcc   
      |
      |-- /new-lib
      |
      |__ /build


buildフォルダに入りconfigureスクリプトを叩きます. 以下のオプションを指定すればとりあえずビルド出来ました.

#buildディレクトリに入る
$ cd ~/build

#configure
$ ../newlib/newlib/configure --target=arm-none-eabi --enable-newlib-io-long-long --enable-newlib-register-fini --enable-newlib-retargetable-locking --disable-newlib-supplied-syscalls CC=arm-none-eabi-gcc --host=arm-none-eabi --build=i686-pc-linux-gnu

#make
$ make

ビルドが無事終了するとbuildディレクトリ直下に libc.a、libg.a、libm.aが生成されます. また、ヘッダファイルは newlib/libc/include に入っています. math.hもこのフォルダに入っています.

また、バイナリのサイズはそれぞれ以下でした.

アーカイブ サイズ
libc.a 4,680kB
libg.a 4.680kB
libm.a 1,718kB

arm-none-eabi用のビルドは出来ましたが、 目的のCortex-M0では動きませんでした (実行可能ファイルを作ることは出来たが、正常に動作しませんでした).

動かなかった原因

正常に動くNewlibと何が違うのかを探るため、STM32CubeIDEに付属するツールチェーンに同梱されているNewlibのバイナリと、自分でビルドしたNewlibのバイナリをreadelfして差分を取りました. なお、ツールチェーンには各アーキテクチャごとにバイナリが分かれているため、一度-Wl,--verboseオプションをつけてビルドすることでCortex-M0用にリンクされるバイナリを同定しました. WinMergeで両者のreadelfの結果を比較すると、以下の決定的な違いが見つかりました.

正常なバイナリ(左)と正常でないバイナリ(右). アーキテクチャが違う

つまり、arm-none-eabiの中でもアーキテクチャが分かれているので、Cortex-M0用のアーキテクチャを明示的に指定しないといけないということですね. 前述のNewlibビルドにおいてarm-none-eabi以外にそれらしきものを指定した覚えはないので、デフォルトではARM v6Kというアーキテクチャ用にビルドされるのでしょう.

Cortex-M0用にビルド

ここが躓きポイントだったのですが、アーキテクチャの指定は configure時ではなく、make時に行います . これはアーキテクチャの指定の方法が汎用的なものではなくマシン依存オプションというcpuごとに異なるものだからだと推測されます. 前述のconfigureに加え、make時には以下のコマンドを打つことでCortex-M0用のバイナリをビルドすることが出来ました.

$ make CFLAGS="-mcpu=cortex-m0"

実際にCortex-M0で試した記事がこちらになります.

prupru-prune.hatenablog.com

まとめ

とりあえず以下のおまじないでCortex-M0用に動くNewlibがビルド出来ました.

# configure
$ configure --target=arm-none-eabi --enable-newlib-io-long-long --enable-newlib-register-fini --enable-newlib-retargetable-locking --disable-newlib-supplied-syscalls CC=arm-none-eabi-gcc --host=arm-none-eabi --build=i686-pc-linux-gnu

$ make CFLAGS="-mcpu=cortex-m0"

参考

www.asahi-net.or.jp

stackoverflow.com

msyksphinz.hatenablog.com

uchan.hateblo.jp

releases.llvm.org

www.gnu.org