分かりやす〜い
コンピュータ技術情報

TOPに戻る
▼Processor
簡単なアセンブラ言語
┣ 高級、低級の意味と
┃ レジスタ、mov、add

┣ 計算を行う
┣ プログラムを作る
┣ loop命令
┣ Indexレジスタの
┃ 役割とレジスタの
┃ 大きさ
┣ リピートプリフィック
┃ ス・ストリング命令

┣ inc・dec命令
┣ MMX技術
┣ MMXレジスタ
┣ MMX・SIMD・SSE
┣ CMP・JMP命令
┣ 関数とパラメータ
┣ スタック領域
┣ ESPレジスタ
┣ セグメント・
┃   call・ret

┣ コードファイルを作る
┣ コードファイル説明1
┣ コードファイル説明2
┗ マイクロコード

Copyright(C) 2001-2002.ugpop. All rights reserved.




■デジタル用語辞典:
■ cmp・jmp命令 ■

前回まではMMX技術について説明しました。
MMX技術を導入する事により複数のデータをいっぺんに処理す
る事が出来るのでした。

今回はプロセッサに「比較」を行なわせる為の命令を紹介しま
す。

インテルプロセッサに比較を行なわせる為には「cmp(Compare)」
という命令を使用します。

例えば、レジスタ「EAX」と「EBX」を比較しなさい、というの
をアセンブラ言語で表すと、「cmp eax, ebx」となります。

では、レジスタ「EAX」を「0」と比較しなさい、というのを
アセンブラ言語で表すとどうなるでしょうか?

答えは簡単ですね。

cmp eax, 0

です。

こんな感じでさまざまな比較を行なう事が出来ます。

ところで比較したは良いのですが、結果はどうなるのでしょう
か?

比較しっぱなしではどうにもならないので、比較結果を反映さ
せなければなりません。

その結果を反映させる為の場所として「EFLAGS」というレジス
タが使われます。

このレジスタはプロセッサの状態を表すさまざまなフラグが集
まっているレジスタです。
そして、このレジスタの第7ビットに「ゼロフラグ」という物
が存在しています。

「ゼロフラグ」というのは、1ビットの大きさしかありません。
比較した結果が「真」であればゼロフラグに「1」が格納され、
比較した結果が「偽」であればゼロフラグに「0」が格納され
ます。

例えば、「cmp eax, 0」という命令があるとして、「eax」レ
ジスタに格納されている値と「0」が同じ値(真)の時はゼロ
フラグに「1」が格納されます。

「eax」レジスタに格納されている値が「0」と異なる値(偽)
の時はゼロフラグには「0」が格納される事になります。


以下にEFLAGSレジスタのイメージを示します。


     EFLAGSレジスタ
┌──────────┬┬───┐
│          ││   │
└──────────┴┴───┘
            ↑
          7ビット目
          ゼロフラグ


それでは早速実践を行ってみましょう。
今回も以前作成したプログラム「inc.c」を流用してしまいま
す。

まずは「inc.c」をコピー&貼り付けして、新しく出来たファ
イルを「cmpjmp.c」というファイル名に変更しておきましょう。

今回はこの「cmpjmp.c」に変更を加えていきます。
まずは変更前のプログラムを見てみましょう。

─↓ここから──────────────────────

#include <stdio.h>
int main(void);
int sub(char*, char*);

int main()
{
  int i;
  char a[8]={ 0, 1, 2, 3, 4, 5, 6, 7};
  char b[8]={10,11,12,13,14,15,16,17};
  
  for(i=0;i<8;i++)
  {
    printf("a[%d]:%d b[%d]:%d\n", i, a[i], i, b[i]);
  }

  sub(&a[0], &b[0]);

  for(i=0;i<8;i++)
  {
    printf("a[%d]:%d b[%d]:%d\n", i, a[i], i, b[i]);
  }
  return 0;
}

int sub(char* a, char* b)
{
  printf("sub routine called\n");
  _asm{
    mov edi, a
    mov esi, b
    mov ecx, 8
LOOP1:
    mov al, [edi]  ;←データaをレジスタalに移動
    mov bl, [esi]  ;←データbをレジスタblに移動
    add al, bl    ;←データa+データbをalレジスタに格納
    mov [edi], al  ;←alレジスタをデータaに移動
    inc edi
    inc esi
    loop LOOP1
  }
}

─↑ここまで──────────────────────


このプログラムはデータbをデータaに加算するプログラムでし
た。
サブ関数ではデータbをデータaに1つずつ加算していく為に、
ループ命令を使用して8回繰り返し加算処理を行なっているの
でした。
(もう何度も見たプログラムなので飽きてきた方もいらっしゃ
るかもしれません。(^^;)

今回はループ命令を使用するのではなく、「cmp」命令を使用
して8回繰り返し処理を行なわせるように変更したいと思いま
す。

今回もメイン関数に変更はありません。サブ関数だけ変更しま
す。

変更後のサブ関数を以下に示します。
(変更部分にはコメントを付けておきます。)

─↓ここから──────────────────────

int sub(char* a, char* b)
{
  printf("sub routine called\n");
  _asm{
    mov edi, a
    mov esi, b
    mov ecx, 8
LOOP1:
    mov al, [edi]  ;←データaをレジスタalに移動
    mov bl, [esi]  ;←データbをレジスタblに移動
    add al, bl    ;←データa+データbをalレジスタに格納
    mov [edi], al  ;←alレジスタをデータaに移動
    inc edi
    inc esi
    dec ecx      ;●←変更した。ecx-1をecxに格納
    cmp ecx, 0    ;●←変更した。ecxが0か?
    jne LOOP1    ;●←変更した。ecx=0でなければLOOP1へジャンプ
  }
}

─↑ここまで──────────────────────


最後の3行が変わっただけです。
変更前は

loop LOOP1    ;←ecxの回数分ループ

というように「loop」命令を使用していましたが、変更後は

dec ecx      ;ecx-1をecxに格納
cmp ecx, 0    ;ecxが0か?
jne LOOP1    ;ecx=0でなければLOOP1へジャンプ

となっています。

ループ命令を忘れてしまった方の為に再度簡単に説明しますが、
ループ命令というのは「ecx」レジスタの回数分処理を繰り返
す為の命令です。

カウンタである「ecx」レジスタが0になるまで「ecx」レジス
タを1づつ減算しながらラベルに制御を移行してくれるのでし
た。

以下にループ処理のイメージを示します。


    ECX に8を格納      ┌───┐
      ├───────→ ECX│ 8 │
LOOP1:   │          └───┘
 ┌───→│
 │    │
 │    │
 │  何らかの処理
 ↑    │
 │    ↓
 │  loop LOOP1        ┌───┐
 │    │←─────── ECX│ 8 │
 │    ↓何回繰り返すか参照 └───┘
 │    │          ┌───┐
 │    ├───────→ ECX│ 7 │
 └────┘ECX を1減算    └───┘


以上が変更前のループ命令の説明です。

では変更後の命令の説明をします。
変更後の命令は3つあります。

dec ecx      ;ecx-1をecxに格納
cmp ecx, 0    ;ecxが0か?
jne LOOP1    ;ecx=0でなければLOOP1へジャンプ

最初の1つめは「dec ecx」という命令です。
これはインクリメント・デクリメントのプログラムを作成した
時に説明しましたが、「dec」命令というのは「1減算しなさ
い」という命令でした。

ただ単に1減算されるだけなので「sub ecx, 1」と書いても良
いのですが、インテルプロセッサの仕様により処理が速く行な
われる為、デクリメント命令を使用しています。

次に「cmp ecx, 0」という命令を使用しています。

これは先ほど説明したように、「ecxと0を比較しなさい」とい
う命令です。
比較した結果は「EFLAGS」レジスタに格納されます。


             EFLAGSレジスタ
      結果格納 ┌─────────┐
cmp ecx, 0─────→│         │
           └─────────┘


最後に「jne LOOP1」という命令があります。
これは初めて出てきた命令です。

jne LOOP1    ;ecx=0でなければLOOP1へジャンプ

比較しただけではいけないので、比較した結果により制御を移
行させる為の命令です。

「jne」(Jump Not Equal)という命令は比較した結果が「等し
くなければ」ジャンプしなさい、という意味になります。

つまり「ecx Not= 0」の時、LOOP1というラベルに制御が移行さ
れます。

このジャンプ命令を実行する時、インテルプロセッサ内部では
「EFLAGS」レジスタのゼロフラグを参照する処理が自動的に行
なわれます。


             EFLAGSレジスタ
       参照  ┌─────────┐
jne LOOP1 ←─────┤         │
           └─────────┘


ジャンプ命令はこの他にもさまざまな物があります。
代表的な物だけ以下に示します。


JE(Jump Equal):等しい時ジャンプする
例)
┌──────┬───────────────────┐
│cmp eax, ebx│                   │
│je LABEL  │eax=ebxの時LABELにジャンプする    │
└──────┴───────────────────┘


JNE(Jump Not Equal):等しくない時ジャンプする
例)
┌──────┬───────────────────┐
│cmp eax, ebx│                   │
│jne LABEL  │eax NOT= ebxの時LABELにジャンプする │
└──────┴───────────────────┘


JA(Jump Above):より大きい時ジャンプする
例)
┌──────┬───────────────────┐
│cmp eax, ebx│                   │
│ja LABEL  │eax > ebxの時LABELにジャンプする   │
└──────┴───────────────────┘


JAE(Jump Above Equal):以上の時ジャンプする
例)
┌──────┬───────────────────┐
│cmp eax, ebx│                   │
│jae LABEL  │eax >= ebxの時LABELにジャンプする  │
└──────┴───────────────────┘


JL(Jump Low):より小さい時ジャンプする
例)
┌──────┬───────────────────┐
│cmp eax, ebx│                   │
│jl LABEL  │eax < ebxの時LABELにジャンプする   │
└──────┴───────────────────┘


JLE(Jump Low Equal):以下の時ジャンプする
例)
┌──────┬───────────────────┐
│cmp eax, ebx│                   │
│jle LABEL  │eax <= ebxの時LABELにジャンプする  │
└──────┴───────────────────┘


以上は「ある条件に合った時」にジャンプする為の命令ですが、
無条件にジャンプする命令も当然あります。

JMP(Jump):無条件ジャンプ
例)
┌──────┬───────────────────┐
│jmp LABEL  │無条件にLABELにジャンプする      │
└──────┴───────────────────┘


●       ●
● ビルドする ●
●       ●

コマンドプロンプトを起動した後は必ず環境設定のバッチファ
イルを実行するようにしましょう。

env.bat

上記バッチファイル実行後、コマンドプロンプト上で以下の様
に入力してください。

sc cmpjmp.c -j

これでビルドされ、"cmpjmp.exe"という実行ファイルが作成さ
れるはずです。



●      ●
● 実行する ●
●      ●

コマンドプロンプト上で以下の様に入力してください。

cmpjmp.exe


例によって実行結果はいつもと同じです。(^^;

以前作成したプログラムと実行結果が同じなのでつまらないか
もしれませんが、コンペア命令とジャンプ命令を使用している
事を考えると少しはへー、と思いますよね?
(こればっかり・・・)


次回は関数って何?という説明をしたいと思います。



▲このページの上へ

▲このページの上へ

▲このページの上へ

▲このページの上へ

←前に戻る    ▲このページの上へ    続きを読む→