仅以此文记录我在Centos
上使用DosBox
写8086汇编小程序,不知为何DosBox
总是会将我当前用户Logout
,然后我必须重新登录的艰苦岁月……
1:HelloWorld
DATA SEGMENT
str db 'Hello World$' ;要输出的字符串必须要以$结尾
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA ;将CS和CODE,DS和DATA段建立联系
START:
MOV BX,DATA
MOV DS,BX
LEA DX,str
MOV AH,9
INT 21H
MOV AH,4CH ;将控制权返回给终端。
INT 21H
CODE ENDS
END START
备注:
1:
MOV BX,DATA
MOV DS,BX
将数据段的值给DS寄存器,但是不能直接 MOV DS,DATA,因为mov操作中不允许将立即数给DS。
2:LEA指令:将源操作数的地址移入目的操作数。
LEA BX,Buffer
源操作数:必须是一个存储器操作数
目的操作数:16位通用寄存器
3:mov AH,9 ;使用9号系统调用从DX中读取字符串输出
int 21H; 产生系统中断。
2:从键盘输入两个一位十进制数,计算两个数之和,并将结果在屏幕上显示出来。
DATA SEGMENT
INFOR1 DB 'Please Input the First Data(<10):$'
INFOR2 DB 0AH,0DH,'Please Input the Second Data(<10):$' ; 0A 是 '\n' 0D 是 '\r',回车换行
INFOR3 DB 0AH,0DH,'The Result is:$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
LEA DX,INFOR1 ;输出第一条提示语句
MOV AH,09H
INT 21H
MOV AH,01H ;1号系统调用将字符输入至AL中。
INT 21H
SUB AL,30H ;输入的位ASCII码,所以减去48
MOV BL,AL
LEA DX,INFOR2
MOV AH,09H
INT 21H
MOV AH,01H
INT 21H
SUB AL,30H
XOR AH,AH ;将AH清空
ADD AL,BL
AAA ;加法ASCII码调整指令
PUSH AX
LEA DX,INFOR3
MOV AH,09H
INT 21H
POP AX
PUSH AX
MOV DL,AH
ADD DL,30H ;计算结束之后加上48输出。
MOV AH,02H ;2号系统调用,输出单个字符,在汇编中想输出数字只能单个ASCII码的输出。
INT 21H
POP AX
MOV DL,AL
ADD DL,30H
MOV AH,02H
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END START
备注:
1: AAA指令:加法ASCII码调整指令。
MOV AX,0007H ;AL=07H AH=00H
MOV BL,08H ;BL=08H
ADD AL,BL ;AL=0FH
AAA ;AL=05H AH=01H
3:编写一段程序比较两个字符串是否相同,相同输出MATCH!
,不相同输出NO MATCH!
。
思路:
- 先计算两个串长度,如果不同直接退出,相同执行第2步
- 挨个比较字符是否相同,若有不相同结束,直到比较结束全部相同
- 输出match
DATA SEGMENT
STR1 DB 'ABCDEFG$'
N EQU $-STR1 ;给N赋值,$表示当前指令的地址,$-STR1表示当前位置到STR1头部的距离,也就是STR1的长度。
STR2 DB 'BCDEFG$'
M EQU $-STR2
MESS DB 'NO MATCH!$'
RIGHT DB 'MATCH!$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA
BEGIN:
MOV AX,DATA
MOV DS,AX
MOV AX,DATA
MOV ES,AX
MOV AL,N
CMP AL,M ;比较长度是否相等,相等ZF=0,否则ZF=1
JNZ EXIT ;JNZ:jump if not zero ,zero 指的是比较结果,而不是ZF标志位的值
LEA SI,STR1
LEA DI,STR2
MOV CL,N
MOV CH,0
CLD
REPE CMPSB ;挨个比较单个字符,如果有一个不等就跳EXIT
JNZ EXIT
LEA DX,RIGHT
JMP OUT1
EXIT:
LEA DX,MESS
OUT1:
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END BEGIN
备注:
1:CMP指令:
不影响两个操作数的原大小,影响的是状态标志位,如果相等,ZF=1。否则ZF=0
2:JNZ指令的逻辑写出来就是下面这样
JNZ(ZF == 0) {
//如果ZF == 0 ,则跳转
}
//如果ZF == 1,则不跳转
4:汇编读写文件
输入原文件名->将文件读入预先定义好的缓冲区->输入新的文件名->将缓冲区的内容写入新文件。
(这部分代码是马辉完成的,我们共同做的汇编程序大赛http://blog.csdn.net/yangbodong22011/article/details/53716225,他负责文件读写部分,我负责加密解密算法部分)
data segment
filePath db 20,?,20 dup(?);存储原文件名称
newFilePath db 10,?,10 dup(?),00 ;存储加密或者解密的文件的路径
fileHandle db 2 dup(?);存储文件代号
fileBuffer db 10000 dup(?);文件缓冲区
fileInputTip db 'please input source file path:$';提示源文件路径
newFileInputTip db 'please input new file path:$';提示新文件路径
openErrorTip db 'open file error !!$';提示打开文件失败
readErrorTip db 'read file error !!$' ;提示读文件失败
fileCount db ? ;定义实际读取的字节数
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
call openFile ;打开文件
call readFile ;将文件读至缓冲区
call closeFile ;关闭文件
call createFile ;创建新文件
call writeFile ;写文件
call closeFile ;关闭文件
call returnDos ;返回DOS
;***************
;打开文件
openFile proc near
;9号功能调用,提示输入文件名
mov dx,offset fileInputTip
mov ah,9
int 21h
;10号功能调用,将文件名存储在filePath中
mov dx,offset filePath
mov ah,10
int 21h
;换行处理
call nextLine
;取得键盘上输入的实际的个数
lea bx,filePath+1
; 清空cx
xor cx,cx
;将键盘上实际输入的个数送给cx
mov cl,[bx]
;取得文件实际的存储路径
lea bx,filePath+2
;处理enter的ascall码
call findEnter
;系统调用,打开文件
mov ah,3dh
mov al,00
lea dx,filePath+2
int 21h
; 若CF为1,打开失败
jc openError
;若CF为0,打开成功,获取返回的ax中的文件代号
jmp getFileHandle
getFileHandle:
;取得fileHandle的地址空间
lea bx,fileHandle
;将文件代号保存在fileHandle中
mov [bx],ax
ret
openError:
;9号功能调用,提示打开文件失败
mov dx,offset openErrorTip
mov ah,9
int 21h
;返回dos
call returnDos
ret
openFile endp
;***************
;***************
;读文件
readFile proc near
;系统调用,读文件
mov ah,3fh
lea si,fileHandle
mov bx,[si]
mov cx,10000
lea dx,fileBuffer
int 21h
;cf=1,读文件失败,cf=0,读文件成功
;提示读取文件失败
jc readError
jmp getFileCount
getFileCount:
;将实际读取的字节数放在fileCount中
lea bx,fileCount
mov [bx],ax
ret
readError:
;9号功能调用,提示读文件失败
mov dx,offset readErrorTip
mov ah,9
int 21h
;返回dos
call returnDos
ret
readFile endp
;***************
;***************
;换行处理
nextLine proc near
mov dl,0dh
mov ah,2
int 21h
mov dl,0ah
mov ah,2
int 21h
ret
nextLine endp
;***************
;***************
;将回车所占的地址空间的值设为00h
findEnter proc near
next1:
inc bx
loop next1
mov al,00h
mov [bx],al
ret
findEnter endp
;***************
;***************
;返回dos
returnDos proc near
mov ah,4ch
int 21h
ret
returnDos endp
;***************
;***************
;关闭文件
closeFile proc near
mov ah,3eh
int 21h
ret
closeFile endp
;***************
;***************
;创建文件,cf=0,返回文件代号,保存在ax中;cf=1,创建失败
createFile proc near
create:
;9号功能调用,提示输入新的文件名加路径
mov dx,offset newFileInputTip
mov ah,9
int 21h
;10号功能调用,将新文件名艺伎路径保存在newFilePath中
mov dx,offset newFilePath
mov ah,10
int 21h
;换行处理
call nextLine
;取得newFilePath缓冲区中实际输入的字符的个数
lea bx,newFilePath+1
;清空cx
xor cx,cx
;将newFilePath缓冲区实际存储的个数送给cx
mov cl,[bx]
;判断是否输入
cmp cx,00h
;如果输入的不为空,则跳转continue
jnz continue
;如果输入的为空,则重新输入
jmp create
continue:
;取得实际的存储路径
lea bx,newFilePath+2
;处理enter的ascall码
call findEnter
;系统调用,创建文件
mov ah,3ch
mov cx,00
lea dx,newFilePath+2
int 21h
; 将文件代号保存在fileHandle中
lea si,fileHandle
mov [si],ax
ret
createFile endp
;***************
;***************
;向文件写数据
writeFile proc near
;系统调用,写文件
mov ah,40h
lea si,fileHandle
mov bx,[si]
lea di,fileCount
mov cx,[di]
lea dx,fileBuffer
int 21h
ret
writeFile endp
;***************
code ends
end start
5:汇编生成随机数
8086 定时器模式生成随机数
;***************
;获取随机数 范围1-8
getRand:
xor al,al
mov ax, 0h; 间隔定时器
out 43h,al; 将0送到43h端口
in al, 40h; 将40h端口的数据送至al
mov bl, 8 ;除8 得到范围为0-7
div bl
mov al, ah
mov ah, 0
inc al ; 加1 得到范围为1-8
ret
;***************
6:汇编生成1-N共N位不重复随机数
例如生成1-8不重复的序列,比如 12435786
或者43256718
,结合上面生成随机数的程序完成如下。
;***************
;创建随机数并存入文件
createRandNum:
lea si,randNum1 ;randNum1是保存随机数串的字符串
mov cx,8 ;设定需要产生的个数
doRand:
push cx
createRandNumdo1: ;循环产生
call getRand ;获得一个随机数
xor di,di
xor cx,cx
lea di,randNum1
mov cx,8
createRandNumdo2: ;将新产生的数字和已经保存的比对
mov bh,[di]
cmp bh,al
jz createRandNumdo1 ;如果出现重复就继续产生
inc di
loop createRandNumdo2
mov bh,RandNum[0] ;保存目前一共产生的随机数个数
add bh,1
mov RandNum[0],bh
cmp bh,9 ;如果为Num+1 就结束
jz mRet
mov [si],al
inc si
pop cx
loop doRand
;***************
;获取随机数 范围1-8
getRand:
xor al,al
mov ax, 0h; 间隔定时器
out 43h,al; 将0送到43h端口
in al, 40h; 将40h端口的数据送至al
mov bl, 8 ;除8 得到范围为0-7
div bl
mov al, ah
mov ah, 0
inc al ; 加1 得到范围为1-8
ret
;***************
7:将一个db类型的每一位取出来保存进一个8个db大小的字符串。
例如 A
的二进制是01000001
我们将它每一位分别保存进一个db,得到0
1
0
0
0
0
0
1
,将其保存入temp1
fetchBinary:
xor dx,dx;
lea si,temp1
mov dl,[bx]
mov dh,dl;
and dh,10000000B ;先拿出最高位是不是1
cmp dh,00H ;如果为0
jz _1
mov dh,01h ;如果不为0就置为1
_1:
mov [si],dh ;将dh的值也就是0给[si]
inc si
mov dh,dl
and dh,01000000B
cmp dh,00H
jz _2
mov dh,01H
_2:
mov [si],dh
inc si
mov dh,dl
and dh,00100000B
cmp dh,0
jz _3
mov dh,01H
_3:
mov [si],dh
inc si
mov dh,dl
and dh,00010000B
cmp dh,00H
jz _4
mov dh,01h
_4:
mov [si],dh
inc si
mov dh,dl
and dh,00001000B
cmp dh,00H
jz _5
mov dh,01h
_5:
mov [si],dh
inc si
mov dh,dl
and dh,00000100B
cmp dh,00H
jz _6
mov dh,01h
_6:
mov [si],dh
inc si
mov dh,dl
and dh,00000010B
cmp dh,00H
jz _7
mov dh,01h
_7:
mov [si],dh
inc si
mov dh,dl
and dh,00000001B
cmp dh,00H
jz _8
mov dh,01h
_8:
mov [si],dh
ret
;***************