# 常見匯編代碼 #
1. 編寫程序:比較AX,BX,CX中帶符號數的大小,將最大的數放在AX中
code segment
assume cs:code
mov ax,32
mov bx,74
mov cx,23
sort: cmp ax,bx
jge X ;如果ax大於等於bx就跟cx比較
xchg ax,bx
X:cmp ax,cx ;如果ax大於cx
jge Y
xchg ax,cx
Y:int 21h
mov ax,4c00h
code ends
end sort
2.要求對鍵盤輸入的小寫字母用大寫字母顯示出來
code segment
assume cs:code
start: mov ah,1
int 21h
cmp al,'a'
jz error
cmp al,'z'
ja error
sub al,20h ;'A'~'Z':41~5AH ‘a'~'z':61~7ah
mov dl,al
mov ah,2
int 21h
jmp start
error:ret
code ends
end start
3.編寫程序:從鍵盤上接收一個四位數的十進制數,並在終端上顯示出與它等值的二進制數。
code segment
assume cs:code
begin:xor bx,bx ;清空bx
mov ch,4
mov cl,4 ;設置內外層的循環次數
input:shl bx,cl ;bx中的內容邏輯左移
mov ah,1
int 21h ;輸入
cmp al,30h ;是否小於0
jb input ;是就重新輸入
cmp al,39h ;是否大於9
ja input
and al,0fh ;轉換為相應的二進制
jmp combine
combine:or bl,al
dec ch
jnz input
display:mov cx,16 ;輸出的循環次數
print:mov dl,0
rol bx,1
rcl dl,1
or dl,30h ;清空dl
mov ah,2
int 21h
loop print
ret
code ends
end begin
4.將內存ffff:0~ffff:d單元中的數據復制到0:200~0:20d單元中。
code segment
assume cs:code
mov bx,0
mov cx,0fh
copy:mov ax,0ffffh
mov ds,ax
mov dl,[bx]
mov ax,0020h
mov ds,ax
mov [bx],dl
inc bx
loop copy
mov ax,4c00h
int 21h
code ends
end copy
5.將AX寄存器中的16位數分成四組,每組四位,然后把這四組數分別放在AL、BL、CL和DL中。
data segment
s db 4 dup(?) ;占位,並清空
mov ax,0ffffh
data ends
;-----------------------------------
progrnam segment
assume cs:progrnam,ds:data
begin:mov cl,4 ;ax邏輯右移四次
mov ch,4
lea bx,s
X: mov dx,ax
and dx,0fh ;邏輯與屏蔽高位
mov [bx],dl ;以字節形式將dl移入bx
inc bx
shr ax,cl ;邏輯右移
dec ch
jnz X
Y: mov dl,s ;依次移入相應寄存器內
mov cl,s+1
mov bl,s+2
mov al,s+3
ret
progrnam ends
end begin
6.從鍵盤輸入一系列字符,以字符‘$’為結束符,然后對其中的非數字字符計數,並顯示出計數結果。
`stack segment
dw 100h dup(?)
top label word
stack ends
data segment
h1 db 'Please input a string: ','$'
h2 db 'The number of the chars that is not digit:','$'
crlf db 0dh,0ah,24h
data ends
code segment
assume cs:code,ds:data,ss:stack
main proc far
begin:mov ax,stack
mov ss,ax
lea sp,top
mov ax,data
mov ds,ax
lea dx,h1
mov ah,9
int 21h
mov cx,0
input: mov ah,1
int 21h
cmp al,'$'
jz exit
cmp al,30h
jb count
cmp al,39h
jnb count
jmp input
count: inc cx
jmp input
exit: lea dx,crlf
mov ah,9
int 21h
lea dx,h2
int 21h
mov si,0
mov bl,10
mov ax,cx
mem: div bl
mov dl,ah
mov dh,0
push dx
inc si
mov ah,0
cmp al,0
jnz mem
prin: pop dx
add dl,30h
mov ah,2
int 21h
dec si
cmp si,0
jnz prin
mov ah,4ch
int 21H
main endp
code ends
end begin
`
7.已知兩個整數變量A和B,試編寫完成下述操作的程序:
(1)若兩個數中有一個數是奇數,則將奇數存入A中,偶數存入B中
(2)若兩個數均為奇數,則兩數分別加1,並存回原變量。
(3)若兩個數均為偶數,則兩變量不變。
code segment
assume cs:code
begin: mov ax,13
mov bx,12
mov cx,ax
mov dx,bx
xor ax,bx
test ax,0001h ;A和B是否同時為奇數或偶數
jz next ;是
test bx,0001h
jz return ;B為偶數,A為奇數,加1
exchange:mov ax,dx ;A為偶數,B為奇數,交換
mov bx,cx
jmp return
next:test bx,0001h ;是否同為奇數
jz return ;同為偶數,不變
inc dx
inc cx
jmp exchange
return:ret
code ends
end begin
8.比較兩個字符串string1和string2所含的字符是否相同。若相同則顯示‘true’,否則顯示‘false’。
data segment
string1 db 'i am a student'
string2 db 'i am a student'
string3 db 'true',0dh,0ah,'$'
string4 db 'false',0dh,0ah,'$'
data ends
;--------------------------
progrnam segment
assume cs:progrnam,ds:data
start:push ds
sub ax,ax
push ax
mov ax,data
mov ds,ax
mov es,ax
begin:lea si,string1
lea di,string2
cld
mov cx,string2-string1
repe cmpsb
jne Y
lea dx,string3
jmp print
Y:lea dx,string4
print: mov ah,9
int 21h
mov ax,4c00h
int 21h
progrnam ends
end start
9.編寫無溢出除法的匯編子程序 。
這里所說的除法溢出並不是指分母為0而發生溢出的情況。我們以除數為8位的情況來說明,假設我們的被除數為65535(16位的最大值)存儲在AX 中,除數為1,存儲在CL中,然后執行除法指令: div CL。根據上面的說法,結果都是放在AX中的,余數為0,當然這沒有問題,然而商為65535要放在AL中卻是放不下的,因為AL能存放的最大值只為 255,所以此時就會發生溢出。我們可以看到65535/1 = 255,這顯然與我位正常的除法結果不符。
如何解決這個溢出問題
既然我們知道了問題的根源,要解 決它就不困難了。為了統一而且不發生溢出,我們可以把所有的除法的商都用32位來保存,即所有的被除數都用32位,所有的除數都用16位,所有的商都用 32位,所有的余數都用16位來保存,就可以解決這個問題,因為一個數除以一個整數后,不可能大於其之前的值。而對於8位的除法,除數和被除數的高位全用 0補全即可。為了達到這個目的,我們就不能使用默認的除法指令div了,而需要我們寫代碼來實現我們自定義的除法。
自定義除法: X為除數,N為被除數,H代表X的高16位,L代表X的低16位,
int(H/N)和rem(H/N)代表着H除以N的商和余數
X/N = int(H/N)* 2^16 + [rem(H/N)* 2^16+L]/N
progrnam segment
assume cs:progrnam
mov ax,0ffffh
mov cx,1 ;初始化進行測試
begin: cmp cx,0
je return ;除數不能為0
push bx
push ax
mov ax,dx
mov dx,0
div cx ;執行H/N,商保存在ax中,余數在DX中
mov bx,ax ;把商保存
pop ax ;取出低位,執行rem(H/N)*2^16+L
div cx ;執行[rem(H/N)*2^16+L]/N ,商保存在ax中 ,余數在dx中
mov cx,dx ;cx保存余數
mov dx,bx ;dx中保存高位除法的商
pop bx
return:ret
mov ax,4c00h
int 21h
progrnam ends
end begin
10.編寫一個程序,接受從鍵盤輸入的10個十進制數字,輸入回車符則停止輸入,然后將這些數字加密后(用XLAT指令變換)存入內存緩沖區BUFFER。加密表為:
輸入數字:0,1,2,3,4,5,6,7,8,9
密碼數字:7,5,9,1,3,6,8,0,2,4
data segment
number db 7,5,9,1,3,6,8,0,2,4
buffer db 10 dup(?)
data ends
;-------------------------------------
code segment
assume cs:code,ds:data
mov si,0
mov cx,10
lea bx,number
input:mov ah,1
int 21h
cmp al,0dh ;是否為回車符
jz return
cmp al,30h ;比較是否是0~9,不是就重新輸入
jb input
cmp al,39h
ja input
xlat ;變換進行存儲
mov buffer[si],al
inc si
loop input
return:ret
code ends
end input
data segment
number db 7,5,9,1,3,6,8,0,2,4
buffer db 10 dup(?)
data ends
;-------------------------------------
code segment
assume cs:code,ds:data
mov si,0
mov cx,10
lea bx,number
input:mov ah,1
int 21h
cmp al,0dh ;是否為回車符
jz return
cmp al,30h ;比較是否是0~9,不是就重新輸入
jb input
cmp al,39h
ja input
xlat ;變換進行存儲
mov buffer[si],al
inc si
loop input
return:ret
code ends
end input
11.編寫一個子程序嵌套結構的程序模塊,分別從鍵盤輸入姓名及8個字符的電話號碼,並以一定的格式顯示出來。
主程序TELIST:
A. 顯示提示符“INPUT NAME:”;
B. 調用子程序INPUT_NAME輸入姓名;
C. 顯示提示符“INPUT A TELEPHONE NUMBER:”;
D. 調用子程序INPHONE輸入電話號碼;
E. 調用子程序PRINTLINE顯示姓名及電話號碼。
子程序INPUT_NAME:
A. 調用鍵盤輸入子程序GETCHAR,把輸入的姓名存放在INBUF緩沖區中;
B. 把INBUF中的姓名移入輸出行OUTNAME。
子程序INPHONE:
A. 調用鍵盤輸入子程序GETCHAR,把輸入的8位電話號碼存放在INBUF緩沖區中;
B. 把INBUF中的號碼移入輸出行OUTPHONE。
子程序PRINTLINE:
顯示姓名及電話號碼,格式為:
NAME TEL.
X X X XXXXXXXX
代碼如下:
data segment
tipname db 'input name:','$'
tipnumber db 'input a telephone number:','$'
inbuf db 12 dup(' ')
crlf db 0dh,0ah,'$'
outname db 16 dup(' ')
outphone db 12 dup(' '),0dh,0ah,'$'
info db 'name',12 dup(' '),'tel',0dh,0ah,'$'
data ends
;------------------------------------
stack segment
dw 100 dup(?) ;偽定義使得同一個變量具有不同的屬性
string label word
stack ends
;----------------------------------------
progrnam segment
main proc far
assume cs:progrnam,ds:data,es:data,ss:stack
start:mov ax,stack
mov ss,ax
mov sp,offset string
push ds
xor ax,ax
push ax
mov ax,data
mov ds,ax
mov es,ax
begin:
mov ah,09 ;輸出提示字符串
mov dx,seg tipname
mov ds,dx
mov dx,offset tipname
int 21h
call input_name ;輸入姓名
mov ah,09 ;輸出提示字符串
mov dx,seg tipnumber
mov ds,dx
mov dx,offset tipnumber
int 21h
call input_number
call printline
ret
main endp
;------------------------------------------
input_name proc near
call getchar
lea si,inbuf
lea di,outname
mov cx,12 ;設置計數器
cld ;設置方向為自增
;movsb 與rep結合是傳送字節,相當於 movs es:byte ptr[di],ds:[si]
rep movsb
ret
input_name endp
;-----------------------------------------------
input_number proc near
call getchar
lea si,inbuf
lea di,outphone
mov cx,12
cld
rep movsb
ret
input_number endp
;------------------------------------------------
getchar proc near
mov al,20h
mov cx,12
lea di,inbuf
cld
;stosb這里是為了每一次輸入一個字節存入相應的緩沖區
rep stosb
mov cx,12
mov di,0
input:mov ah,1
int 21h
cmp al,0dh
jz return
mov inbuf[di],al
inc di
loop input
return: call disp_crlf ;輸出回車符
ret
getchar endp
;--------------------------------------
printline proc near ;這里均是將所得的字符串進行輸出
mov ah,09
mov dx,seg info
mov ds,dx
mov dx,offset info
int 21h
mov ah,09
mov dx,seg outname
mov ds,dx
mov dx,offset outname
int 21h
ret
printline endp
;---------------------------------------
disp_crlf proc near
mov ah,09
mov dx,seg crlf
mov ds,dx
mov dx,offset crlf
int 21h
ret
disp_crlf endp
;-----------------------------------------
progrnam ends
end start
12.試編寫一個匯編語言子程序,要求將包含任意字符、以0結尾的字符串中的小寫字母轉換成大寫字母。
data segment
string db 'i am A stuDEnt',0h
data ends
;------------------------------
progrnam segment
assume ds:data,cs:progrnam
start:push ds
xor ax,ax
mov ax,data
mov ds,ax
lea si,string
push si
begin: mov al,[si] ;判斷是否為小寫字母並進行轉換
cmp al,0
je return
cmp al,'a'
jb print
cmp al,'z'
ja print ;如果不是小寫字母直接進行輸出
sub al,20h
mov [si],al
print:push ds ;將字母進行輸出
;mov al,[si]
mov dl,al
mov ah,2
int 21h
pop ds
n:inc si
jmp begin
return:
pop si
pop ds
mov ax,4c00h
int 21h
progrnam ends
end start
13.編寫程序,將一個包含有20個數據的數組M分成兩個數組:正數數組P和負數數組N,並分別把這兩個數組中數據的個數顯示出來。
data segment
string1 db 0dh,0ah, 'positive number:','$'
string2 db 0dh,0ah,'negative number:','$'
array dw 1,2,3,4,5,6,7,8,-4,-8,-9,-6,-2,-8,8,12,18,-12,5,64
array1 dw 20 dup(?) ;存儲正數數組
array2 dw 20 dup(?) ;存儲負數數組
count1 db 0
count2 db 0 ;計數
CRLF DB 0dh,0ah,'$'
data ends
;----------------------------------
progrnam segment
main proc far
assume ds:data,cs:progrnam
s: push ds
xor ax,ax
push ax
mov ax,data
mov ds,ax
begin:mov cx,20 ;循環次數
lea bx,array ;bx相當於數組的首地址
lea si,array1
lea di,array2
start:mov ax,[bx]
cmp ax,0 ;是否為負數
js Y ;是負數
mov [si],ax ;存入正數數組
inc count1
add si,2
jmp short next
Y: mov [di],ax
inc count2
add di,2
next:add bx,2
loop start
lea dx,string1
mov al,count1
call print
lea dx,string2
mov al,count2
call print
ret
main endp
;--------------------------------------
print proc near
push ax ;al中存儲計數值,要進行保存
mov ah,9
int 21h
pop ax ;出棧,進行ASCII碼調整
aam ;調整方式AH<-AL/10(商),AL<-AL%10
push ax
add ah,30h ;變為0~9的ASCII碼
mov dl,ah
mov ah,2
int 21h
pop ax
add al,30h
mov dl,al
mov ah,2
int 21h
lea dx,CRLF
mov ah,9
int 21h
ret
print endp
progrnam ends
end s
14.設有10個學生的成績分別是76,69,84,90,73,88,99,63,100和80分。試編制一個子程序統計60~69分,70~79分,80~89分,90~99分和100分的人數,分別存放到S6,S7,S8,S9和S10單元中。
data segment
grade dw 76,69,84,90,73,88,99,63,100,80
count1 dw 0
count2 dw 0
count3 dw 0
count4 dw 0
count5 dw 0
data ends
;-----------------------------------------
progrnam segment
assume ds:data,cs:progrnam
push ds
xor ax,ax
push ax
mov ax,data
mov ds,ax
begin:mov cx,10
mov si,0
next:mov ax,grade[si]
mov bx,10
div bl
mov bl,al
sub bx,6
sal bx,1 ;將(grade/10-6)×2就是
inc count1[bx] ;count1是首地址
add si,2
loop next
progrnam ends
end begin
15.輸出空行
progrnam segment
assume cs:progrnam
begin:push cx
push dx
mov ax,3 ;這里對ax進行賦值,觀察輸出的結果
mov cx,ax
print:mov dl,0dh
mov ah,2 ;這是對與輸出一個字符的bios的調用
int 21h ;print的功能就是輸出空行,0dh為回車
mov dl,0ah ;0ah為換行
mov ah,2
int 21h
loop print
pop dx
pop cx
;這一段程序是為了測試輸出后的結果,主要母的是輸出一個黃色的'*'
mov ah,9
mov al,'*'
mov bh,0
mov bl,0eh
mov cx,1
int 10h
ret
progrnam ends
end begin