10. x86アセンブリ処理とフローチャート¶
ここでは、x86アセンブリ処理とフローチャートの対応関係について書きます。ソースコードとフローチャートを順番に書くことで、x86アセンブリ処理の流れを明確にします。※アセンブラはNASM、Windows用リンカはalink、ライブラリはwin32.libを利用します。
Contents
10.1. goto文¶
x86アセンブリではジャンプ命令を多用します。
gotoの構文
jmp ジャンプ先アドレス
;「ジャンプ先アドレス」はラベル、レジスタなどアドレスをあらわすものが来ます。
org 100H
section .text
START:
jmp B
A:
mov bx, P01
call PRINT
B:
mov bx, P02
call PRINT
jmp D
C:
mov bx, P03
call PRINT
D:
;プログラムの終了
mov ah, 4cH
int 21H
;表示関数
PRINT:
mov ax, 0200H
mov dl, [ds:bx]
cmp dl, 00H
jz PRINTEND
int 21H ;システムコール
inc bx
jmp PRINT
PRINTEND:
ret
section .data ;データセクション
P01 db '01',00H
P02 db '02',00H
P03 db '03',00H
goto文例のフローチャート
10.3. if...else文¶
※参考:Javaの if...else文への参照
if...else文は無いですが、cmp命令とj*命令を組み合わせて使うことで同様の処理が可能です。
cmp、j*の構文
;===========================
;符号あり
;===========================
;dest:ジャンプ先アドレス
;if(A == B) goto dest
cmp A, B
je dest
;if(A < B) goto dest
cmp A, B
jg dest
;if(A <= B) goto dest
cmp A, B
jle dest
;if(A > B) goto dest
cmp A, B
jg dest
;if(A >= B) goto dest
cmp A, B
jge dest
;not
;===========================
;if(!(A == B)) goto dest
;if(A != B) goto dest
cmp A, B
jne dest
;if(!(A < B)) goto dest
cmp A, B
jnl dest
;if(!(A <= B)) goto dest
cmp A, B
jnle dest
;if(!(A > B)) goto dest
cmp A, B
jng dest
;if(!(A >= B)) goto dest
cmp A, B
jnge dest
;===========================
;符号なし
;===========================
;dest:ジャンプ先アドレス
;if(A == B) goto dest
cmp A, B
je dest
;if(A < B) goto dest
cmp A, B
jb dest
;if(A <= B) goto dest
cmp A, B
jbe dest
;if(A > B) goto dest
cmp A, B
ja dest
;if(A >= B) goto dest
cmp A, B
jae dest
;not
;===========================
;if(!(A == B)) goto dest
;if(A != B) goto dest
cmp A, B
jne dest
;if(!(A < B)) goto dest
cmp A, B
jnb dest
;if(!(A <= B)) goto dest
cmp A, B
jnbe dest
;if(!(A > B)) goto dest
cmp A, B
jna dest
;if(!(A >= B)) goto dest
cmp A, B
jnae dest
if..else文例
as_if_else.asm
org 100H
;非初期化データセクション(変数として使う)
section .bss
age: resw 1 ;short int age
result: resw 1 ;short int result
section .text
START:
mov [ds:age], word 116
mov [ds:result], word 0
if00: ;if(age>=70)
cmp [ds:age], word 70
jge then01
jmp elseif01
then01:
mov [ds:result], word STR01
jmp endif00
elseif01: ;else if(age>=60)
cmp [ds:age], word 60
jge then02
jmp elseif02
then02:
mov [ds:result], word STR02
jmp endif00
elseif02: ;else if(age>=50)
cmp [ds:age], word 50
jge then03
jmp elseif03
then03:
mov [ds:result], word STR03
jmp endif00
elseif03: ;else if(age>=40)
cmp [ds:age], word 40
jge then04
jmp elseif04
then04:
mov [ds:result], word STR04
jmp endif00
elseif04: ;else if(age>=30)
cmp [ds:age], word 30
jge then05
jmp elseif05
then05:
mov [ds:result], word STR05
jmp endif00
elseif05: ;else if(age>=15)
cmp [ds:age], word 15
jge then06
jmp else06
then06:
mov [ds:result], word STR06
jmp endif00
else06:
mov [ds:result], word STR07
jmp endif00
endif00:
mov bx, [ds:result]
call PRINT ;=>学に志す
;プログラムの終了
mov ah, 4cH
int 21H
;表示関数
PRINT:
mov ax, 0200H
mov dl, [ds:bx]
cmp dl, 00H
jz PRINTEND
int 21H ;システムコール
inc bx
jmp PRINT
PRINTEND:
ret
;初期化データセクション
section .data
STR01 db '心の欲する所に従って矩を踰えず',00H
STR02 db '耳順う',00H
STR03 db '天命を知る',00H
STR04 db '惑わず',00H
STR05 db '立つ',00H
STR06 db '学に志す',00H
STR07 db '無し',00H
if..else文例のフローチャート
10.4. switch文¶
この構文はありません。しかし、「section .data」データセクションを使って類似の記述ができます。
構文
section .rodata
定数(配列)名 サイズ 初期化値1 初期化値2 ...
;サイズ:dd、dw、db ディレクティブを使って、32ビット、16ビット、8ビットの値を宣言します。
jmp ジャンプ先アドレス
※参考:Javaの switch文への参照
switch文例
as_switch.asm
org 100H
;非初期化データセクション 大域変数として使う
section .bss
month: resw 1 ;shot int month
result: resw 1 ;shot int result
section .text
START:
mov [ds:month], word 2
mov [ds:result], word 0
mov ax, [ds:month]
;switch(month)
;範囲判定
cmp ax, 1
jl default0
cmp ax, 12
jg default0
;caseへのジャンプ
jmp [SW_CASES+(eax-1)*2]
case1:
mov [ds:result], word MONTH01
jmp endswitch
case2:
mov [ds:result], word MONTH02
jmp endswitch
case3:
mov [ds:result], word MONTH03
jmp endswitch
case4:
mov [ds:result], word MONTH04
jmp endswitch
case5:
mov [ds:result], word MONTH05
jmp endswitch
case6:
mov [ds:result], word MONTH06
jmp endswitch
case7:
mov [ds:result], word MONTH07
jmp endswitch
case8:
mov [ds:result], word MONTH08
jmp endswitch
case9:
mov [ds:result], word MONTH09
jmp endswitch
case10:
mov [ds:result], word MONTH10
jmp endswitch
case11:
mov [ds:result], word MONTH11
jmp endswitch
case12:
mov [ds:result], word MONTH12
jmp endswitch
default0:
mov [ds:result], word ERROR
jmp endswitch
endswitch:
mov bx, [ds:result]
call PRINT
;プログラムの終了
mov ah, 4cH
int 21H
;表示関数
PRINT:
mov ax, 0200H
mov dl, [ds:bx]
cmp dl, 00H
jz PRINTEND
int 21H ;システムコール
inc bx
jmp PRINT
PRINTEND:
ret
;定数(const)を格納するためのセクション※read only data section
section .rodata
;switch caseテーブル
SW_CASES dw case1, case2, case3, case4, case5, case6, case7, case8, case9, case10, case11, case12, default0
;文字列テーブル
MONTH01 db 'January',00H
MONTH02 db 'February',00H
MONTH03 db 'March',00H
MONTH04 db 'April',00H
MONTH05 db 'May',00H
MONTH06 db 'June',00H
MONTH07 db 'July',00H
MONTH08 db 'August',00H
MONTH09 db 'September',00H
MONTH10 db 'October',00H
MONTH11 db 'November',00H
MONTH12 db 'December',00H
ERROR db 'err',00H
switch文例のフローチャート
10.5. for文¶
for文は無いので、ジャンプ命令、cmp命令を利用して類似の処理を行います。
※参考:Javaの for文への参照
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ; int sum
i: resd 1 ; int i
str: resb 64 ; char str[64]
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
mov [ds:sum], dword 0
;for(i=1;i<=10;i++)
mov [ds:i], dword 1
for01:
cmp dword [ds:i], 10
jle then01
jmp endfor01
then01:
mov eax, dword [ds:i]
add [ds:sum], dword eax
inc dword [ds:i]
jmp for01
endfor01:
;end for
push dword [ds:sum]; PRINTNUM(sum)
call PRINTNUM ;=>55
sub esp, 4;PRINTNUM呼び出し引数スタック除去
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess;
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
for文例のフローチャート
10.6. for-each文¶
for-each文は無いので、ジャンプ命令、com命令を利用して類似の処理を行います。
※参考:Javaの for each文への参照
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
NUMS dd 1,2,3,4,5,6,7,8,9,10 ;const int NUMS[] = {1,2,3,4,5,6,7,8,9,10}
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ;int sum;
i: resd 1 ;int i;
str: resb 64 ;char str[64];
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
mov [ds:sum], dword 0
;for(i=0;i<10;i++)
mov [ds:i], dword 0
for01:
cmp dword [ds:i], 10
jl then01
jmp endfor01
then01:
mov eax, dword [ds:i]
mov ebx, [ds:NUMS+eax*4]
add [ds:sum], dword ebx
inc dword [ds:i]
jmp for01
endfor01:
;end for
push dword [ds:sum]; PRINTNUM(sum)
call PRINTNUM ;=>55
sub esp, 4;PRINTNUM呼び出し引数スタック除去
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess;
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
for each文例のフローチャート
10.7. while文¶
while文はありません。しかし、ジャンプ命令とcmp命令を使って類似の記述ができます。
※参考:Javaの while文への参照
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ; int sum
i: resd 1 ; int i
str: resb 64 ; char str[64]
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;i=1
mov [ds:i], dword 1
;sum=0
mov [ds:sum], dword 0
;while(i<=10)
while01:
cmp dword [ds:i], 10
jle then01
jmp endwhile01
then01:
mov eax, dword [ds:i]
add [ds:sum], dword eax
inc dword [ds:i]
jmp while01
endwhile01:
;end while
push dword [ds:sum]; PRINTNUM(sum)
call PRINTNUM ;=>55
sub esp, 4;PRINTNUM呼び出し引数スタック除去
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess;
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
while文例のフローチャート
10.8. do..while文¶
do..while文はありません。しかし、ジャンプ命令とcmp命令を使って類似の記述ができます。
※参考:Javaの do while文への参照
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ; int sum
i: resd 1 ; int i
str: resb 64 ; char str[64]
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;i=1
mov [ds:i], dword 1
;sum=0
mov [ds:sum], dword 0
;do
do01:
mov eax, dword [ds:i]
add [ds:sum], dword eax
;i++
inc dword [ds:i]
cmp dword [ds:i], 10
jle do01
dowhile01:
;while(i<=10)
push dword [ds:sum]; PRINTNUM(sum)
call PRINTNUM ;=>55
sub esp, 4;PRINTNUM呼び出し引数スタック除去
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess;
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
do_while文例のフローチャート
10.9. continue文¶
continue文は無いので、ジャンプ命令、cmp命令を利用して類似の処理を行います。
※参考:Javaの continue文への参照
as_for_continue.asm
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ; int sum
i: resd 1 ; int i
str: resb 64 ; char str[64]
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
mov [ds:sum], dword 0
;for(i=1 ; i<=10 ; i++)
mov [ds:i], dword 1
for01:
cmp dword [ds:i], 10
jle then01
jmp endfor01
then01:
cmp dword [ds:i], dword 3
je continue01
mov eax, dword [ds:i]
add [ds:sum], dword eax
continue01:
;i++
inc dword [ds:i]
jmp for01
endfor01:
;end for
push dword [ds:sum]
;PRINTNUM(sum)
call PRINTNUM ;=>52
;PRINTNUM呼び出し引数スタック除去
sub esp, 4
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
continue文例のフローチャート
10.10. break文¶
break文は無いので、ジャンプ命令、cmp命令を利用して類似の処理を行います。
※参考:Javaの break文への参照
as_for_break.asm
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ; int sum
i: resd 1 ; int i
str: resb 64 ; char str[64]
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
mov [ds:sum], dword 0
;for(i=1 ; i<=10 ; i++)
mov [ds:i], dword 1
for01:
cmp dword [ds:i], 10
jle then01
jmp endfor01
then01:
mov eax, dword [ds:i]
add [ds:sum], dword eax
cmp dword [ds:sum], dword 30
jge break01
;i++
inc dword [ds:i]
jmp for01
break01:
endfor01:
;end for
push dword [ds:sum]
;PRINTNUM(sum)
call PRINTNUM ;=>36
;PRINTNUM呼び出し引数スタック除去
sub esp, 4; pop n
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess;
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
break文例のフローチャート
10.11. ラベル付きcontinue文¶
ラベル付きcontinue文は無いので、ジャンプ命令、cmp命令を利用して類似の処理を行います。
※参考:Javaの ラベルcontinue文への参照
as_for_double_continue.asm
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ; int sum
i: resd 1 ; int i
j: resd 1 ; int j
str: resb 64 ; char str[64]
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
mov [ds:sum], dword 0
;MYLABEL:for(i=1 ; i<=10 ; i++)
mov [ds:i], dword 1
for01:
cmp dword [ds:i], 10
jle then01
jmp endfor01
then01:
;for(j=1 ; j<=10 ; j++)
mov [ds:j], dword 1
for02:
cmp dword [ds:j], 10
jle then02
jmp endfor02
then02:
cmp dword [ds:i], dword 3
je continue01; continue MYLABEL
;sum = sum+i*j
mov eax, dword [ds:i]
mov ebx, dword [ds:j]
mul ebx
add [ds:sum], dword eax
;j++
inc dword [ds:j]
jmp for02
endfor02:
;end for
continue01:
;i++
inc dword [ds:i]
jmp for01
endfor01:
;end for
push dword [ds:sum]
;PRINTNUM(sum)
call PRINTNUM ;=>2860
;PRINTNUM呼び出し引数スタック除去
sub esp, 4; pop n
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess;
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
ラベル付きcontinue文例のフローチャート
10.12. ラベル付きbreak文¶
ラベル付きbreak文は無いので、ジャンプ命令、cmp命令を利用して類似の処理を行います。
※参考:Javaの ラベルbreak文への参照
as_for_double_break.asm
extern MessageBoxA
extern wsprintfA
extern ExitProcess
;定数(const)を格納するためのセクション※read only data section
section .rodata
STR_FORMAT db '%d',00H ;const char STR_FORMAT[] = "%d"
STR_TITLE db 'Message',00H ;const char STR_TITLE[] = "Message"
;非初期化データセクションを変数として使う
section .bss
sum: resd 1 ; int sum
i: resd 1 ; int i
j: resd 1 ; int j
str: resb 64 ; char str[64]
section .text
global main
main:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
mov [ds:sum], dword 0
;MYLABEL:for(i=1 ; i<=10 ; i++)
mov [ds:i], dword 1
for01:
cmp dword [ds:i], 10
jle then01
jmp endfor01
then01:
;for(j=1 ; j<=10 ; j++)
mov [ds:j], dword 1
for02:
cmp dword [ds:j], 10
jle then02
jmp endfor02
then02:
;sum = sum+i*j
mov eax, dword [ds:i]
mov ebx, dword [ds:j]
mul ebx
add [ds:sum], dword eax
cmp dword [ds:sum], dword 15
jge break01; break MYLABEL
;j++
inc dword [ds:j]
jmp for02
endfor02:
;end for
;i++
inc dword [ds:i]
jmp for01
break01:
endfor01:
;end for
push dword [ds:sum]
;PRINTNUM(sum)
call PRINTNUM ;=>15
;PRINTNUM呼び出し引数スタック除去
sub esp, 4; pop n
;Windowsプログラムの終了ではExitProcessを呼ぶ
call ExitProcess;
;プログラムの終了
;終了シーケンス
mov esp, ebp
pop ebp
ret
;メッセージボックス表示関数
PRINTNUM:
;エントリーシーケンス
push ebp
mov ebp, esp
;関数コード
;eax = 第1引数
mov eax, [ebp+8]
push dword eax
;STR_FORMAT = "%d"
push dword STR_FORMAT
;strはchar[64]
push dword str
;sprintf(str,"%d",eax)
call wsprintfA
push dword 0
push dword STR_TITLE
push dword str
push dword 0
;MessageBoxA(0,str,"Message",0)
call MessageBoxA
;終了シーケンス
mov esp, ebp
pop ebp
ret
ラベル付きbreak文例のフローチャート