20
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Linuxでx86アセンブラ(条件分岐編)

:large_blue_diamond:この記事について

Linuxでx86アセンブラ、第8回目.今回はアセンブラでの条件分岐について書いていきます.条件分岐とは条件にしたがって行う処理を切り替えることです.Cなどの高級言語では、ifswitchなどで行っています.アセンブラでの条件分岐はCなどの条件分岐と比べて少し複雑です.なぜなら、条件判定と分岐が分かれているからです.
どのように条件分岐をしているかというと、まずcmptestなどのニーモニックで分岐するかを始めに判定しステータスフラグをセットします.ステータスフラグは計算結果の状態を真または偽で保持する特殊なレジスタです.そのステータスフラグに基づいてジャンプ(指定された命令の位置へ移動すること.)するかどうかを判定しジャンプします.
それでは、ステータスフラグ、ジャンプ、分岐判定の順に説明していきます.

:large_blue_diamond:ステータスフラグ

主なステータスフラグにはSF、ZF、CF、AF、PFがあります.
SF(Sign Flag)は計算結果が正の時1、負の時は0になります.
ZF(Zero Flag)は計算結果が0の時1、負の時は0になります.
OF(Overflow Flag)は符号あり整数の桁溢れが発生した際に真になります.
CF(Carry Flag)は符号なし整数の桁溢れが生じた際に1になります.
AF(Auxiliary Flag)は上位の4ビットと下位4ビットの間で桁上げか桁下げが起きた時に1になります.
PF(Parity Flag)は1であるビット数が偶数の時に1になります.

:large_blue_diamond:ジャンプ

ジャンプとは今いる命令のアドレスから、指定されたアドレスの命令のアドレスに移動することです.
無条件でジャンプするにはjmpニーモニックを使います.

jmp <命令のアドレス or ラベル>

条件付きのジャンプにはjzjcjojsjpがあります.

  • ゼロでジャンプ
    jzはjump if zeroで、ZFが1の時ジャンプします.対になる命令でjnzがあります.こちらはZFが0の時ジャンプします.

  • キャリー発生でジャンプ
    jcはjump if carryで、CFが1の時ジャンプします.jzと同様にjncがあり、こちらはCFが0の時ジャンプします.

  • オーバフローでジャンプ
    joはjump if overflowでOFが1の時ジャンプします.これも、jnoがあります.

  • 負の計算結果でジャンプ
    jsはjump if negative signの略でSFが1の時ジャンプします.
    正の時にジャンプしたい場合はjnsを使います.

:large_blue_diamond:条件判定

cmptest ニーモニックはオペランドを比較してフラグをセットします.

  • 整数値の比較
    整数値の比較にはcmpニーモニックを使います.
cmp <レジスタ・メモリ>, <レジスタ・メモリ・即値>

cmp は第一オペランドと第二オペランドの引き算を実行します.
その結果に基づきフラグをセットします.計算結果の値は破棄され、どのレジスタメモリにも保存されません.なので、オペランドの値はこの命令によって変更を受けることはありません.

  • ビット列の比較 ビット列の比較にはtest ニーモニックを使用します.
test <レジスタ・メモリ>, <レジスタ・メモリ・即値>

testは2つのオペランドのAND計算を実行し、計算結果に基づきフラグをセットします.cmp の時と同様に計算結果は破棄され、オペランドのレジスタ・メモリは変更を受けません.

:large_blue_diamond:デモコード

この記事で扱った命令の使い方を説明するデモコードです.

control_flow.asm
section .data

section .bss

section .text

global main

main:
   enter 0,0
   nop

   jmp .compare

.equal:
    mov ebx, 5
    cmp ebx, 8
    jns .greater
    cmp ebx, 7
    jns .greater
    cmp ebx, 6
    jns .greater
    cmp ebx, 5
    jns .greater
    cmp ebx, 4
    jns .greater

.final:
    mov eax, 0
    leave
    ret

.greater:
    xor eax, eax
    xor ebx, ebx
    jmp .final

.compare:
    mov eax, 3
    cmp eax, 2
    jz .equal
    cmp eax, 5
    jz .equal
    cmp eax, 3
    jz .equal

コンパイルしてgdb上で実行してみてください.
gdbでフラグの状態を表示するにはdisplay $ps コマンドを利用してください.

参考文献

↓↓:bowtie:過去の投稿もよろしくね:bowtie:↓↓

↓↓:bowtie:コメントをいただけたら励みになります:bowtie:↓↓

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
20
Help us understand the problem. What are the problem?