x86汇编代码记录

一、汇编代码如何执行

  1. 编译 masm a.asm
  2. 链接 link a.obj
  3. 执行 a.exe

二、编码注意事项

  1. 写函数时,用到的寄存器,最好不要破坏原有的值,所以一般把用到的寄存器先push,退出函数前再按相反的顺序pop出来。
fun1 proc near
	push ax
	push bx

	;使用ax,bx做一些操作
	
	pop bx
	pop ax
	ret
fun1 endp

三、汇编练习代码

  1. 设计程序。实现Y=2X+3,X是一位十进制数。要求X从键盘输入,在下一行上显示’Y=2X+3=’ 以及十进制计算结果。
.model small
.data
	mess1 db 'input x:','$'		;输出字符串要以$结尾
	mess2 db 0ah,0dh,'y=2x+3=$'	;0ah,0dh就是回车换行
.stack 100h
.code
start:
	mov ax,@data
	mov ds,ax

	mov dx,offset mess1
	mov ah,9
	int 21h
	
	mov ah,1
	int 21h
	sub al,30h
	shl al,1
	add al,3
	mov ah,0
	mov bl,10
	div bl
	add ax,3030h
	mov bx,ax

	mov dx,offset mess2
	mov ah,9
	int 21h
	
	mov ah,2
	mov dl,bl
	int 21h
	mov dl,bh
	int 21h
	
	mov ah,4ch
	int 21h
end start 

  1. 计算 Y=5X-18,如果结果为负,求绝对值。并显示十进制结果。
.model small
.data
mess1 db 'input string:','$'
buffer db 64,?,64 dup(?)		;字符串缓冲区
crlf db 0ah,0dh,'output:$'				;回车换行,字符串要以$结尾

.code
start:
	mov ax,@data
	mov ds,ax

	lea dx,mess1
	mov ah,09h
	int 21h

	;输入字符串
	mov dx,offset buffer
	mov ah,0ah
	int 21h

	mov si,1
	mov al,buffer[si]	
	add al,2
	mov ah,0
	mov si,ax
	mov buffer[si],24h			;在字符串最后面加上$

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

	mov ah,9 
	mov dx,offset buffer
	int 21h


	mov ah,4ch
	int 21h

end start
  1. 从键盘输入一串字符,如果是数字存入NUMB单元,如果是字母,将大写字母存入CAPI单元,小写字母存入LETT单元,分别统计个数,输入回车时退出。
.model small

.data
	numb db 10 dup(?)
	capi db 10 dup(?)
	lett db 10 dup(?)

	numbCount dw ?
	capiCount dw ?
	lettCount dw ?

	mess1 db 'input string:$'
	mess2 db 'number count is:$'
	mess3 db 'capital count is:$'
	mess4 db 'lower letter count is:$'
	

.stack 100h

.code 

;回车换行函数
crlf proc near
	mov ah,2
	mov dl,0ah
	int 21h
	mov dl,0dh
	int 21h
	ret
crlf endp

;自然数十进制输出,数字需要放在bx中
printNum proc near
	mov ax,bx
	mov bx,10
	mov cx,0

cal:
	mov dx,0
	div bx

	push dx
	inc cx

	cmp ax,0
	ja	cal

print:
	pop dx
	add dl,30h
	mov ah,2
	int 21h

	dec cx
	cmp cx,0

	ja print
	
	ret
printNum endp


start:
	mov ax,@data
	mov ds,ax

	mov dx,offset mess1
	mov ah,9
	int 21h

	mov di,0	;保存数字的个数
	mov si,0	;保存大写字母的个数
	mov bx,0	;保存小写字母的个数

input:
	;开始输入字符
	mov ah,1
	int 21h
	cmp al,0dh	;回车
	jz exit
	test al,40h	;区分数字和字母
	jz number
	test al,20h	;区分大小写
	jz capital

lower:
	cmp al,'z'	;排除大于小写字母的字符
	ja input
	mov lett[bx],al
	inc bx

capital:
	cmp al,'Z'	;排除大小写字母之间的字符
	ja input
	cmp al,'A'	;排除大写字母和数字之间的字符
	jb input
	mov capi[si],al
	inc si


number:
	cmp al,'0'		;排除其他字符
	jl input	
	cmp al,'9'
	ja input
	mov numb[di],al
	inc di
	jmp input


exit:
	mov numbCount,di
	mov capiCount,si
	mov lettCount,bx

	;打印数字的个数
	call crlf
	mov ah,9
	mov dx,offset mess2
	int 21h
	mov bx,numbCount
	call printNum

	;打印大写字母的个数
	call crlf
	mov ah,9
	mov dx,offset mess3
	int 21h
	mov bx,capiCount
	call printNum

	;打印小写字母的个数
	call crlf
	mov ah,9
	mov dx,offset mess4
	int 21h
	mov bx,lettCount
	call printNum

	mov ah,4ch
	int 21h

end start

  1. 用查表和循环左移的方式显示十六进制
.model small
.data 
	x dw 23d4h,0029h
	count db 2
	hex db '0123456789ABCDEF'		;十六进制数码表
	mess db 0ah,0dh,'hex=$'

.stack 100h

.code 

;回车换行函数
crlf proc near
	mov ah,2
	mov dl,0ah
	int 21h
	mov dl,0dh
	int 21h
	ret
crlf endp

;十六进制输出,将数值放在bx里面
printHex proc near
	mov ch,4		;循环左移4次
	mov cl,4		;循环左移,每次左移4位

tag:
	rol bx,cl
	mov di,bx
	and di,000fh
	mov dl,hex[di]
	mov ah,2
	int 21h

	dec ch
	cmp ch,0
	ja tag

	ret
printHex endp 

start:

	mov ax,@data
	mov ds,ax

	mov bx,x[0]
	call printHex

	call crlf

	mov bx,x[2]
	call printHex

	mov ah,4ch
	int 21h
end start

  1. 串传送
data segment
    str1 db '1234567890'
data ends
extra segment
    str2 db 10 dup(?)
extra ends
code segment
    assume cs:code,ds:data,es:extra
start:
    mov ax,data
    mov ds,ax
    mov ax,extra
    mov es,ax

    lea si,str1         ;源串首地址
    lea di,str2         ;目的串首地址
    cld                 ;方向标志清0
    mov cx,10
    rep movsb           ;以字节形式重复传送CX次

    mov ah,4ch
    int 21h
code ends
end start
  1. 比较两个字串
data segment
	str1 db 'student'
	str2 db 'stuDent'
data ends
code segment
assume cs:code,ds:data
start:
	mov ax,data
	mov ds,ax
	
	lea si,str1
	lea di,str2
	cld
	mov cx,7
	repe cmpsb 		;repe重复串操作指令,每重复一次CX的值就减一,一直到CX为0或ZF为0时停止。 cmpsb是字符串比较指令,把ESI指向的数据与EDI指向的数一个一个的进行比较。
	
	jz yes
	mov dl,'n'
	jmp print
yes:
	mov dl,'y'
print:
	mov ah,2
	int 21h
	mov ax,4c00h
	int 21h

code ends
end start
  1. 将字数组按升序排序(冒泡排序)
data segment
	part dw 15,32,6,-27,8
	sign dw ?
data ends

code segment
	assume cs:code,ds:data
start:
	mov ax,data
	mov ds,ax
	
	mov cx,sign-part		;数组长度
	shr cx,1				;shr逻辑右移,元素个数
	dec cx
loop1:						;外循环
	push cx 
	mov bx,0
loop2:						;内循环
	mov ax,part[bx]
	cmp ax,part[bx+2]
	jle next
	xchg ax,part[bx+2]		;交换
	mov part[bx],ax
next:
	add bx,2
	loop loop2

	pop cx					;恢复外循环次数
	loop loop1

	mov ah,4ch
	int 21h
code ends
end start
  1. 分别求两个数组ARRAY1和ARRAY2的正数累加和。累加和分别放在TOTAL1和TOTAL2中,最后打印和。
;分别求两个数组ARRAY1和ARRAY2的正数累加和。累加和分别放在TOTAL1和TOTAL2中。最后打印和
data segment 
    array1 dw 3,2,-5,8,-7
    array2 dw 4,-1,5,6,2
    total1 dw ?
    total2 dw ?
    m dw 5
data ends

code segment
	assume cs:code, ds:data

;求和函数
getSum proc near
	push cx			;通过push、pop保存cx的值

	mov bx,0
	mov ax,0

	loop1:
		cmp word ptr[bx][si],0
		jle continue
		add ax,[bx][si]
	continue:
		add bx,2
		loop loop1

	mov word ptr[di], ax

	pop cx
	ret
getSum endp


;十进制打印bx的数
printNum proc near
	push ax
	push bx
	push cx
	push dx

	mov ax,bx
	mov bx,10
	mov cx,0

	cal:
		mov dx,0
		div bx

		push dx
		inc cx

		cmp ax,0
		ja	cal

	print:
		pop dx
		add dl,30h
		mov ah,2
		int 21h

	dec cx
	cmp cx,0
	ja print

	pop dx
	pop cx
	pop bx
	pop ax
	
	ret
printNum endp

;主函数
main proc near
	mov cx,m	;累加次数

	lea si,array1
	lea di,total1
	call getSum
	mov bx,total1
	call printNum

	lea si,array2
	lea di,total2
	call getSum
	mov bx,total2
	call printNum

	ret
main endp


start:
	mov ax,data
	mov ds,ax

	call main

	mov ah,4ch
	int 21h
code ends
end start
  1. 宏的定义和适用
    (1)定义
;宏定义,保存文件为a.mac

;输入宏
input macro 
	mov ah,1
	int 21h
endm

;输出宏
output macro x
	mov dl,x
	mov ah,2
	int 21h
endm

;退出宏
retsys macro
	mov ah,4ch
	int 21h
endm

;相加宏
addi macro x1,x2,result
	mov ax,x1
	add ax,x2
	mov result,ax
endm

;字符串移动宏
str_mov macro op1,op2,op3
	mov cx,op1
	lea si,op2
	lea di,op3
	cld
	rep movsb
endm

(2)使用

include a.mac
.model small
.stack 100h
.data
	x db 33h,34h
	y dw ?
	mess1 db 1,2,3,4,5,6,7,8,9,0
	mess2 db 10 dup(?)

.code 
start:
	mov ax,@data
	mov ds,ax
	mov es,ax

	str_mov 10,mess1,mess2
	str_mov 2,x,y

	input
	sub al,20h
	output al

	addi 34,25,y
	retsys
end start
  1. 多模块
    a.asm
;打印x

;在各个模块间共用的变量、符号、标号、过程等要用PUBLIC伪指令事先说明为全局变量,以便能被其他模块引用。
;格式:PUBLIC 符号1[,符号2,……]
public x

;EXTRN伪指令用来说明某个变量、符号或过程是其它模块定义的,在本模块中需要引用。
;格式:EXTRN 符号1:类型 [,符号2:类型,……] 功能:对外部符号和其类型进行说明。类型为:BYTE、WORD、DWORD、NEAR、FAR等。
extrn print:far

data segment
	x db 'a'
data ends

stack segment
	dw 100h dup(0)
	top dw ?
stack ends

;由于多个源程序分别在不同的代码段中使用,因此段的属性要设置正确,以便于段组合。在定义代码段时,代码段名相同时要加上PARA’CODE’,以使其类别相同
code segment para'code'
	assume cs:code,ds:data,ss:stack

start:
	mov ax,data
	mov ds,ax
	mov ax,stack
	mov ss,ax
	mov sp,offset top

	call print

	mov ax,4c00h
	int 21h

code ends
end start

b.asm

;全局符号定义
public print

;外部符号说明
extrn x:byte

code segment para'code'
	assume cs:code

;定义打印函数
print proc far
	mov dl,x
	mov ah,2
	int 21h

	ret

print endp

code ends
end

执行命令:
masm a.asm
masm b.asm
link a.obj+b.obj
a.exe

  1. 在程序设计过程中,有时要编写一些小型程序,要求占用空间少、执行速度快。这样的程序只能有一个段。如果只有一个段,这个段必须是代码段。那么数据、堆栈都要在同一个段中。在这样的程序结构中,数据、堆栈、代码是混杂的,此时尤其要注意指针的改变。包括指令指针IP和栈指针SP。
include 1.mac
.model small
.code
	x db 33h,34h
	y dw ?
	mess1 db 1,2,3,4,5,6,7,8,9,0
	mess2 db 10 dup(?)
	sss dw 10h dup(1)				;定义16个堆栈单元
	eee db 'e'						;用来表示栈底

start:
	mov ax,@code					;各个段都在代码段中
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov sp,eee-x					;设置栈指针sp指向栈底

	str_mov 10,mess1,mess2
	str_mov 2,x,y

mark1:
	input
	sub al,20h						;变为大写
	output al
mark2:
	addi 34,25,y

	str_mov mark2-mark1,mark1,mark3	;宏,把mark1和mark2之间的若干条指令传送到mark3处
	nop								;空操作指令
mark3:
	db mark2-mark1 dup(90h)			;预定义n个单元,存放NOP(90H)指令

	mov cx,5
	mov bx,0
stacopr:
	mov ax,word ptr mess1[bx]
	push ax
	add bx,2
	loop stacopr

	retsys
end start 

你可能感兴趣的:(x86汇编)