組み込み教育・アセンブラ アドレッシングモード編


前回までの記事ではコピー元やコピー先について体系的な説明を行わず、「どこからどこへコピーする」という形で説明していた。
今回はその指定方法についてスタック以外のデータ格納領域も含めて説明する。

C言語プログラムとバイナリコード

グローバル変数及び静的変数を含むプログラム①をコンパイルし、アセンブラコードに変換すると②のようになる。

① C言語プログラム

int global_data;
main()
{
    static int main_data = 0x1000;
    int array_data[5];
    int stack_data = 0x10;
    int i = 4;

    array_data[i] = 0;
    global_data = main_data + stack_data;
}

このプログラムでは以下の変数が宣言されている。

  • global_data:グローバル変数
  • main_data:main()関数内の静的変数
  • stack_data:スタック上に確保されるローカル変数
  • array_data[5]:スタック上に確報される配列

② アセンブラコード

.bss
 global_data resd 1 ; グローバル変数(未初期化)

 .data
 main_data dd 1000h        ; static変数(初期化ありなのでデータ領域) 

.text
 global main 
main:
     push ebp
     mov  ebp, esp
     sub  esp, 28            ; array_data(20) + stack_data(4) + i(4)
     ; stack_data = 0x10
     mov  DWORD PTR [ebp-4], 10h
     ; i = 4
     mov  DWORD PTR [ebp-8], 4
     ; array_data[i] = 0
     mov  eax, DWORD PTR [ebp-8]
     ; eax = i
     mov  DWORD PTR [ebp-28 + eax*4], 0
     ; global_data = main_data + stack_data
     mov  eax, DWORD PTR main_data
     add  eax, DWORD PTR [ebp-4]
     mov  DWORD PTR global_data, eax
     mov  esp, ebp
     pop  ebp
     ret

ディレクティブとデータ定義

「.」で始まる行はディレクティブと呼ばれ、コード配置やデータ定義など、機械語生成以外の制御を指示する疑似命令である。

.bss
global_data resd 1
  • .bss は未初期化データ領域を表す
  • global_data はラベル(アドレスを示す)
  • resd 1 は32bit領域を1つ確保する命令。データ型により、resb、resw等がある。

※ .bss 領域は通常、プログラム起動時に0で初期化される。

.data
main_data dd 1000h
  • .data は初期化済みデータ領域
  • dd は32bitデータ定義命令。データ型により、db、dw等がある。
  • 初期値は 1000h
.text
  • .textは実行コード(命令列)が格納される領域

対象となる計算処理命令のアドレッシングモード

アドレッシングモードとは、CPUが命令を実行する際に処理対象となるデータの格納場所(メモリアドレスやレジスタ)を指定する方法のことである。
ここでは各命令のアドレッシングモードについて説明する。なお、説明対象を赤文字としている。

① 即値アドレッシング
 命令内に直接値を指定する方法

mov DWORD PTR [ebp-8], 4

② レジスタアドレッシング
 レジスタを直接指定する方法

mov eax, DWORD PTR [ebp-8]

③ 直接アドレッシング
 メモリアドレス(ラベル)を指定する方法
 下の例では静的変数であるmain_data というラベルの付いたメモリのアドレスを指定している
 グローバル変数へも同様の方法で指定する

mov eax, DWORD PTR main_data

④ ベースレジスタ相対アドレッシング
 ebp(ベースポインタ)を基準に nバイトずらしたアドレスの値を指定する方法
 スタック上のローカル変数などに使用する

mov DWORD PTR [ebp-8], 4

⑤ インデックス付きアドレッシング
 ebp(ベースポインタ)を基準に、インデックスレジスタの値を足したアドレスの値を指定する方法
 下の例ではebp – 28 (ローカル変数 array_dataの先頭アドレス)にレジスタeax(インデックスレジスタの値)×4(要素のサイズ) を足したアドレスを指定している
 eaxには1つ前の命令でローカル変数 i の値を入れているので、array_data[i] を指し示すことになる

mov DWORD PTR [ebp-28 + eax*4], 0

変数の種類とアドレッシングモード

ここまで命令毎にアドレッシングモードの説明を行った。
次にデータの格納場所毎にどのアドレッシングモードが使用されるかをまとめる。

種類配置アドレッシング
グローバル変数.bss / .data直接
静的変数.bss / .data直接
ローカル変数(スタック)スタックベースレジスタ相対
ローカル変数(最適化時)レジスタレジスタ
引数スタックベースレジスタ相対
配列スタックインデックス付き


以上、簡単ですが自動変数以外の変数の確保される領域とアクセスする方法についての説明でした。


関連記事

TOP
CONTACT ACCESS LINE CALL