Hatena::ブログ(Diary)

七誌の開発日記(旧) このページをアンテナに追加 RSSフィード

新ブログ Twitter OneDrive Wiki

2011-05-13

[][][][][][]クロスコンパイラ

第7回 IT初心者勉強会 アセンブラ大会に参加しました。色々なCPUアセンブリ言語を比較していて、とても楽しかったです。

そこで使われていたクロスコンパイラWindows用にビルドしたので配布します。MSYS用です。MSYSはgccを動かすのに特化しており、Cygwinより手軽です。インストール方法はこちらを参照してください。

ダウンロード

インストール

/usr/localに展開するだけで完了です。以下にPowerPCインストール例を示します。他のアーキテクチャインストール方法も同様です。

$ mkdir /usr/local
$ tar xvJf gcc-4.6.1-msys-cross-powerpc-elf.tar.xz -C /usr/local

※ 既に/usr/localが存在する場合、mkdirは不要です。

使い方

配布バイナリにはlibcが含まれていないため、実行ファイルを出力する際には -nostdlib オプションを付けてください。出力ファイルを指定しないと a.out というファイル名で出力されます。

以下にPowerPCでの使用例を示します。他のアーキテクチャも同様です。

$ powerpc-elf-gcc -nostdlib hello.c
$ file a.out
a.out: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), statically linked, not stripped

詳しい使い方は全資料に含まれるMakefileを参照してください。

ビルド手順

バイナリを使うだけなら必要ないのですが、参考までに配布物のビルド手順を書いておきます。

IT初心者勉強会環境構築方法とは若干異なります。

  • 勉強会のサンプルではlibcを使っていないため、newlibは省略しています。
  • gccのバージョンを4.6.1に上げました。
依存ライブラリ

まずgcc-4.6.1の依存ライブラリビルドします。

  • gmp-5.0.2.tar.bz2
$ tar xvjf gmp-5.0.2.tar.bz2
$ cd gmp-5.0.2
$ ./configure
$ make
$ make install
  • mpfr-3.0.1.tar.xz
$ tar xvJf mpfr-3.0.1.tar.xz
$ cd mpfr-3.0.1
$ CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure
$ make
$ make install
$ tar xvzf mpc-0.9.tar.gz
$ cd mpc-0.9
$ CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure
$ make
$ make install
binutils/gcc

binutilsgccは各アーキテクチャでソースを共用するため、ソースの外でビルドします。このようにすれば、ソースの展開は1回で済みます。

$ tar xvjf binutils-2.21.1.tar.bz2
$ tar xvjf gcc-core-4.6.1.tar.bz2

以下にPowerPC用クロスコンパイラビルド手順を示します。

$ mkdir powerpc-elf
$ cd powerpc-elf
$ mkdir binutils
$ cd binutils
$ ../../binutils-2.21.1/configure --target=powerpc-elf
$ make
$ make install
$ cd ..
$ mkdir gcc
$ cd gcc
$ CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ../../gcc-4.6.1/configure --target=powerpc-elf
$ CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib make all-target-libgcc
$ make install-gcc
$ make install-target-libgcc

他のアーキテクチャはtargetを変えるだけで手順は同様です。ただしMSYSではMIPSのlibgccがメモリ不足でビルドできなかったため、配布バイナリにはNetBSDビルドしたものを入れています。

アーカイブ

配布バイナリの作成では、make installを一時ディレクトリに対して行いアーカイブしています。

$ cd powerpc-elf/binutils
$ make prefix=/opt install
$ cd ../gcc
$ make prefix=/opt install-gcc
$ make prefix=/opt install-target-libgcc
$ cd /opt
$ find . -name "*.exe" | xargs strip
$ tar cvJf gcc-4.6.1-msys-cross-powerpc-elf.tar.xz *

このようにして作成したバイナリを配布しています。

2010-12-16

[][][][][]コンパイラ移植

Excelで動くコンパイラid:n7shi:20100519)をOpenOffice.org Calcに移植しました。マクロを使用しているため、セキュリティを中にしてご利用ください。

以下のアーキテクチャバイナリを出力できます。

2010-06-22

[][][]クロス開発

昨日と同じネタですが、今日はWindows CE系が対象です。使用しているファイルはid:n7shi:20100519のものです。

f:id:n7shi:20100622125727p:image:medium:right

f:id:n7shi:20100622122904p:image:medium:right

【画像左】Windows Mobileエミュレータ(ARM)の共有フォルダ機能でホストのフォルダをマウントして、ExcelからクロスビルドしたEXEを実行しています。

【画像右】古いSDKに付いてくるPocket PCエミュレータx86なので、デスクトップ用のWindowsとの違いを比較するのにはちょうど良いです。

Windows Phone 7ではネイティブバイナリや野良アプリが禁止されるので、こういう遊びができなくなってしまいます。

2010-03-05

[][][]コンパイラWindows Mobile対応)

id:n7shi:20100303で公開したExcel上で動くコンパイラが割と好評だったようなので、調子に乗ってWindows Mobile用のARMバイナリも出力できるようにしてみました。

x86を直訳したような冗長なARMのコードを吐きます。残念ながらPocket Excelではマクロが動かないため使えません。

2009-12-13

[][][]MIZU GAME for NetWalker

id:fslashtさんのMIZU GAMEをC++に移植して、Interix上のクロス開発環境(id:n7shi:20091212)でNetWalker用にビルドしました。バイナリ(NetWalker/Windows)とソース(gcc/VC)を置いておきます。

実機がないため原作者のid:fslashtさんに動作確認をお願いしたところ、無事に動作したとのことです。

MIZU GAME for NetWalker動かしてみました!バッチリ動いてますよ〜。たださすがに性能不足でFPSは半分くらい・BGMが途切れがちです。とはいえ動作自体は完全移植ですね。マップエディターも動くとは。SDLUtils.cpp/hでSDL.NETとの差異を吸収ですか

【追記】id:fslasht:20091213スクリーンショット付きでご紹介いただきました。

動機

id:fslashtさんのARM Forum 2009のレポート(id:fslasht:20091110)を読んで、今後ARM搭載デバイスが色々登場すれば面白そうだと思いました。スマートフォン以外でもARM搭載の非WindowsのNetBookが出てきそうです。この手のマシンとして先陣を切ったNetWalkerをリファレンスマシンに見立てて、開発手法を確立してみたくなりました。

NetWalkerはUbuntuのためクロス開発もUbuntu上で行えば簡単ですが、Ubuntuを常用していなければ敷居が高いです。Windows上でクロス開発するため、開発用パッケージを集めて(id:n7shi:20091210)、クロスコンパイラを用意(id:n7shi:20091212)しました。

せっかく環境を構築しても、実際にビルドしないと面白くありません。そこできっかけを頂いたid:fslashtさんの作品を移植してみました。将来的にはC#のネイティブコンパイラを作りたいとも考えているため、一度は手作業でのネイティブ化を経験しておこうとも思いました。そのためNetWalkerでmonoを動かせば済むという突っ込みはなしですw

常に動作確認

当初はC#のクラスをひとつずつC++/CLIに書き換えて、常に動作確認をしながら移植しようと考えていました。C#とC++/CLIは基本的に同じILを別の表記にしたものなので、機械的に書き換えられます。

常に動作確認する方針の重要性についてはid:aoisomeさんの素晴らしい記事があります。

移植手順

少しずつ書き換える方針により、以下のステップを踏みました。

  1. 逆コンパイル
  2. Managed C++
  3. SDL.NETの軽量化
  4. SDL.NETの変換
  5. SDL.NETの取り外し
  6. ネイティブ化
  7. バグ修正

ステップが多いのは、MIZU GAME本体だけでなくSDL.NETもどうにかしないといけなかったためです。

1. 逆コンパイル

C#からC++/CLIへの書き換えに着手したところ、クラス間の循環参照が多いため、ある程度一気に移植しなければ動作確認できないことに気付きました。一気に移植してから問題箇所を特定するような作業はid:n7shi:20091011で懲りていたため、別の方法に切り替えました。

C#とC++/CLIはILを媒介に変換できるため、C#のバイナリを逆コンパイラでC++/CLIにできそうです。コメントやローカル変数名が失われますが、元のソースがあるので必要に応じて復元すれば良いと割り切りました。

2. Managed C++

.NETの逆コンパイラとして有名な.NET Reflectorを試したところ、C++/CLIはサポートされていませんでした。Managed C++(以下MC++)はサポートされていたため、C++/CLIではなくMC++に変換しました。

生成されたコードは宣言と定義が一緒になった.cppファイルだけで、そのままではコンパイルが通りません。クラス間の循環参照があるため、Visual Studioのフォームデザイナのように全部ヘッダに書くという荒技も使えません。

仕方ないので手動で.hと.cppに分離しました。さすがに機械的に変換しただけあって、一部変換が不完全な部分を手直ししただけで動きました。

3. SDL.NETの軽量化

MIZU GAME本体だけでなく、参照しているSDL.NETも何とかしないといけません。SDL.NETはSDLの単純なラッパーではなく、クラスライブラリとして使いやすいように再構築されているため、単純に生のSDLを使うコードに書き換えることができません。

SDL.NETも逆コンパイラで変換できますが、そのままでは巨大過ぎて変換後の手直しが大変です。変換の前段階として使っていないクラスやメソッドを削りました。

4. SDL.NETの変換

必要最低限に軽量化したSDL.NETをReflectorでMC++に変換して、ビルドが通るように修正しました。

SDL.NETはP/InvokeラッパーのTao.Sdlを通してSDLを呼んでいます。Tao.Sdlは単純にP/InvokeでSDLをラップしただけのもので、クラス名を取り除くだけで直接SDLを呼べるようになりました。

C++からSDLを呼ぶにはヘッダとインポートライブラリが必要のため、上記アーカイブに同梱して相対パスで参照しています。別途SDLを用意してパスを通す手間はありません。

5. SDL.NETの取り外し

SDL.NETからSDLを呼んでいるコードをMIZU GAME本体に移して、必要なくなったSDL.NETのコードを削りながら、最終的にSDL.NETを完全に取り外しました。

bitbltや文字列描画など直接SDLを呼び出すと冗長になる部分は関数を作って、id:fslashtさんのご指摘通りSDLUtils.cppにまとめました。

6. ネイティブ化

コードがMIZU GAME本体だけになったので、MC++をC++に書き換えれば完成です。__gcを外していくだけの簡単なお仕事です。

C++化に伴いGCがなくなります。MIZU GAMEではオブジェクトの所有権が明確に構造化されて寿命がはっきりしていたため、自動変数をデストラクタで解放するRAIIの手法で対処できました。もしインスタンスをあちこち参照で取り回していたら、スマートポインタを持ち出す必要があったかもしれません。

ネイティブ化により、WindowsではVC++だけでなくgccでもビルドして動くようになりました。

7. バグ修正

ARMのクロスコンパイラでもビルドできたので、これで完成かと思いました。しかし念のため手元にあったFreeBSDで動作確認したところ、問題が発生しました。

  1. 文字が1文字しか描画されない(ワイド文字問題)
  2. タイトルからゲームに移るときに落ちる(ゼロ除算問題)

今までは機械的な変換作業だけで順調でしたが、ここに来て初めて移植に伴うバグに遭遇しました。ちなみにオリジナルのC#版はFreeBSDでもmonoで動きます。

ワイド文字問題

SDL_ttfの描画関数TTF_RenderUNICODE_Blended()は文字列として16bit整数型の配列を要求します。

当初はWindows上で作業していたため、単純にL"ABC"のようにワイド文字列を渡していました。しかしFreeBSDではwchar_tが32bitのため、単純にワイド文字列を渡すと1文字目の上位ワードが'\0'として解釈され、最初の文字しか表示されません。

gccオプション(-fshort-wchar)でwchar_tを16bitにしたところ、文字列のフォーマットに使用していたstd::wostringstreamで落ちるようになりました。libstdc++がビルドされたときのwchar_tのサイズと矛盾するのが原因です。std::basic_ostringstream<wchar_t>でも改善しなかったので、オプションでの対処は諦めました。

MIZU GAMEで使用する文字はUnicodeの基本多言語面に収まっているため、単純にwchar_tの配列を16bitの配列にコピーすることで対応しました。念のため基本多言語面に収まらない文字は'?'で置換しています。

#ifdef WIN32
	SDL_Surface *src = TTF_RenderUNICODE_Blended(font, (const Uint16 *)text, c);
#else
	int len = wcslen(text);
	Uint16 *buf = new Uint16[len + 1];
	for (int i = 0; i < len; i++)
	{
		unsigned int ch = text[i];
		buf[i] = ch > 0xffff ? '?' : ch;
	}
	buf[len] = 0;
	SDL_Surface *src = TTF_RenderUNICODE_Blended(font, buf, c);
	delete [] buf;
#endif

このコードではワイド文字列がUnicodeではない環境で問題が起きますが、今はWindowsとFreeBSDとNetWalkerで動けば良いので、気にしないことにします・・・。

ゼロ除算問題

gdbで追ったところ、SDL_mixerのMix_PlayMusic()内でSIGFPEが発生していました。試しにWineWin32バイナリを実行するとDivide by zeroが発生しました。

余談ですが、Wineで落ちた後に起動するデバッガではPEとELFが混ざってとんでもないことになります。 ⇒ スクリーンショット

それでゼロ除算ですが、実は心当たりがありました。SDL.NETを取り外すときに例外処理は全部無視しましたが、Audio/Music.csに以下の記述があったのです。

public void Play(int numberOfTimes)
{
    try
    {
        MusicPlayer.CurrentMusic = this;
        MusicPlayer.Play(numberOfTimes);
    }
    catch (DivideByZeroException)
    {
        // Linux audio problem
    }
}

※MusicPlayer.Play()でMix_PlayMusic()が呼ばれています。

SDL.NETでも諦めているくらいなので、原因は調査しないで無視することにしました。

#ifndef WIN32
static jmp_buf jbuf;
static void handler(int n) { longjmp(jbuf, 1); }
#endif

int SPlayMusic(Mix_Music *music, int loops)
{
#ifdef WIN32
	return Mix_PlayMusic(music, loops);
#else
	struct sigaction sig;
	memset(&sig, 0, sizeof(sig));
	sig.sa_handler = &handler;
	sigaction(SIGFPE, &sig, NULL);
	int ret = 0;
	if (setjmp(jbuf) == 0)
	{
		ret = Mix_PlayMusic(music, loops);
	}
	sig.sa_handler = SIG_DFL;
	sigaction(SIGFPE, &sig, NULL);
	return ret;
#endif
}

この修正により、FreeBSDでも動作するようになりました。同じソースをNetWalker用にクロスコンパイルしたものも動作したそうです。

SIGFPE

SIGFPEで検索に引っ掛かるかもしれないので、参考までに試したことを書いておきます。

初めはSIGFPEをSIG_IGNで無視しようとしたのですが、SIG_IGNが無視されてコアダンプしたので大域脱出で逃げました。

検索しても無視の定石のようなものは出てこなかったのですが、ハンドラを設定すると無限に呼ばれ続けました。ハンドラからの復帰はBasicのOn Error Resume Nextではなく再試行で、エラーの原因を取り除かないと無限ループになるため、SIGFPEは無視できないようです。

本気で無視しようとするならレジスタ書き換えなどで計算結果を改竄するしかないのですが、今回はx86だけでなくARMでも動かす必要があるので諦めました。もし無視してINT_MAXを返してもSDL_mixerが誤動作するだけで意味はなさそうです。

謝辞

今回の移植では私自身色々と勉強になりました。こういう機会でもなければ経験できないことばかりです。きっかけをくださったid:fslashtさんに改めて御礼申し上げます。ありがとうございました。

2009-12-12

[][][]クロス開発環境構築

WindowsでNetWalker(Ubuntu 9.04 ARM)のアプリをクロス開発するため、Interix上にクロス開発環境を構築しました。基本的な手順はid:n7shi:20091211のFreeBSDと同じですが、Interixではビルドに必要なツールやライブラリを自前で用意しないといけないため大変です。Package Manager for Interixを利用して、自動的にソースをダウンロードしてビルドするようにまとめました。Win32(MinGW)とWin64(id:n7shi:20091004)のクロスコンパイラも同梱しています。

Windows XPでの動作を確認しています。Vistaや7では未確認ですが動作するはずです。独自形式はメンテナンスが大変なので、Debian Interix Portへの移行を検討しています。

ビルド方法

C Shellを管理者として実行して、インストール先を作成します。

% mkdir /opt/pmgr
% chmod 777 /opt/pmgr
% exit

通常ユーザーでC Shellを実行して、ビルドを開始します。

% gzip -dc pmgr-interix-0.2-20091128.tar.gz | tar xvf -
% setenv PATH "/opt/pmgr/bin:$PATH"
% cd pmgr-interix
% make install

ソースをダウンロードしてビルドが始まります。目安として Athlon 64 X2 4600+ (2.4GHz) で約3時間掛かります。(※ダウンロード時間を除く)

パッケージ管理

簡単なパッケージ管理機能があります。

一度ビルドしたパッケージは以下のフォルダに入ります。pmgr-addコマンドで再インストールできます。

  • pmgr-interix/packages/

パッケージ配布

Windows XP用のパッケージの配布を行っています。Vistaや7のInterixとはバイナリ互換性がないため使用できません。

パッケージをインストールするには、pmgr-interix-0.2-20091128.tar.gzからbase/pmgrとbase/xzのインストールが必要です。

% cd pmgr-interix/base/pmgr
% make install
% cd ../xz
% make install
% rehash
% pmgr-add [package file]

pmgrファイルの実体はtar.xzです。オリジナルのtar.bz2から変更しました。

2009-12-11

[][][]クロス開発環境構築

FreeBSD上でNetWalker(Ubuntu 9.04 ARM)のアプリをクロス開発するため、クロス開発環境を構築しました。手順は以下の通りです。

  1. binutils-2.20
  2. ヘッダ・ライブラリ (id:n7shi:20091210より)
  3. gcc-4.4.2

FreeBSDに依存していないため、他のUNIX系OSでも同じ手順が使えるはずです。id:n7shi:20091115の手順と比較すると、glibcは既存のパッケージから流用しているため簡単です。

準備

以下のportsをインストールします。pkg_add -rでリモートインストールすると簡単です。

  • gmake
  • bison
  • texinfo
  • libgmp
  • mpfr
  • xz

ヘッダやライブラリが見えるように環境変数を設定します。

setenv CPPFLAGS -I/usr/local/include
setenv LDFLAGS -L/usr/local/lib

arm-linux-gnueabi

Ubuntu 9.04はarmelというARMの新しいABIを採用しています。armelはarm-gnueabiと指定するため、OSまで含めるとarm-linux-gnueabiとなります。

1. binutils-2.20

アセンブラやリンカなどコンパイラの下請けをするツール群です。

ソースをダウンロードして展開します。

fetch ftp://ftp.gnu.org/gnu/binutils/binutils-2.20.tar.bz2
tar xvjf binutils-2.20.tar.bz2

以下のパッチを当てます。中括弧を追加するだけの簡単な修正なので、手動で編集できます。

--- gas/config/tc-arm.c.orig
+++ gas/config/tc-arm.c
@@ -2486,7 +2486,7 @@
       frag->tc_frag_data.first_map = symbolP;
     }
   if (frag->tc_frag_data.last_map != NULL)
-    know (S_GET_VALUE (frag->tc_frag_data.last_map) < S_GET_VALUE (symbolP));
+    {know (S_GET_VALUE (frag->tc_frag_data.last_map) < S_GET_VALUE (symbolP));}
   frag->tc_frag_data.last_map = symbolP;
 }
 

binutilsgccはサブディレクトリで作業するのが流儀のようです。強制ではないようですが、ソースが膨大なため、色々な環境向けにビルドする際に使い回すのが目的のようです。

cd binutils-2.20
mkdir build
cd build
../configure --target=arm-linux-gnueabi
gmake
gmake install

2. ヘッダ・ライブラリ

id:n7shi:20091210アーカイブダウンロードします。

クロス開発環境から認識されるパスに展開します。

xz -dc ubuntu-jaunty-araneo-armel-dev.tar.xz | tar xvf - -C /usr/local/arm-linux-gnueabi

3. gcc-4.4.2

ソースをダウンロードして展開します。

fetch ftp://ftp.gnu.org/gnu/gcc/gcc-4.4.2/gcc-core-4.4.2.tar.bz2
fetch ftp://ftp.gnu.org/gnu/gcc/gcc-4.4.2/gcc-g++-4.4.2.tar.bz2
fetch ftp://ftp.gnu.org/gnu/gcc/gcc-4.4.2/gcc-objc-4.4.2.tar.bz2
tar xvjf gcc-core-4.4.2.tar.bz2
tar xvjf gcc-g++-4.4.2.tar.bz2
tar xvjf gcc-objc-4.4.2.tar.bz2

binutilsと同じようにサブディレクトリで作業します。

cd gcc-4.4.2
mkdir build
cd build
../configure --target=arm-linux-gnueabi
gmake
gmake install

テスト

a.c

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

上のソースをコンパイルします。

% arm-linux-gnueabi-gcc a.c
% file a.out
a.out: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (use
s shared libs), for GNU/Linux 2.6.16, not stripped

このa.outはARMバイナリのためx86上では実行できません。

% ./a.out
./a.out: Exec format error. Binary file not executable.

QEMUのユーザーモードエミュレーションを使用すればx86上でもARMバイナリを実行できますが、OSが同じである必要があります。FreeBSDのLinux互換環境での動作を試みましたが、うまくいきませんでした。

QEMUのARMシステムエミュレータでOSごと動かす方法もありますが、未確認です。

2009-12-10

[][]クロス開発用ヘッダ・ライブラリ

Ubuntu以外の環境でNetWalker(Ubuntu 9.04 ARM)のクロス開発環境を構築するため、debパッケージからヘッダとライブラリを抜き出してtarballにまとめました。GTK+, SDL, OpenGLの開発に必要なパッケージを選択しました。

これを使って実際にクロス開発環境を構築する方法は後日まとめます。 ⇒ id:n7shi:20091211(FreeBSD), id:n7shi:20091212(Interix)

jaunty-araneo-armel

Ubuntu 9.04はコードネームjauntyと呼ばれています。jauntyのパッケージリストは以下です。

NetWalkerではjauntyにaraneoというNetBook用の更新パッケージを適用しています。jaunty-araneoのパッケージリストは以下です。

jaunty-araneoではarmelと呼ばれる新しいARMのABIを採用しています。

パッケージ分析ツール

パッケージの量が膨大だったため、C#で依存関係分析ツールを作成しました。自分用に適当に作ったものですが、参考までにソースを置いておきます。

起動するといきなりパッケージリストをダウンロードして解析を始めます。.NET Frameworkではgzipストリームが扱えるので、gz形式のパッケージリストをダウンロードしています。

このツールでdebのURLリストを作成して、集めたdebを展開してアーカイブしたのが冒頭のファイルです。

2008-10-18

[]アセンブラ

ARMのアセンブラをいじってみました。生のバイナリを確認するにはアセンブルしてから逆アセンブルすれば簡単です。x86のときはnasmとndisasm -uでやっていましたが、binutilsではasとobjdumpを使います。

以下の内容をa.sとして保存します。

mov r1, #0x12000000
add r1, r1, #0x340000
add r1, r1, #0x5600
add r1, r1, #0x78 

x86に慣れているとaddの引数が3つもあるのは不思議な感じです。これは r1 = r1 + 0x340000 を意味しています。

アセンブルします。

% arm-wince-pe-as a.s 

出力ファイルを指定していないため出力はデフォルトのa.outになります。それを逆アセンブルします。

% arm-wince-pe-objdump -d a.out

a.out:     file format pe-arm-wince-little

Disassembly of section .text:

00000000 <.text>:
   0:   e3a01412        mov     r1, #301989888  ; 0x12000000
   4:   e281170d        add     r1, r1, #3407872        ; 0x340000
   8:   e2811c56        add     r1, r1, #22016  ; 0x5600
   c:   e2811078        add     r1, r1, #120    ; 0x78 

ARMでは引数込みで4バイト固定長になっているのが分かります。

x86ならmov eax, 0x12345678とすれば済みますが、ARMでは4バイト制約があるため、即値の代入でもこのように演算を交える必要があります。即値はシフトと組み合わせることが出来るため、下位ビットがゼロであれば巨大な数(0x12000000など)も表現することができます。

これでは効率が悪いため、プロシージャの直後に定数用のエリアを確保して、そこから値を読み込むようです。たとえば以下のC言語のソース(test.c)を用意します。

void test()
{
    int a = 0x12345678;
} 

これをコンパイルして逆アセンブルします。

% arm-wince-pe-gcc -c test.c
% arm-wince-pe-objdump -d test.o 

test.o:     file format pe-arm-wince-little

Disassembly of section .text:

00000000 <_test>:
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    {fp, ip, lr, pc}
   8:   e24cb004        sub     fp, ip, #4      ; 0x4
   c:   e24dd004        sub     sp, sp, #4      ; 0x4
  10:   e59f3004        ldr     r3, [pc, #4]    ; 1c <L3>
  14:   e50b3010        str     r3, [fp, #-16]
  18:   e89da808        ldm     sp, {r3, fp, sp, pc}

0000001c <L3>:
  1c:   12345678        eorsne  r5, r4, #125829120      ; 0x7800000 

1cは定数エリアのため、逆アセンブル結果(eorsne)に意味はありません。

gccに-Sオプションを渡せば逆アセンブルする必要はないのですが、アセンブリだけでなくバイナリが見たかったため、今回は-Sオプションを使わずにコンパイル結果を逆アセンブルしています。-Sオプションの出力はx86と違ってAT&T形式ではありません。

ちなみにx86やx64では-masm=intelと指定すればnasmと同じ形式で出力できます。

日本語資料

ARMの日本語資料は会員登録すれば無料で入手できます。

命令セットは「ARMアーキテクチャリファレンスマニュアル」で解説されています。

余談

今までx86以外はどこから手を付ければ良いのか分からなかったのですが、こうやってARMのバイナリに触れてみると、急に身近になったような気がしました。

ハードも開発用の評価ボードがないと手が出ないような先入観があったのですが、いつも持ち歩いているWILLCOM 03でも実験できるので、これまた身近です。

むしろなぜ今まで気付かなかったのだろうという印象です。