2012年11月15日木曜日
2012年11月8日木曜日
2012年10月9日火曜日
ARM クロスコンパイラをビルドする
普通は Menter Graphics (旧CodeSourcery)からビルド済みのコンパイラをダウンロードする人が多いと思いますが。。
arm-linux-gnueabi-gcc をソースからビルドしてみました。物好きですな。
まずは各種ソースの tarball を入手します。
入手元を併記します。
(1) binutils-2.21.1.tar.bz2 - http://www.gnu.org/software/binutils/ から入手
(2) gcc-4.6.3.tar.bz2 - http://gcc.gnu.org/ から入手
(3) gmp-4.3.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(4) mpc-0.8.1.tar.gz - http://gcc.gnu.org/ から入手 (infrastructure の下)
(5) mpfr-2.4.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(6) linux-3.0.45.tar.bz2 - http://www.kernel.org/ から入手
(7) eglibc-2.13.tar.bz2 - http://www.eglibc.org/ から入手
(7) は公式サイトでtarball を配布してないようなので、
$ svn co svn://svn.eglibc.org/branches/eglibc-2_13 eglibc-2.13
のようにチェックアウトし、
$ tar jcf eglibc-2.13.tar.bz2 eglibc-2.13
のようにして、固めておきました。
ビルドの仕方は
eglibc/libc/EGLIBC.cross-building
に書いてあるので、それに沿ってやるだけなのですが、
ステップ数が多いので、シェルスクリプトにしたものを最後につけておきます。
最後のシェルスクリプトを例えば、 install_gcc.sh などのファイル名で保存し、上記7個の tarball と同じディレクトリに置く。
$ ./install_gcc.sh
で実行するだけ。
同じディレクトリの arm-built-from-src の中に一式出来上がる。
速いマシンだと1時間以内に完了します。
$ ./install_gcc.sh -T /path/to/install/directory
のようにインストール先を指定するオプションも用意してあること。
(補足1)
make 3.82 だとEGLIBC のビルドでコケるので、 make 3.81 を使う。
(「make 3.82 glibc」でググるとこのあたりのことが出てくる。)
(補足2)
eglibc のビルドに GNU awk が必要。
最近のUbuntuだとデフォルト mawk が入っていたりするので apt-get install gawk で入れる。
(補足3)
eglibc はあえて古めの 2.13 を使っている。
2.14 以降だと、rpc/rpc.h などのヘッダーがなくなっていて、あとあと面倒なので。
「glibc rpc/rpc.h」でググるとこのあたりの事情が出てくるが、ちゃんと追いかけてません。
(補足4)
gcc を解凍したディレクトリで
$ contrib/download_prerequisites
とすると、gmp, mpfr, mpc をダウンロードしてくれるが、
ここでは、最初にまとめてtarball を準備しておく方法をとった。
--- シェルスクリプトここから ---
arm-linux-gnueabi-gcc をソースからビルドしてみました。物好きですな。
まずは各種ソースの tarball を入手します。
入手元を併記します。
(1) binutils-2.21.1.tar.bz2 - http://www.gnu.org/software/binutils/ から入手
(2) gcc-4.6.3.tar.bz2 - http://gcc.gnu.org/ から入手
(3) gmp-4.3.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(4) mpc-0.8.1.tar.gz - http://gcc.gnu.org/ から入手 (infrastructure の下)
(5) mpfr-2.4.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(6) linux-3.0.45.tar.bz2 - http://www.kernel.org/ から入手
(7) eglibc-2.13.tar.bz2 - http://www.eglibc.org/ から入手
(7) は公式サイトでtarball を配布してないようなので、
$ svn co svn://svn.eglibc.org/branches/eglibc-2_13 eglibc-2.13
のようにチェックアウトし、
$ tar jcf eglibc-2.13.tar.bz2 eglibc-2.13
のようにして、固めておきました。
ビルドの仕方は
eglibc/libc/EGLIBC.cross-building
に書いてあるので、それに沿ってやるだけなのですが、
ステップ数が多いので、シェルスクリプトにしたものを最後につけておきます。
最後のシェルスクリプトを例えば、 install_gcc.sh などのファイル名で保存し、上記7個の tarball と同じディレクトリに置く。
$ ./install_gcc.sh
で実行するだけ。
同じディレクトリの arm-built-from-src の中に一式出来上がる。
速いマシンだと1時間以内に完了します。
$ ./install_gcc.sh -T /path/to/install/directory
のようにインストール先を指定するオプションも用意してあること。
(補足1)
make 3.82 だとEGLIBC のビルドでコケるので、 make 3.81 を使う。
(「make 3.82 glibc」でググるとこのあたりのことが出てくる。)
(補足2)
eglibc のビルドに GNU awk が必要。
最近のUbuntuだとデフォルト mawk が入っていたりするので apt-get install gawk で入れる。
(補足3)
eglibc はあえて古めの 2.13 を使っている。
2.14 以降だと、rpc/rpc.h などのヘッダーがなくなっていて、あとあと面倒なので。
「glibc rpc/rpc.h」でググるとこのあたりの事情が出てくるが、ちゃんと追いかけてません。
(補足4)
gcc を解凍したディレクトリで
$ contrib/download_prerequisites
とすると、gmp, mpfr, mpc をダウンロードしてくれるが、
ここでは、最初にまとめてtarball を準備しておく方法をとった。
--- シェルスクリプトここから ---
#!/bin/bash # version gmp=gmp-4.3.2 mpfr=mpfr-2.4.2 mpc=mpc-0.8.1 binutils=binutils-2.21.1 gcc=gcc-4.6.3 eglibc=eglibc-2.13 linux=linux-3.0.45 # constant variables tarballtop=$(pwd) worktop=$(pwd) tools=$worktop/arm-built-from-src target=arm-none-linux-gnueabi sysroot=$tools/$target/libc linux_arch=arm # # helper functions # msg () { echo ";" echo ";" echo ";;;;; $1 ;;;;;" echo ";" echo ";" } usage () { cat <&2 usage: install_gcc.sh [-t tarballtop] [-w worktop] [-T tools] [targets...] Valid targets are: binutils Build and install binutils gcc1 Build and install the first gcc linuxhdr Install Linux kernel headers eglibchdr Install EGLIBC headers gcc2 Build and install the second gcc eglibc Build and install eglibc gcc3 Build and install the third gcc all Do all of above in above order If no target is given, "install_gcc all" shall be run. EOF } optcheck () { if [ -z $2 ] || [ $(echo $2 | cut -c 1) != "/" ]; then echo "error: specify absolute pass for $1 option" exit 1 fi } unpack () { # search *.tar.gz, *.tar.bz2, *.tar.xz, *.tgz, *.tbz2 *.tar # in this order. # If found, the tarball shall be uncompressed. for suffix in tar.gz tar.bz2 tar.xz tgz tbz2 tar; do tarball=$tarballtop/$1.$suffix if [ -f $tarball ]; then case $suffix in tar.gz) taropt=-zxf ;; tar.bz2) taropt=-jxf ;; tar.xz) taropt=-Jxf ;; tgz) taropt=-zxf ;; tbz2) taropt=-jxf ;; tar) taropt=-xf ;; *) echo "error: something wrong. fix me." >&2 ; exit 1 ;; esac echo "uncompressing $tarball ..." tar $taropt $tarball return fi done echo "error: tarball not found. Abort." >&2 exit 1 } gcc_prerequisites () { # $1: relative or absolute path to gcc source directory # sanity check if [ -z $1 ]; then echo "error: gcc_prerequisites was called without args" >&2 exit 1 fi gccdir=$1 if [ ! -d $gccdir ]; then echo "error: directory \'$gccdir\' not found" exit 1 fi # cd $gccdir # ./contrib/download_prerequisites # Instead of doing above, do following: unpack $gmp unpack $mpfr unpack $mpc mv $gmp $mpfr $mpc $gccdir/ ln -s $gmp $gccdir/gmp ln -s $mpfr $gccdir/mpfr ln -s $mpc $gccdir/mpc } install_binutils () { srcdir=$binutils objdir=obj-binutils cd $worktop rm -rf $srcdir $objdir unpack $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --with-sysroot=$sysroot make make install cd $worktop rm -rf $srcdir $objdir } install_gcc1 () { srcdir=$gcc objdir=obj-gcc1 cd $worktop rm -rf $srcdir $objdir unpack $srcdir gcc_prerequisites $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --without-headers --with-newlib \ --disable-shared --disable-threads --disable-libssp \ --disable-libgomp --disable-libmudflap \ --disable-libquadmath \ --enable-languages=c PATH=$tools/bin:$PATH make PATH=$tools/bin:$PATH make install cd $worktop rm -rf $srcdir $objdir } install_linuxhdr () { srcdir=$linux cd $worktop rm -rf $srcdir unpack $srcdir cd $srcdir make headers_install \ ARCH=$linux_arch CROSS_COMPILE=$target- \ INSTALL_HDR_PATH=$sysroot/usr cd $worktop rm -rf $srcdir } install_eglibchdr () { srcdir=$eglibc objdir=obj-eglibc-headers cd $worktop rm -rf $srcdir $objdir unpack $srcdir mv $srcdir/ports $srcdir/libc mkdir -p $objdir cd $objdir BUILD_CC=gcc \ CC=$tools/bin/$target-gcc \ CXX=$tools/bin/$target-g++ \ AR=$tools/bin/$target-ar \ RANLIB=$tools/bin/$target-ranlib \ $worktop/$srcdir/libc/configure \ --prefix=/usr \ --with-headers=$sysroot/usr/include \ --host=$target \ --disable-profile --without-gd --without-cvs --enable-add-ons make install-headers install_root=$sysroot \ install-bootstrap-headers=yes make csu/subdir_lib mkdir -p $sysroot/usr/lib cp csu/crt1.o csu/crti.o csu/crtn.o $sysroot/usr/lib $tools/bin/$target-gcc -nostdlib -nostartfiles -shared -x c /dev/null \ -o $sysroot/usr/lib/libc.so cd $worktop rm -rf $srcdir $objdir } install_gcc2 () { srcdir=$gcc objdir=obj-gcc2 cd $worktop rm -rf $srcdir $objdir unpack $srcdir gcc_prerequisites $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --with-sysroot=$sysroot \ --disable-libssp --disable-libgomp --disable-libmudflap \ --disable-libquadmath \ --enable-languages=c PATH=$tools/bin:$PATH make PATH=$tools/bin:$PATH make install cd $worktop rm -rf $srcdir $objdir } install_eglibc () { srcdir=$eglibc objdir=obj-eglibc cd $worktop rm -rf $srcdir $objdir unpack $srcdir mv $srcdir/ports $srcdir/libc mkdir -p $objdir cd $objdir BUILD_CC=gcc \ CC=$tools/bin/$target-gcc \ CXX=$tools/bin/$target-g++ \ AR=$tools/bin/$target-ar \ RANLIB=$tools/bin/$target-ranlib \ $worktop/$srcdir/libc/configure \ --prefix=/usr \ --with-headers=$sysroot/usr/include \ --host=$target \ --disable-profile --without-gd --without-cvs --enable-add-ons PATH=$tools/bin:$PATH make PATH=$tools/bin:$PATH make install install_root=$sysroot cd $worktop rm -rf $srcdir $objdir } install_gcc3 () { srcdir=$gcc objdir=obj-gcc3 cd $worktop rm -rf $srcdir $objdir unpack $srcdir gcc_prerequisites $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --with-sysroot=$sysroot \ --enable-__cxa_atexit \ --disable-libssp --disable-libgomp --disable-libmudflap \ --enable-languages=c,c++ make make install cd $worktop rm -rf $srcdir $objdir } # stop immediately if an error occurres set -e # process options while [ $# -gt 0 ] ; do case "$1" in -t) optcheck $1 $2; shift; tarballtop=$1 ;; -w) optcheck $1 $2; shift; worktop=$1 ;; -T) optcheck $1 $2; shift; tools=$1; sysroot=$tools/$target/libc ;; -*) (echo error: $1: unknown option ; echo ) >&2 ; usage ; exit 1 ;; *) break;; esac shift done if [ $# -eq 0 ] ; then set all fi # process targets while [ $# -gt 0 ] ; do case "$1" in binutils) msg binutils ; install_binutils ;; gcc1) msg gcc1 ; install_gcc1 ;; linuxhdr) msg linuxhdr ; install_linuxhdr ;; eglibchdr) msg eglibchdr ; install_eglibchdr ;; gcc2) msg gcc2 ; install_gcc2 ;; eglibc) msg eglibc ; install_eglibc ;; gcc3) msg gcc3 ; install_gcc3 ;; all) set binutils gcc1 linuxhdr eglibchdr gcc2 eglibc gcc3; continue ;; *) (echo error: $1: unknown target ; echo ) >&2 ; usage ; exit 1;; esac shift done
2012年6月9日土曜日
2012年6月8日金曜日
Gas の .align ディレクティブ
GNU Assembler の .align ディレクティブについて。
例えば、4バイトアラインするときに
.align 2 と書いている人と .align 4 と書いてる人がいて、どっちが正しいんだ?と思ったので調べてみた。
The GNU Assembler のドキュメントを参照すると、、、
The way the required alignment is specified varies from system to system.
For the a29k, hppa, m68k, m88k, w65, sparc, Xtensa, and Renesas / SuperH SH, and i386 using ELF format, the first expression is the alignment request in bytes.
For example .align 8 advances the location counter until it is a multiple of 8.
If the location counter is already a multiple of 8, no change is needed.
For other systems, including the i386 using a.out format, and the arm and strongarm, it is the number of low-order zero bits the location counter must have after advancement.
For example .align 3 advances the location counter until it a multiple of 8.
If the location counter is already a multiple of 8, no change is needed.
なんだそうだ。
例えば i386 (ELF) は
.align 2 → 2バイトアライン
.align 4 → 4バイトアライン
.align 8 → 8バイトアライン
となるのに対し、
ARMは
.align 1 → 2バイトアライン
.align 2 → 4バイトアライン
.align 3 → 8バイトアライン
となるらしい。
こりゃ気をつけな間違えるな~。
というわけで、
.balign を使えば、システムに依存せずに、
.balign 2 → 2バイトアライン
.balign 4 → 4バイトアライン
.balign 8 → 8バイトアライン
となるみたいだ。
例えば、4バイトアラインするときに
.align 2 と書いている人と .align 4 と書いてる人がいて、どっちが正しいんだ?と思ったので調べてみた。
The GNU Assembler のドキュメントを参照すると、、、
The way the required alignment is specified varies from system to system.
For the a29k, hppa, m68k, m88k, w65, sparc, Xtensa, and Renesas / SuperH SH, and i386 using ELF format, the first expression is the alignment request in bytes.
For example .align 8 advances the location counter until it is a multiple of 8.
If the location counter is already a multiple of 8, no change is needed.
For other systems, including the i386 using a.out format, and the arm and strongarm, it is the number of low-order zero bits the location counter must have after advancement.
For example .align 3 advances the location counter until it a multiple of 8.
If the location counter is already a multiple of 8, no change is needed.
なんだそうだ。
例えば i386 (ELF) は
.align 2 → 2バイトアライン
.align 4 → 4バイトアライン
.align 8 → 8バイトアライン
となるのに対し、
ARMは
.align 1 → 2バイトアライン
.align 2 → 4バイトアライン
.align 3 → 8バイトアライン
となるらしい。
こりゃ気をつけな間違えるな~。
というわけで、
.balign を使えば、システムに依存せずに、
.balign 2 → 2バイトアライン
.balign 4 → 4バイトアライン
.balign 8 → 8バイトアライン
となるみたいだ。
2012年4月6日金曜日
2012年4月5日木曜日
2012年2月23日木曜日
UNK/SBZP
ARM ARM (ARM Architecture Reference Manual) で UNK/SBZP という用語が頻発していて、何の略だろうと思ったら、
UKNOWN on reads, Should-Be-Zero-or-Preserved on writes.
のことらしい。
レジスタのreserved ビットに対する、ソフトでの扱い方を述べているようです。
reserved ビットは、0読み出し、書き込み無視のようにハードではたぶん実装しているはずだが、ソフトはそれを期待するなということだと思います。
UKNOWN on reads, Should-Be-Zero-or-Preserved on writes.
のことらしい。
レジスタのreserved ビットに対する、ソフトでの扱い方を述べているようです。
reserved ビットは、0読み出し、書き込み無視のようにハードではたぶん実装しているはずだが、ソフトはそれを期待するなということだと思います。
2012年2月8日水曜日
2012年2月2日木曜日
ARM Linux カーネルエントリー
組み込みLinux勉強中につき、メモ。
ARMのLinuxカーネルのエントリは arch/arm/kernel/head.S の ENTRY(stext)から始まる。
ブートローダーはメモリのどっかにカーネルイメージを置いてあげて、ENTRY(stext)の「物理アドレス」へジャンプする。「論理アドレス」ではない。
つまりカーネルの最初のあたりはPCは仮想アドレスを指しておらず、物理アドレスを指している。
This code is mostly position independent というコメントにあるように、基本的にposition independent なコードになっていて、必要な部分は仮想アドレス→物理アドレスに変換して動いてくれるようになっている。
ENTRY(stext) はカーネルイメージの先頭からある程度のオフセット(普通は0x8000)をつけたところから始まっている。
オフセット量を確認するにはカーネルのelf を逆アセしてもいいし、リンカースクリプトを見てもよい。
リンカースクリプトは
arch/arm/kernel/vmlinux.lds.S
をプリプロセッサに通して作られる
arch/arm/kernel/vmlinux.lds
だが、見てみると
例えば、
みたいになっていれば、 オフセットは0x8000。
なので、ブートローダーはカーネルを置いた位置の先頭から + 0x8000のオフセット位置にジャンプすればよいことになる。
Kernelにjumpする前にブートローダーは
r0 = 0
r1 = machine nr
r2 = atags pointer
を設定しておく。
machine nr はmachineごとの固有の番号で、arch/arm/tools/mach-types に表がある。
atags pointerはよくわかりません。とりあえず0を入れておく。
ARMのLinuxカーネルのエントリは arch/arm/kernel/head.S の ENTRY(stext)から始まる。
ブートローダーはメモリのどっかにカーネルイメージを置いてあげて、ENTRY(stext)の「物理アドレス」へジャンプする。「論理アドレス」ではない。
つまりカーネルの最初のあたりはPCは仮想アドレスを指しておらず、物理アドレスを指している。
This code is mostly position independent というコメントにあるように、基本的にposition independent なコードになっていて、必要な部分は仮想アドレス→物理アドレスに変換して動いてくれるようになっている。
ENTRY(stext) はカーネルイメージの先頭からある程度のオフセット(普通は0x8000)をつけたところから始まっている。
オフセット量を確認するにはカーネルのelf を逆アセしてもいいし、リンカースクリプトを見てもよい。
リンカースクリプトは
arch/arm/kernel/vmlinux.lds.S
をプリプロセッサに通して作られる
arch/arm/kernel/vmlinux.lds
だが、見てみると
例えば、
SECTIONS
{
. = 0xC0000000 + 0x00008000;
.text.head : {
_stext = .;
_sinittext = .;
*(.text.head)
}
みたいになっていれば、 オフセットは0x8000。
なので、ブートローダーはカーネルを置いた位置の先頭から + 0x8000のオフセット位置にジャンプすればよいことになる。
Kernelにjumpする前にブートローダーは
r0 = 0
r1 = machine nr
r2 = atags pointer
を設定しておく。
machine nr はmachineごとの固有の番号で、arch/arm/tools/mach-types に表がある。
atags pointerはよくわかりません。とりあえず0を入れておく。
登録:
投稿 (Atom)