アンティーク・アセンブラ~Antique Assembler

第2回 メモリに始まりメモリに終わる

この記事を読むのに必要な時間:およそ 8.5 分

直接アドレッシング/間接アドレッシング

取り扱い対象を直接指定するのが直接アドレッシング⁠⁠,指定したものをアドレス値とみなしてメモリ領域(あるいはそこに格納された値)を取り扱うのが間接アドレッシング」です。

以下に,レジスタ指定/値指定との組み合わせの例を示します。

リスト4 直接/間接アドレッシング

    .data
    .align  4

    .global value
value:
    .long   1

    .text
    .align  4

    .global entry_point
entry_point:
    int3        # プログラム実行の一時停止

    # 転送元: value 領域の格納値(間接)
    # 転送先: レジスタ eax(直接)
    movl    value, %eax

    # 転送元: value 領域のアドレス(直接)
    # 転送先: レジスタ eax(直接)
    movl    $value, %eax

    # 転送元: レジスタ eax の参照先領域の格納値(間接)
    # 転送先: レジスタ ebx(直接)
    movl    (%eax), %ebx

    # 転送元: 即値(直接)
    # 転送先: レジスタ eax の参照先領域の格納値(間接)
    movl    $0xFFFFFFFF, (%eax)

    # 転送元: 即値(直接)
    # 転送先: value 領域(間接)
    movl    $0x12345678, value

    # 転送元: レジスタ eax(直接)
    # 転送先: value 領域(間接)
    movl    %eax, value

    .global end_of_program
end_of_program:
    int3        # プログラム実行の一時停止
    nop

上記サンプルプログラムを実行して,データ転送状況を確認してみましょう。

図3 直接/間接アドレッシングの実行例

(gdb) disassemble entry_point end_of_program
    ※ 逆アセンブルで命令位置を確認
Dump of assembler code from 0x401000 to 0x401022:
0x00401000 :    int3   
0x00401001 :    mov    0x402000,%eax
0x00401006 :    mov    $0x402000,%eax
0x0040100b :    mov    (%eax),%ebx
0x0040100d :    movl   $0xffffffff,(%eax)
0x00401013 :    movl   $0x12345678,0x402000
0x0040101d :    mov    %eax,0x402000
End of assembler dump.
(gdb) run
....
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00401001 in entry_point ()
(gdb) info register eax ebx
eax            0x0    0
ebx            0x7ffdf000    2147348480
(gdb) print/x value
$1 = 0x1
    ※ レジスタ/メモリ内容の初期値を確認
(gdb) print/x &value
$2 = 0x402000
    ※ value のアドレスを確認
(gdb) stepi
0x00401006 in entry_point ()
    ※ "mov    0x402000,%eax" の実行
(gdb) info register eax
eax            0x1    1
    ※ レジスタ値の確認(= value 位置の内容)
(gdb) stepi
0x0040100b in entry_point ()
    ※ "mov    $0x402000,%eax" の実行
(gdb) info register eax
eax            0x402000    4202496
    ※ レジスタ値の確認(= value のアドレス)
(gdb) stepi
0x0040100d in entry_point ()
    ※ "mov    (%eax),%ebx" の実行
(gdb) info register ebx
ebx            0x1    1
    ※ レジスタ値の確認(= value 位置の内容)
(gdb) stepi
0x00401013 in entry_point ()
    ※ "movl   $0xffffffff,(%eax)" の実行
(gdb) print/x value
$3 = 0xffffffff
    ※ value 位置の内容確認
(gdb) stepi
0x0040101d in entry_point ()
    ※ "movl   $0x12345678,0x402000" の実行
(gdb) print/x value
$4 = 0x12345678
    ※ value 位置の内容確認
(gdb) stepi
0x00401022 in end_of_program ()
    ※ "mov    %eax,0x402000" の実行
(gdb) print/x value
$5 = 0x402000
    ※ value 位置の内容確認
(gdb) 

GDBのstepiコマンドは,CPU命令単位で1命令毎の実行を行います(= STEP Instruction⁠⁠。実行後に表示されるのは次に実行される命令の位置ですので,読み間違えないように注意してください。

あまり一般的ではありませんが,指定されたメモリ領域に格納された値をアドレスとみなし,さらに別のメモリ領域へとアクセスする,といった多段間接アドレッシングを許すCPUアーキテクチャもあります。

先述したように,ここで述べているアドレッシング分類は筆者独自のものです。

筆者の分類では,アドレス指定によるメモリ内容の読み書きは「間接」アドレッシングとみなしていますが,CPU アーキテクチャによってはこのアドレッシングを,レジスタ間接アドレッシングによるメモリ参照との対比から,直接メモリ参照」と呼称する場合もあります。

著者プロフィール

藤原克則(ふじわらかつのり)

Mercurial三昧の日々が嵩じて, いつの間にやら『入門Mercurial Linux/Windows対応』を上梓。凝り性なのが災いして,年がら年中アップアップな一介の実装屋。最近は仕事の縁が元で,OpenSolarisに入れ込む毎日。