アンティーク・アセンブラ~Antique Assembler
第2回 メモリに始まりメモリに終わる
一般的な CPU アーキテクチャでは,演算や比較といったデータの加工は,レジスタに読み込んだデータに対して実施するのが通例です。その一方で加工対象となるデータは,プログラム作成時には定まっておらず,通常はメモリ上に格納されています。
そのためアセンブラプログラムの多くは,メモリ/レジスタの間でのデータ転送命令によって占められています。
今回は,メモリアクセスの基本となるデータ転送命令について説明します。
アドレッシング
アセンブラでは,処理対象となるものを特定するための形式のことを 「アドレッシングモード」(addressing mode),あるいは単に「アドレッシング」と呼びます。
冒頭で「(メモリ間との)データ転送について説明する」と述べた上で「アドレス」(address)という言葉が含まれていることから,「アドレッシングはメモリを指定するもの」といった誤解を招くかもしれませんが,先述したように「アドレッシング」とは「処理対象となるものを特定するための形式」を指すものですので注意してください。
各CPUアーキテクチャごとにさまざまな種類のアドレッシングが提供されていますが,概ね以下に述べるような分類が可能です。
ここで述べる分類は筆者独自の分類であり,CPU アーキテクチャによっては異なる分類/呼称を用いている場合もありますので注意してください。
レジスタ指定/値指定
処理対象として,レジスタ自身(あるいはレジスタが保持している値)を指定するのか,あるいは値そのものを指定するかで,アドレッシングは大きく2種類に分類できます。
Intel 80x86アーキテクチャでレジスタを指定する場合,"%" に続けてレジスタ名を記述します。
32ビットIntel 80x86アーキテクチャでは,32 ビット幅の値を扱うことができる汎用レジスタとして,EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESPの8つのレジスタが利用可能です。
ただし,汎用レジスタと銘打ってはいるものの,歴史的経緯/アーキテクチャ設計上の理由から,特定用途での使用を前提としているレジスタがあります。上記のレジスタで言うなら,EBPおよびESPはスタック管理(詳細は第5回以降で説明予定)専用と考えた方が良いでしょう。
値そのものが指定される場合,その値を「即値」(immediate value)と呼びます。Intel 80x86アーキテクチャでは,"$" を冒頭に記述することで即値記述であることを明示します。
リスト1 レジスタ指定/値指定
.text
.align 4
.global entry_point
entry_point:
int3 # プログラム実行の一時停止
# 即値 ⇒ レジスタ eax
movl $0x12345678, %eax
# レジスタ eax ⇒ レジスタ ebx
movl %eax, %ebx
.global end_of_program
end_of_program:
int3 # プログラム実行の一時停止
nop
即値は値そのものですから,データ転送先として指定することはできません。そのため,以下のプログラムはエラーとなります。
リスト2 アドレッシングエラー
# レジスタ ⇒ 即値
movl %eax, $0x12345678
# 即値 ⇒ 即値
movl $0xFFFFFFFF, $0x12345678
これまでは特に断りなく "movl"というデータ転送命令の表記を用いてきましたが,この表記は「データ転送」(move)を表す "mov" と「32 ビット長」を表す "l"(long)を組み合わせたものです。
データ転送におけるデータ長を16ビット(word)や 8ビット(byte)で行う場合は,データ長を表す "w" や "b"を指定します。
リスト3 データ長指定
.text
.align 4
.global entry_point
entry_point:
int3 # プログラム実行の一時停止
movl $0x12345678, %eax
movl $0xFFFFFFFF, %ebx
movl $0xFFFFFFFF, %ecx
# 16 ビット長の転送
movw %eax, %ebx
# 8 ビット長の転送
movb %eax, %ecx
.global end_of_program
end_of_program:
int3 # プログラム実行の一時停止
nop
データ長を32ビット未満に限定した場合,レジスタ上で対象データ位置に該当しない部分は値が変更されません。
図1 データ長指定の実行例
(gdb) run .... Program received signal SIGTRAP, Trace/breakpoint trap. 0x00401001 in entry_point () (gdb) continue Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. 0x00401016 in end_of_program () (gdb) info register eax ebx ecx eax 0x12345678 305419896 ebx 0xffff5678 -43400 ecx 0xffffff78 -136 (gdb)
なお,このプログラムに対して,asコマンドは以下のような警告を出します。
図2 データ長指定による警告
Warning: using `%bx' instead of `%ebx' due to `w' suffix Warning: using `%ax' instead of `%eax' due to `w' suffix Warning: using `%cl' instead of `%ecx' due to `b' suffix Warning: using `%al' instead of `%eax' due to `b' suffix
これは,レジスタ指定アドレッシングの"%eax"が「32ビット長」であることを暗に示しているために,データ長指定の"w"や"b"と整合が取れていないことに対する警告です。
Intel 80x86アーキテクチャでは,後方互換性の維持の点から,レジスタ表記とデータ長を以下のように定めています。
表1 データ長別レジスタ表記
| 表記 | データ長 | 意味 |
|---|---|---|
eax | 32ビット | axの32ビット拡張("extended") |
ax | 16ビット | eax |
ah | 8ビット | ax |
al |
8 ビット | ax |
上記はEAXレジスタに対する表記例ですが,16ビット長に関する表記は他の全ての汎用レジスタに対して,8ビット長に関する表記はEBX,ECX,EDXに対して適用することができます。


