Tweet

日記からの寄せ集めです.

ARM Thumb 命令セット

ARM の Thumb 命令セットの特徴をざっくり書くと

  • 1 命令が 16 bit
  • できることは ARM 命令セットのサブセット
  • 使えるレジスタは r0 〜 r7 の 8 つ
  • 2 オペランド命令

といったところかな.

プログラムサイズが小さくなる

命令長が短いことから,高密度のコードを生成できることが期待されるのだけれど,命令長が短いがために 1 命令あたりでできることは少なくなります. ARM 社の説明によると,それでもトータルで 30% 程度コード量が小さくなるそうです.

実行速度は遅くなる

Thumb 命令は CPU 内部では ARM 命令に展開されて実行されるそうです. 1 命令でできることは ARM 命令よりも少ないので,プログラムの速度は ARM 命令よりも遅くなります.

ということで

ARM Linux 上で Thumb 命令はどれだけ使えるのか,というあたりをつついていこうかと思ってます. どこまで突っ込んで見れるかはわからないけど.

(追記)

そういえば,Thumb-2 命令セット,なんてのもあるけど,今回はこっちの話は無し. だって実行環境持ってないんだもん.

ARM Thumb 命令セット 文献

ざっくりと挙げておきます.

ARM Architecture Reference Manual

ARM 社が出している ARMv5 アーキテクチャのリファレンスマニュアルです.

改訂 ARMプロセッサ―32ビットRISCのシステム・アーキテクチャ (Design Wave BOOKS)

いきなり英語はつらい方は,こちらで予習してから臨んだほうがよいでしょう.

大学の講義を前提にして書かれた本のようで,「ARM を例に CPU アーキテクチャの勉強をする」というスタンスで書かれています. 「そんなのはもう知ってるから,オレは ARM アーキテクチャについて知りたいんだ」という場合には正直うざいところがあります.

gcc のマニュアル

わざわざ web で読まなくても,環境によっては info コマンドで読める場合があります.

ARM Thumb 命令セット 状態遷移

もう少し復習めいた話が続きます.

32bit ARM 命令のモードと Thumb 命令のモード間の遷移は下図のようになります.

ARM          --(BX)-->               Thumb
            <--(BX)--
      <--(interrupt/exception)--

BX 命令でブランチすることにより,プログラム中で明示的に命令モードを変更することができます. 暗黙の遷移として,割り込みや例外などが発生した場合,Thumb モードから強制的に ARM モードへと切り替わります. この「割り込み」には「ソフトウェア割り込み」も含まれます. つまり,Linux 上でのシステムコールでもこの遷移が発生することになります.

ARM Thumb 命令セット Linux カーネル

Thumb 命令セットの Linux カーネル側の対応について.

Linux カーネル自身が Thumb コードでコンパイルされるわけではなく,Thumb ユーザプログラムが動くようにするための話です.

menuconfig 設定項目

CONFIG_ARM_THUMB という項目があります.

この項目の help を見ると

         Say Y if you want to include kernel support for running user space
         Thumb binaries.

         The Thumb instruction set is a compressed form of the standard ARM
         instruction set resulting in smaller binaries at the expense of
         slightly less efficient code.

         If you don't know what this all is, saying Y is a safe choice.

とあります.

実際のコード

CONFIG_ARM_THUMB で grep かけてみると,このマクロの影響する部分はちょろちょろとあります. 例えば linux/arch/arm/kernel/entry-armv.S の中です.

#ifdef CONFIG_ARM_THUMB
        bx      \reg
#else
        mov     pc, \reg
#endif

カーネルモードからユーザモードにジャンプするコードです. (マクロ定義の中なので,レジスタ名の部分が \reg になっちゃってます) bx 命令は Thumb 命令セットを持つ CPU でしか使えないので,こういうことになってるのでしょう. カーネル空間では ARM 命令セットで動作しているのでユーザ空間に戻るときはモードを元に戻す必要があり,ここで bx 命令が使われるわけです.

ARM Thumb 命令セット gcc サポート

gcc 上での Thumb 命令サポートについて.

コンパイルオプション

gcc のドキュメントから Thumb 命令に関するオプションを拾ってみると

  • -mthumb-interwork / -mno-thumb-interwork
  • -mthumb
  • -mtpcs-frame / -mno-tpcs-frame / -mtpcs-leaf-frame
  • -mcallee-super-interworking / -mcaller-super-interworking

というあたりかな.

ざっくり分類すると,こんなところかな.

Thumb 命令自体の有効/無効
これは当然.
関数呼び出し・リンク時の問題
ARM 命令モードの状態で Thumb 命令を使った関数はそのままでは呼ぶことはできない. 必ずどこかでモード切り替えが必要となる. で,どこでどう切り替えることにしよう,という約束事が必要になるのだけれど,そういうあたり.
スタックフレーム
どういう形式のスタックフレームを採用するかのオプション.

Thumb Interwork

-mthumb-interwork の説明によると

    Generate code which supports calling between the ARM and Thumb
    instruction sets.  Without this option the two instruction sets
    cannot be reliably used inside one program.  The default is
    `-mno-thumb-interwork', since slightly larger code is generated
    when `-mthumb-interwork' is specified.

ARM 命令セットと Thumb 命令セットをチャンポンに使ってプログラムをリンクできる枠組みのようです.

Super Interworking

-mcallee-super-interworking の説明によると

    Gives all externally visible functions in the file being compiled
    an ARM instruction set header which switches to Thumb mode before
    executing the rest of the function.  This allows these functions
    to be called from non-interworking code.

上記の Thumb Interwork の枠組みを使わずに呼び出し元 or 呼び出し先でモード切り替えを行うことで,非 Thumb Interwork コードとインターフェースしよう,ということのようですね.

ARM Thumb 命令セット Thumb Interwork

gcc での Thumb 命令サポートでの Thumb Interwork とよばれてるものについて.

環境

今回は old ABI の環境でいじりました.

CPU
88F5182 (I-O DATA HDL-GXR)
kernel
linux 2.6.12.6
userland
debian etch
gcc
gcc 4.1.2

ソース

例としてこんなソースを用意します.

  • arm.c, main.c は ARM 命令セットで
  • thumb.c は Thumb命令セットで

コンパイルすることを考えてます.

関数の呼び出しはこんなところ. ARM → Thumb と Thumb → ARM の両パターンが入るようにしています.

main -+-> arm_caller   -> thumb_callee
      |-> thumb_caller -> arm_callee

arm.c

extern int thumb_callee ( int );

int arm_caller ( int a )
{
	return a + thumb_callee ( a );
}

int arm_callee ( int a )
{
	return 1 + a;
}

thumb.c

extern int arm_callee ( int );

int thumb_caller ( int a )
{
	return a + arm_callee ( a );
}

int thumb_callee ( int a )
{
	return 1 + a;
}

main.c

#include <stdio.h>
extern int arm_caller ( int );
extern int thumb_caller ( int );

int main ( void )
{
	printf ( "%d %d\n", arm_caller(1), thumb_caller(1) );
	return 0;
}

コンパイル

とりあえずコンパイルしてみます.-mthumb-interwork というオプションで Thumb Interwork を使うことを指示しています.

$ gcc -mthumb-interwork main.c -c
$ gcc -mthumb-interwork arm.c -c
$ gcc -mthumb-interwork -mthumb thumb.c -c

ELF ヘッダ

生成されたオブジェクトファイルの ELF ヘッダを見てみます.

$ readelf -h arm.o 
ELF ヘッダ:
  マジック:  7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00 
  クラス:                            ELF32
  データ:                            2 の補数、リトルエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            ARM
  ABI バージョン:                    0
  タイプ:                            REL (再配置可能ファイル)
  マシン:                            ARM
  バージョン:                        0x1
  エントリポイントアドレス:          0x0
  プログラムの開始ヘッダ:            0 (バイト)
  セクションヘッダ始点:              268 (バイト)
  フラグ:                            0x4, GNU EABI, interworking enabled
  このヘッダのサイズ:                52 (バイト)
  プログラムヘッダサイズ:            0 (バイト)
  プログラムヘッダ数:                0
  セクションヘッダ:                  40 (バイト)
  Number of section headers:         9
  Section header string table index: 6

「フラグ」のところに interworking enabled というフラグが立っており,通常の ARM 命令の ELF ファイルとは区別されるようになってます.

オブジェクトファイルのディスアセンブル

ディスアセンブルしてみます.

$ objdump -d arm.o 

arm.o:     ファイル形式 elf32-littlearm

セクション .text の逆アセンブル:

00000000 <arm_caller>:
   0:	e1a0c00d 	mov	ip, sp
   4:	e92dd800 	stmdb	sp!, {fp, ip, lr, pc}
   8:	e24cb004 	sub	fp, ip, #4	; 0x4
   c:	e24dd004 	sub	sp, sp, #4	; 0x4
  10:	e50b0010 	str	r0, [fp, #-16]
  14:	e51b0010 	ldr	r0, [fp, #-16]
  18:	ebfffffe 	bl	0 <thumb_callee>
  1c:	e1a02000 	mov	r2, r0
  20:	e51b3010 	ldr	r3, [fp, #-16]
  24:	e0823003 	add	r3, r2, r3
  28:	e1a00003 	mov	r0, r3
  2c:	e24bd00c 	sub	sp, fp, #12	; 0xc
  30:	e89d6800 	ldmia	sp, {fp, sp, lr}
  34:	e12fff1e 	bx	lr
…

関数からの戻りは bx 命令でモード切り替えをするようになってますが,thumb_callee の呼び出しは bl 命令を使っており,このままでは Thumb モードにはスイッチできませんね. もっとも,単体でコンパイルしているのでこの段階ではコンパイラは「thumb_callee が Thumb 命令の関数である」ということを知らないわけで,無理もありません.

thumb.o も同様にディスアセンブルしてみます.

$ objdump -d thumb.o

thumb.o:     ファイル形式 elf32-littlearm

セクション .text の逆アセンブル:

00000000 <thumb_caller>:
   0:	b580      	push	{r7, lr}
   2:	b081      	sub	sp, #4
   4:	af00      	add	r7, sp, #0
   6:	1c3b      	adds	r3, r7, #0
   8:	6018      	str	r0, [r3, #0]
   a:	1c3b      	adds	r3, r7, #0
   c:	681b      	ldr	r3, [r3, #0]
   e:	1c18      	adds	r0, r3, #0
  10:	f7ff fffe 	bl	0 <arm_callee>
  14:	1c02      	adds	r2, r0, #0
  16:	1c3b      	adds	r3, r7, #0
  18:	681b      	ldr	r3, [r3, #0]
  1a:	18d3      	adds	r3, r2, r3
  1c:	1c18      	adds	r0, r3, #0
  1e:	46bd      	mov	sp, r7
  20:	b001      	add	sp, #4
  22:	bc80      	pop	{r7}
  24:	bc02      	pop	{r1}
  26:	4708      	bx	r1
…

1命令が 16bit になっており,ちゃんと Thumb 命令が使われてますね. 関数呼び出しと関数からのリターンは arm.o と同様のことになってます.

リンク

というわけで,おもむろにリンク.

$ gcc -o main main.o arm.o thumb.o
/usr/bin/ld: Warning: /usr/lib/gcc/arm-linux-gnu/4.1.2/libgcc_s.so does not support interworking, whereas main does
/usr/bin/ld: Warning: /lib/libc.so.6 does not support interworking, whereas main does
/usr/bin/ld: Warning: /usr/lib/libc_nonshared.a(elf-init.oS) does not support interworking, whereas main does
/usr/bin/ld: Warning: /lib/ld-linux.so.2 does not support interworking, whereas main does
/usr/bin/ld: Warning: /usr/lib/gcc/arm-linux-gnu/4.1.2/libgcc_s.so does not support interworking, whereas main does
/usr/bin/ld: Warning: /usr/lib/gcc/arm-linux-gnu/4.1.2/crtend.o does not support interworking, whereas main does
/usr/bin/ld: Warning: /usr/lib/gcc/arm-linux-gnu/4.1.2/../../../crtn.o does not support interworking, whereas main does

ELF ヘッダの interworking フラグを見ているようで,warning の嵐. main.o arm.o thumb.o は Thumb Interwork の ELF ファイルですが,libc や crt.o (スタートアップルーチン.main の前に実行される部分)などは 非 Thumb Interwork ファイルなので「形式が違うぞ」と警告しているわけです.

とりあえずこのままでも実行ファイルはできているのですが,warning が嫌いという場合には

$ gcc  -Wl,--no-warn-mismatch -o main main.o arm.o thumb.o

これで warning は表示されなくなります. ただし,「表示されない」というだけで問題が解決したわけではないので注意しましょう.

実行ファイルのディスアセンブル

生成された実行ファイルもディスアセンブルしてみましょう.

$ objdump -d main
…(略)…
0000840c <arm_caller>:
    840c:       e1a0c00d        mov     ip, sp
    8410:       e92dd800        stmdb   sp!, {fp, ip, lr, pc}
    8414:       e24cb004        sub     fp, ip, #4      ; 0x4
    8418:       e24dd004        sub     sp, sp, #4      ; 0x4
    841c:       e50b0010        str     r0, [fp, #-16]
    8420:       e51b0010        ldr     r0, [fp, #-16]
    8424:       eb000060        bl      85ac <__thumb_callee_from_arm>
    8428:       e1a02000        mov     r2, r0
    842c:       e51b3010        ldr     r3, [fp, #-16]
    8430:       e0823003        add     r3, r2, r3
    8434:       e1a00003        mov     r0, r3
    8438:       e24bd00c        sub     sp, fp, #12     ; 0xc
    843c:       e89d6800        ldmia   sp, {fp, sp, lr}
    8440:       e12fff1e        bx      lr
…(略)…
00008498 <thumb_callee>:
    8498:       b580            push    {r7, lr}
    849a:       b081            sub     sp, #4
    849c:       af00            add     r7, sp, #0
    849e:       1c3b            adds    r3, r7, #0
    84a0:       6018            str     r0, [r3, #0]
    84a2:       1c3b            adds    r3, r7, #0
    84a4:       681b            ldr     r3, [r3, #0]
…(略)…
000085ac <__thumb_callee_from_arm>:
    85ac:       e59fc000        ldr     ip, [pc, #0]    ; 85b4 <__thumb_callee_from_arm+0x8>
    85b0:       e12fff1c        bx      ip
    85b4:       00008499        muleq   r0, r9, r4
…(略)…

関数呼び出しの間に __thumb_callee_from_arm というルーチンが挟まっていて,arm_caller → __thum_callee_from_arm → arm_callee という経路で呼び出されています. で,__thumb_callee_from_arm の中で ARM → Thumb のモード切り替えが行われています. ARM 社のツールキットの説明では,このように間に挟まってモード切り替えを行うルーチンを「ベニア (veneer)」と呼んでいます.

余談ですが,アドレス 0x85b4 に入っているのはホントは命令ではなくて「thumb_callee の先頭アドレス + thumb フラグ」のデータなのですが,ディスアセンブラは命令として解釈してしまってるようですね. 実行パスを解釈してディスアセンブルしているわけじゃないので,こんなこともよく起こります.

実行

プログラムを実行してみましょう.

$ ./main 
3 3
$ echo $?
0

ちゃんと動いてますね.

まとめ

Thumb Interwork は ARM Linux 上でもかろうじて使える,のかなぁ?

ARM Thumb 命令セット Super Interworking

gcc での Thumb 命令サポートの Super Interworking について.

オプションの説明

gcc の info より抜粋.

`-mcallee-super-interworking'
    Gives all externally visible functions in the file being compiled
    an ARM instruction set header which switches to Thumb mode before
    executing the rest of the function.  This allows these functions
    to be called from non-interworking code.
`-mcaller-super-interworking'
    Allows calls via function pointers (including virtual functions) to
    execute correctly regardless of whether the target code has been
    compiled for interworking or not.  There is a small overhead in
    the cost of executing a function pointer if this option is enabled.

オプションの名前は対称的なんだけど,やってることは非対称な雰囲気ですね.

-mcallee-super-interworking のほうは関数先頭で Thumb モードへの切り替えを行い,外面的には ARM 命令セットの関数として振る舞うようです. 一方,-mcaller-super-interworking のほうは関数ポインタでの呼び出しをうまく処理してくれるようです. どう処理してくれるかはこの説明だけではよくわかりませんね.

環境

今回試した環境は

CPU
88F5182 (I-O DATA HDL-GXR)
カーネル
linux 2.6.12.6
ユーザランド
debian etch

です.

Callee Super Interworking

まずはこっちのほうを試してみましょう.

ソース

main.c

#include <stdio.h>

extern int thumb_callee ( int );

int main ( void )
{
	printf ( "%d\n", thumb_callee ( 1 ) );
	return 0;
}

thumb.c

int thumb_callee ( int a )
{
	return a + 1;
}

コンパイル

コンパイルします. main.c は ARM 命令セットで,thumb.c は Thumb 命令セットでコンパイルします.

$ gcc -mthumb -mcallee-super-interworking thumb.c -c
$ gcc main.c -c

ディスアセンブル

$ objdump -d thumb.o

thumb.o:     ファイル形式 elf32-littlearm

セクション .text の逆アセンブル:

00000000 <thumb_callee>:
   0:	e38fc001 	orr	ip, pc, #1	; 0x1
   4:	e12fff1c 	bx	ip

00000008 <.real_start_ofthumb_callee>:
   8:	b580      	push	{r7, lr}
   a:	b081      	sub	sp, #4
   c:	af00      	add	r7, sp, #0
   e:	1c3b      	adds	r3, r7, #0
  10:	6018      	str	r0, [r3, #0]
  12:	1c3b      	adds	r3, r7, #0
  14:	681b      	ldr	r3, [r3, #0]
  16:	3301      	adds	r3, #1
  18:	1c18      	adds	r0, r3, #0
  1a:	46bd      	mov	sp, r7
  1c:	b001      	add	sp, #4
  1e:	bc80      	pop	{r7}
  20:	bc02      	pop	{r1}
  22:	4708      	bx	r1

関数先頭で ARM → Thumb のモード切り替えが入っています. 戻り側も bx 命令で戻っているので ARM モードに復帰するようになっています.

ELF ヘッダ

ELF ヘッダを見てみます. 両者に違いはないようです.

$ readelf -h main.o 
ELF ヘッダ:
  マジック:  7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00 
  クラス:                            ELF32
  データ:                            2 の補数、リトルエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            ARM
  ABI バージョン:                    0
  タイプ:                            REL (再配置可能ファイル)
  マシン:                            ARM
  バージョン:                        0x1
  エントリポイントアドレス:          0x0
  プログラムの開始ヘッダ:            0 (バイト)
  セクションヘッダ始点:              232 (バイト)
  フラグ:                            0x0
  このヘッダのサイズ:                52 (バイト)
  プログラムヘッダサイズ:            0 (バイト)
  プログラムヘッダ数:                0
  セクションヘッダ:                  40 (バイト)
  Number of section headers:         10
  Section header string table index: 7
$ readelf -h thumb.o 
ELF ヘッダ:
  マジック:  7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00 
  クラス:                            ELF32
  データ:                            2 の補数、リトルエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            ARM
  ABI バージョン:                    0
  タイプ:                            REL (再配置可能ファイル)
  マシン:                            ARM
  バージョン:                        0x1
  エントリポイントアドレス:          0x0
  プログラムの開始ヘッダ:            0 (バイト)
  セクションヘッダ始点:              200 (バイト)
  フラグ:                            0x0
  このヘッダのサイズ:                52 (バイト)
  プログラムヘッダサイズ:            0 (バイト)
  プログラムヘッダ数:                0
  セクションヘッダ:                  40 (バイト)
  Number of section headers:         8
  Section header string table index: 5

リンク

というわけで,リンクは何も小細工無しに通ってしまいます.

$ gcc -o main main.o thumb.o

実行

もちろん,問題なく実行できます.

$ ./main 
2

Caller Super Interworking

というわけで,謎の Caller Super Interworking について.

ソース

main.c

#include <stdio.h>

extern int thumb_callee ( int );

int main ( void )
{
	printf ( "%d\n", thumb_callee ( 1 ) );
	return 0;
}

int arm_callee ( int a )
{
	return a + 1;
}

thumb.c

extern int arm_callee ( int );
static int (*acallee)( int ) = arm_callee;

int thumb_callee ( int a )
{
	return 1 + acallee ( a );
}

main → thumb_callee → arm_callee という経路で関数が呼び出されます.

コンパイル

$ gcc -mthumb -mcallee-super-interworking -mcaller-super-interworking thumb.c -c
$ gcc main.c -c

ディスアセンブル

$ objdump -d thumb.o

thumb.o:     ファイル形式 elf32-littlearm

セクション .text の逆アセンブル:

00000000 <thumb_callee>:
   0:	e38fc001 	orr	ip, pc, #1	; 0x1
   4:	e12fff1c 	bx	ip

00000008 <.real_start_ofthumb_callee>:
   8:	b580      	push	{r7, lr}
   a:	b081      	sub	sp, #4
   c:	af00      	add	r7, sp, #0
   e:	1c3b      	adds	r3, r7, #0
  10:	6018      	str	r0, [r3, #0]
  12:	4b07      	ldr	r3, [pc, #28]	(30 <.text+0x30>)
  14:	681a      	ldr	r2, [r3, #0]
  16:	1c3b      	adds	r3, r7, #0
  18:	681b      	ldr	r3, [r3, #0]
  1a:	1c18      	adds	r0, r3, #0
  1c:	f7ff fffe 	bl	0 <_interwork_call_via_r2>
  20:	1c03      	adds	r3, r0, #0
  22:	3301      	adds	r3, #1
  24:	1c18      	adds	r0, r3, #0
  26:	46bd      	mov	sp, r7
  28:	b001      	add	sp, #4
  2a:	bc80      	pop	{r7}
  2c:	bc02      	pop	{r1}
  2e:	4708      	bx	r1
  30:	0000      	lsls	r0, r0, #0
	...

この段階では _interwork_call_via_r2 という関数経由で arm_callee を呼び出そうとしているようです.

ELF ヘッダ

$ readelf -h thumb.o
ELF ヘッダ:
  マジック:  7f 45 4c 46 01 01 01 61 00 00 00 00 00 00 00 00 
  クラス:                            ELF32
  データ:                            2 の補数、リトルエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            ARM
  ABI バージョン:                    0
  タイプ:                            REL (再配置可能ファイル)
  マシン:                            ARM
  バージョン:                        0x1
  エントリポイントアドレス:          0x0
  プログラムの開始ヘッダ:            0 (バイト)
  セクションヘッダ始点:              228 (バイト)
  フラグ:                            0x0
  このヘッダのサイズ:                52 (バイト)
  プログラムヘッダサイズ:            0 (バイト)
  プログラムヘッダ数:                0
  セクションヘッダ:                  40 (バイト)
  Number of section headers:         10
  Section header string table index: 7

ARM 命令セットの obj ファイルと一緒ですね.

リンク

というわけでリンクしてみます.

$ gcc -o main main.o thumb.o
thumb.o: In function `.real_start_ofthumb_callee':
thumb.c:(.text+0x1c): undefined reference to `_interwork_call_via_r2'
collect2: ld returned 1 exit status

先ほどの _interwork_call_via_r2 が見つからず,リンクが失敗しています. 今回の環境ではこの関数は用意されてないようです. 残念.

ARM Thumb 命令セット gcc サポート ひとまずまとめ

いろいろつついてみて,わかったことをひとまずまとめてみる.

Thumb Interwork と Super Interworking

これら 2 つの枠組みの性格としては,おそらく

Thumb Interwork
ARM モードと Thumb モードの切り替えは toolchain 任せ
Super Interworking
ARM モードと Thumb モードの切り替えを自分で管理する

というようなところなのだろう.

根本的な問題

Thumb Interwork, Super Interworking に共通する問題として C プログラムの場合,ARM モードと Thumb モードの指定はファイル単位でしか行えない,という制限がある.

例えばデータ処理で

  • 前処理は呼び出し頻度が低いので Thumb 命令で
  • 本処理は頻度が高いので ARM 命令で

コンパイルしたい,なんてことは十分有り得るだろう. で,このようなプログラムの場合,(規模にもよるが)前処理と本処理は1つのソースファイルにまとめるのが普通である. が,gcc の縛りにより,1 つのソースファイル中で任意に ARM モード・Thumb モードの切り替えはできない.

フルスクラッチでプログラムを起こす場合は「しょうがないから ARM モードの部分と Thumb モードの部分でソースを分けよう」なんてこともできるが,既存のプログラムを移植するような場合は…ちょっと考えたくない. ソースファイル内で例えば #pragma ARM とかのコンパイラ指令でモードを行き来できたりすると,移植はしやすいんだけどなぁ.


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-11-21 (土) 09:30:36 (2945d)