アセンブリ言語のcmp命令

アセンブリ言語のcmp命令は、次の命令とセットになってある場所にジャンプするものと思ってないか。

例えば、

cmp dl,dh

je yes

は、"cmp dl,dh"は次の"je yes"とセットになって「dlの数値とdhの数値が同じであればyesという所にジャンプする」命令と思ってないか。

それは違う。"cmp dl,dh"はdlの数値とdhの数値とを比較しその結果をある所に格納するものであり、je yesはある所に格納されている結果がイコールであればyesにジャンプするものである。

なので、"cmp dl,dh"と"je yes"との間に好きな命令を挟むことができる。

 

 

そんなcmp命令を利用したアセンブリ言語プログラムがこれ。

 

bits 16
org 0x100

;Aの数値を入力
mov ah,9
mov dx,msg1
int 21h
mov ah,8
int 21h
mov ah,02
mov dl,al
int 21h
mov ch,al
mov al,0
mov ah,9
mov dx,crlf
int 21h

;Bの数値を入力
mov ah,9
mov dx,msg2
int 21h
mov ah,8
int 21h
mov ah,02
mov dl,al
int 21h
mov cl,al
mov al,0
mov ah,9
mov dx,crlf
int 21h

;AとBの数値の比較
sub cx,3030h   ;cxレジスタ内の各数字をそれぞれ数値に
cmp ch,cl   ;ch内の数値(A)とcl内の数値(B)を比較
mov ah,9
mov dx,msg3
int 21h
mov dx,crlf
int 21h

;AはBよりも?
jg more   ;大きければmoreへ
jl less   ;小さければlessへ

;AとBが等しい場合
mov ah,9
mov dx,msg6
int 21h
jmp exit

;AとBが等しくない場合
more:
mov ah,9
mov dx,msg4
int 21h
jmp exit
less:
mov ah,9
mov dx,msg5
int 21h

;プログラム終了シーケンス
exit:
mov ah,4Ch
mov al,0
int 21h

;文字列データ群
msg1 db "A:$"
msg2 db "B:$"
msg3 db "A and B were compared.$"
msg4 db "A>B$"
msg5 db "A<B$"
msg6 db "A=B$"
crlf db 0dh,0ah,"$"   ;改行用

 

Aに入力できる数値とBに入力できる数値はそれぞれ1桁の10進数のみ。

Aの数値とBの数値をcmp命令で比較した後、"A and B were compared."という文字列が出る。

その後、そのcmp命令での比較の結果に応じた出力がされる("A>B"と"A<B"と"A=B"のいずれかが画面に出る)。

割り算の答えを帯分数で表すアセンブリ言語プログラム

bits 16
org 0x100

mov ah,08h
int 21h
mov cl,al

mov ah,02
mov dl,cl
int 21h

mov ah,02
mov dl,'/'
int 21h

mov ah,08h
int 21h
mov ch,al

mov ah,02
mov dl,ch
int 21h

push cx
sub cx,3030h

mov ax,0
mov al,cl
mov cl,ch
mov ch,0
div cl

mov cx,ax
mov ax,0

cmp ch,0
jne tai


mov ah,9
mov dx,crlf
int 21h
mov ah,02

mov dl,'='
int 21h

add cl,30h
mov dl,cl
int 21h

jmp exit


tai:
mov ah,9
mov dx,crlf
int 21h
mov ah,02
mov dl,' '
int 21h

add ch,30h
mov dl,ch
int 21h

mov ah,9
mov dx,crlf
int 21h
mov ah,02

add cl,30h
mov dl,cl
int 21h

mov dl,'-'
int 21h

mov ah,9
mov dx,crlf
int 21h
mov ah,02
mov dl,' '
int 21h

pop cx
mov dl,ch
int 21h


exit:
mov ah,4Ch
mov al,0
int 21h


crlf db 0dh,0ah,"$"

 

入力できるのは1ケタの10進数のみ。

某フリー画像をアプリにすると?

このフリー画像を「BINファイル」にして逆アセンブルしたやつの一部がこれ(全部だとすごく長いから)。

000770C0  0821              or [bx+di],ah
000770C2  8410              test [bx+si],dl
000770C4  42                inc dx
000770C5  0821              or [bx+di],ah
000770C7  8410              test [bx+si],dl
000770C9  42                inc dx
000770CA  C88B81FF          enter 0x818b,0xff
000770CE  0F792B            vmwrite ebp,dword [bp+di]
000770D1  B5FC              mov ch,0xfc
000770D3  9C                pushf
000770D4  F0EC              lock in al,dx
000770D6  CD00              int 0x0
000770D8  0000              add [bx+si],al
000770DA  004945            add [bx+di+0x45],cl
000770DD  4E                dec si
000770DE  44                inc sp
000770DF  AE                scasb
000770E0  42                inc dx
000770E1  60                pusha
000770E2  82                db 0x82

そして本フリー画像を拡張子をcomにしたやつを「DOSBox 0.74-3」上で起動すると?

「DOSBox 0.74-3」の画面が消えた!

そう、本フリー画像は「DOSBox 0.74-3」を閉じる(シャットダウン)アプリになるのである。

素数判定プログラムのアセンブリ言語コード

bits 16
org 100h

mov ah,0ah
mov dx,buf
mov byte [buf],20h
int 21h

mov dx,crlf
mov ah,09h
int 21h

mov dl,[buf+1]
cmp dl,1h
je one_digit
cmp dl,2h
je two_digits

jmp exit

one_digit:
mov dl,[buf+2]
sub dl,30h
jmp prime_judge

two_digits:
mov ax,[buf+2]
sub ax,30h
mov cx,0ah
mul cx
mov dx,ax
mov ax,[buf+3]
sub ax,30h
add dl,al


prime_judge:
mov ax,0
mov cx,0
mov cl,dl
cmp cl,0
je no
dec cl
cmp cl,0
je no

search:
mov ax,0
cmp cl,1
je yes
mov al,dl
div cl
cmp ah,0
je no
loop search

yes:
mov ax,0
mov ah,9
mov dx,msg1
int 21h
jmp exit

no:
mov ax,0
mov ah,9
mov dx,msg2
int 21h


exit:
mov ah,4Ch
mov al,0
int 21h


buf db " $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"
crlf db 0dh,0ah,"$"
msg1 db "It is a prime.$"
msg2 db "It is not a prime.$"

 

入力できるのは1桁の数値と2桁の数値だけで、入力した数値が素数なら"It is a prime."という文字列が出、入力した数値が素数でなければ"It is not a prime."という文字列が出る。

擬似命令dbにより文字列のデータが存在するアセンブリ言語プログラムを逆アセンブルすると?

bits 16
org 0x100

mov ah,9
mov dx,msg
int 21h

mov ah,4Ch
mov al,0
int 21h

msg db "Hello.$"

 

これをアセンブルしたやつを逆アセンブルすると、

 

00000000  B409              mov ah,0x9
00000002  BA0D01            mov dx,0x10d
00000005  CD21              int 0x21
00000007  B44C              mov ah,0x4c
00000009  B000              mov al,0x0
0000000B  CD21              int 0x21
0000000D  48                dec ax
0000000E  656C              gs insb
00000010  6C                insb
00000011  6F                outsw
00000012  2E                cs
00000013  24                db 0x24

 

になる。

 

最初の"bits 16"と"org 0x100"が消されているのは良い。何とも合理的だ。

問題は文字列のデータの部分。

アドレスDにおける"dec ax"はHを意味し、アドレスEとアドレスFにおける"gs insb"はelを意味し、アドレス10における"insb"はlを意味し、アドレス11における"outsw"はoを意味し、アドレス12における"cs"は.を意味し、アドレス13における"db 0x24"は$を意味する。

アセンブルすれば文字列が命令として扱われるのだ。

奇妙なアセンブル

Hello.
I'm fine, thank you.
And you?

 

というテキストをBINファイルにして逆アセンブルすると、

 

dec ax
gs insb
insb
outsw
cs or ax,0x490a
daa
insw
and [bp+0x69],ah
outsb
gs sub al,0x20
jz 0x7c
popa
outsb
imul sp,[bx+si],byte +0x79
outsw
jnz 0x4a
or ax,0x410a
outsb
and [fs:bx+di+0x6f],bh
jnz 0x65

 

になる。

 

そしてそれをアセンブルしてプログラムとして実行すると…?

そのプログラム、終わらない!