【コラム】
今回第5回は、アセンブラに挑戦してみましょう。アセンブラでは、必然的にOSやCPUに依存したプログラムとなりますが、これは仕方ないところでしょう。
リスト1は、Linux(CPUはx86)版のアセンブラのHello Worldです。このプログラムは、C言語での「write(1, "Hello World\n", 12); _exit(0);」に相当します。アセンブラでは、ソフトウェア割り込み(int $0x80)でwriteシステムコールを直接呼び出してメッセージを表示しています。その後、プログラムを正常に終了するため、_exitシステムコールを呼び出して終了です。このように、Linuxのシステムコールでは、システムコール番号(eax)やその引数の値(ebx、ecx、edxなど)を、CPUレジスタに代入して渡します。
このプログラムは、実はもう少しコードサイズを最適化できるのですが、わかりやすさ優先で記述してあります。
.text ← テキスト(プログラム)セクションの開始
_start: ← 実行開始アドレスのシンボル
.globl _start ← _startをグローバルシンボルにする
mov $12, %edx ← 出力バイト数、12バイトをedxに代入
mov $message, %ecx ← 文字列の先頭アドレスをecxに代入
mov $1, %ebx ← 標準出力のファイル記述子、1番をebxに代入
mov $4, %eax ← writeのシステムコール番号、4番をeaxに代入
int $0x80 ← システムコール実行(ソフトウェア割り込み)
xor %ebx, %ebx ← 終了ステータス、0をebxに代入
mov $1, %eax ← _exitのシステムコール番号、1番をeaxに代入
int $0x80 ← システムコール実行(ソフトウェア割り込み)
message: ← 文字列の先頭アドレスのシンボル
.ascii "Hello World\n" ← 文字列本体
アセンブルには、実行例1のように、gccコマンドがそのまま使えます。ファイルの拡張子が.sの場合、自動的にアセンブラのソースとみなされます。ここで、作成される実行バイナリファイルが、libcや、Cランタイムオブジェクトとリンクしないように、-nostdlibオプションを付けることが重要です。
$ gcc -o as_write_linux as_write_linux.s -nostdlib -static ← -nostdlibを付ける
$ ./as_write_linux ← 作成された実行バイナリファイルを実行
Hello World ← 確かにHello Worldが表示される
$ ← シェルのプロンプトに戻る
リスト2はFreeBSDの場合のアセンブラです。FreeBSDでは、システムコールがC言語の関数の形で呼び出されることを考慮して、引数をスタックにpushして渡す仕様になっています。この例のようにシステムコールを直接呼び出す場合、引数の後にダミーのリターンアドレスのpushが必要です。
このプログラムは短く、すぐに_exitで終了するため、システムコールの後のpopを行わず、スタックをもとに戻すことを省略しています。
.text
_start:
.globl _start
push $12 ← writeの第3引数(出力バイト数)をpush
push $message ← writeの第2引数(文字列のアドレス)をpush
push $1 ← writeの第1引数(ファイル記述子)をpush
push $0 ← ダミーのリターンアドレスをpush
mov $4, %eax ← writeのシステムコール番号、4番をeaxに代入
int $0x80 ← システムコール実行(ソフトウェア割り込み)
push $0 ← _exitの第1引数(終了ステータス)をpush
push $0 ← ダミーのリターンアドレスをpush
mov $1, %eax ← _exitのシステムコール番号、1番をeaxに代入
int $0x80 ← システムコール実行(ソフトウェア割り込み)
message:
.ascii "Hello World\n"
x86版Solarisの場合は、ソフトウェア割り込みの番号が$0x80から$0x91に変わる以外は、FreeBSDと同じになります(リスト3)。
ただし、「int $0x91」はSolaris10のシステムコールです。Solaris9以前では、代わりに「lcall $0x27,$0」または「lcall $7,$0」という命令を使用する必要があります。
.text
_start:
.globl _start
push $12
push $message
push $1
push $0
mov $4, %eax ← writeのシステムコール番号
int $0x91 ← Solaris10(x86)のシステムコール
push $0
push $0
mov $1, %eax ← _exitのシステムコール番号
int $0x91 ← Solaris10(x86)のシステムコール
message:
.ascii "Hello World\n"
最後にx86以外のCPUの例として、SunOS4(CPUはSPARC)のアセンブラを挙げておきましょう(リスト4)。SunOS4では、システムコールは「ta 0」というトラップ命令を使用し、システムコール番号はg1に、その引数は順にo0、o2、o3などのレジスタに入れて渡します。なお、SPRACでは、レジスタへの32bit定数値の代入が1命令ではできず、sethiとorの2命令を使って行います。
.text
_start:
.globl _start
mov 12, %o2 ← 出力バイト数、12バイトをo2に代入
sethi %hi(message), %o1 ← 文字列のアドレスの上位ビットをo1に代入
or %o1, %lo(message), %o1 ← 文字列のアドレスの下位ビットをo1に代入
mov 1, %o0 ← ファイル記述子1番をo0に代入
mov 4, %g1 ← writeのシステムコール番号4番をg1に代入
ta 0 ← SunOS4のシステムコール(トラップ命令)
clr %o0 ← 終了ステータス0をo0に代入
mov 1, %g1 ← _exitのシステムコール番号1番をg1に代入
ta 0 ← SunOS4のシステムコール(トラップ命令)
.align 8 ← 8バイト境界にそろえる
message:
.ascii "Hello World\n" ← 文字列本体
| 理研、脳・脊髄形成に必要な神経板湾曲の仕組みを解明 [20:16 5/25] |
| 京大、「慢性閉塞性肺疾患」患者の労作時呼吸困難は鍼治療が有効と実証 [20:08 5/25] |
| 120Hz SHVカメラ用イメージセンサーを使った撮像装置 - SHVフルスペック化へ [18:10 5/25] |
| 京大、視覚による物体認知は前頭前野からのトップダウン信号が重要と確認 [17:45 5/25] |
| 製品数の拡大だけでなくBCPの展開なども含めた総合力で事業の強化を図るTI [17:25 5/25] |
|
【連載】これだけは要チェック! TOEIC(R)単語帳 第108回 今回のお題は…「issue」 [20:00 5/27] キャリア |
|
TVアニメ『ペルソナ4』、新規カットを加えた再編集版を劇場でイベント上映 [20:00 5/27] ホビー |
|
[9nine]制服姿見納め? セーラー服で登場も川島海荷「4人はコスプレ」 [19:15 5/27] エンタメ |
|
「NO.6」4巻は書き下ろしドラマCD付、木乃のサイン会も [18:49 5/27] ホビー |
|
[今週の新刊]マンガ大賞3回ノミネート「アイアムアヒーロー」 カープ愛「球場ラヴァーズ」も [18:33 5/27] ホビー |
4つの診断で、自分の適性を見つめなおそう!
働くこと・挑戦し続けることへの思いを綴ったインタビュー
あなたにピッタリのアドバイスを読むことができます。
転職に必要な情報が収集できます
企業からアプローチのメッセージが届きます。