汇编语言(九):汇编语言格式、变量定义、顺序/分支/循环程序设计

作为汇编语言的课程笔记,方便之后的复习与查阅

本篇为课程第十次课内容

目录

  • 汇编语句格式
    • 标识符
    • 硬指令、执行性语句
    • 伪指令、说明性语句
  • 变量定义
    • 变量名
    • 初值表
    • 变量定义伪指令助记符
      • 定义字节单元伪指令DB
      • 定义字单元伪指令DW
      • 定义双字单元伪指令DD
    • PTR操作符
  • 顺序程序设计
    • 求两数之和
    • 移位
    • 代码转换 XLAT
  • 分支程序设计
    • 二分支
    • 三分支
    • 多分支
  • 循环程序设计

汇编语句格式

标识符

  • 标识符(Identifier)一般最多由31个字母、数字及规定的特殊符号(如 _、$、?、@)组成,不能以数字开头。默认情况下,汇编程序不区别标识符中的字母大小写
  • 一个程序中,每个标识符的定义是唯一的,还不能是汇编语言采用的保留字。
  • 保留字(Reserved Word)是汇编程序已经利用的标识符,主要有:
    硬指令助记符——例如:MOV、ADD
    伪指令助记符——例如:DB、EQU
    操作符——例如:OFFSET、PTR
    寄存器名——例如:AX、CS

硬指令、执行性语句

硬指令:使CPU产生动作、并在程序执行时才处理的语句

执行性语句——由硬指令构成的语句,它通常对应一条机器指令,出现在程序的代码段中,格式:

标号: 硬指令助记符 操作数,操作数				;注释
again: mov 			dx,		offset string		;注释
  • 标号:反映硬指令位置(逻辑地址)的标识符,后跟一个冒号分隔
  • 硬指令助记符:可以是任何一条处理器指令
  • 处理器指令的操作数可以是立即数、寄存器和存储单元

伪指令、说明性语句

伪指令(Directive)——不产生CPU动作、在程序执行前由汇编程序处理的说明性语句
伪指令与具体的处理器类型无关,但与汇编程序的版本有关

说明性语句——由伪指令构成的语句,它通常指示汇编程序如何汇编源程序:

名字  伪指令助记符  参数,参数,…		;注释
string 	db 		‘Hello,world’		;注释
  • 名字:反映伪指令位置(逻辑地址)和属性的标识符,后跟空格或制表符分隔,没有冒号
  • 伪指令助记符:定义字节数据和字符串的DB就是伪指令
  • 伪指令的参数可以是常数、变量名、表达式等,可以有多个,参数之间用逗号分隔

变量定义

变量定义(Define)伪指令为变量申请固定长度的存储空间,并可同时将相应的存储单元初始化

变量定义伪指令要放在.exit后,end之前,因为它不是可执行的语句

变量名

变量名为用户自定义标识符,表示初值表首元素的逻辑地址;用这个符号表示地址,常称为符号地址。设置变量名是为了方便存取它指示的存储单元。变量名可以没有。这种情况,汇编程序将直接为初值表分配空间。

初值表

初值表是用逗号分隔的参数

主要由数值常数、表达式或?DUP组成

  • ?——表示初值不确定,即未赋初值
BUFFER	DB ?
  • DUP——表示重复初值
    DUP的格式为:重复次数 DUP(重复参数)
BUFFER	DB 10 dup(0)
BUFFER	DB 10 dup(?)

变量定义伪指令助记符

DB——定义字节伪指令
DW——定义字伪指令
DD——定义双字伪指令

DF——定义3字伪指令
DQ——定义4字伪指令
DT——定义10字节伪指令

重点掌握前三个

定义字节单元伪指令DB

DB伪指令用于分配一个或多个字节单元,并可以将它们初始化为指定值

初值表中每个数据一定是字节量(Byte),存放一个8位数据:

  • 0~255的无符号数
  • -128~+127带符号数
  • 字符串常数
X	db 'a',-5
	db 2 dup(100),?		;第二行没有带名字,默认由x往下继续进行内存分配
Y	db 'ABC'

汇编语言(九):汇编语言格式、变量定义、顺序/分支/循环程序设计_第1张图片

定义字单元伪指令DW

初值表中每个数据一定是字量(Word),一个字单元可用于存放任何16位数据:

  • 一个段地址
  • 一个偏移地址
  • 两个字符
  • 0~65535之间的无符号数
  • -32768~+32767之间的带符号数
count	dw 8000h,?,'AB'			; A在高地址处
maxint	equ 64h					; equ是等价的意思,表示之后maxint就是64h
number	dw maxint
array	dw maxint dup(0)

汇编语言(九):汇编语言格式、变量定义、顺序/分支/循环程序设计_第2张图片

定义双字单元伪指令DD

初值表中每个数据是一个32位的双字量(Double Word):

  • 有符号或无符号的32位整数
  • 用来表达16位段地址(高位字)和16位的偏移地址(低位字)的远指针
vardd	DD 0,?,12345678h
farpoint	DD 00400078h

PTR操作符

PTR操作符使名字或标号具有指定的类型

  • 类型名可以是
    BYTE/WORD/DWORD/FWORD/QWORD/TBYTE
mov byte ptr [2000H],10H

使用PTR操作符,可以临时改变名字或标号的类型

顺序程序设计

求两数之和

NUM1和NUM2单元中各存放着一个双字无符号数,编制程序计算两数之和,将结果存于SUM双字单元中,进位保存到FSUM字节单元中

  • 分析:最多一次处理16位,双字需分开处理
.model tiny
.code
.startup 
	mov ax,word ptr num1    	;处理低16位
	add ax,word ptr num2
	mov word ptr sum,ax     	;保存低16位
	mov ax,word ptr num1+2  	;处理高16位
	adc ax,word ptr num2+2
	mov word ptr sum+2,ax   	;保存高16位
	
	mov dx,0 		   			;最高进位
	rcl dl,1
	mov fsum,dl		   			;保存进位	
	.exit 0           
	                     
	num1   dd 82348567H
	num2   dd 87658321H
	sum   dd ?
	fsum   db ? 
end

也可以用串操作

移位

ddvarw为一个32位的数据12ab56cdH,编程将其整个循环左移4位(使用顺序结构)得到 2ab56cd1H

汇编语言(九):汇编语言格式、变量定义、顺序/分支/循环程序设计_第3张图片

.model tiny
.code
.startup
	mov ax,word ptr ddvar  		;低16位
	mov dx,word ptr ddvar+2		;高16位
	mov  cl , 4
	mov  bh , dh				;保存高8位到BH 
	mov  bl , ah				;保存低8位到BL
	shl  dx  , cl 				;高16位左移 4位
	shl  ax , cl  				;低16位左移 4位
	shr  bh , cl 				;高8位右移4位,高4位到bh中
	shr  bl , cl 				;低8位右移 4位,低4位到bl中
	or   dl , bl  				;原低4位转到高4位
	or   al, bh   				;原高4位转到低4位
	.exit 0 
	
	ddvar	dd 12ab56cdh
end

代码转换 XLAT

用查表法,实现一个8位二进制数(00-0FH)转换为ASCII码显示

.model tiny
.code
.startup
	mov bx,offset ASCII			;BX指向ASCII码表
	mov al,hex					;AL取得一位16进制数,	
	and al,0fh					;只有低4位是有效的,高4位清0
	xlat						; 换码:AL←DS:[BX+AL]
	mov dl,al					;入口参数:DL←AL
	mov ah,2					;02号DOS功能调用
	int 21h						;显示一个ASCII码字符
	.exit 0

	ASCII db 30h,31h,32h,33h,34h,35h
	      db 36h,37h,38h,39h	;0~9的ASCII码
	      db 41h,42h,43h,44h,45h,46h ;A~F的ASCII码
  	hex db 0bh    ;任意设定了一个待转换的1位16进制数
end

分支程序设计

  • 判断的条件是各种指令,如CMPTEST等执行后形成的状态标志
  • 转移指令JccJMP可以实现分支控制

二分支

比较两个数大小:在DATA1和DATA2单元中各有一个16位二进制无符号数,找出其中较小的数,存于MIN单元中

.model tiny
.code
.startup
	mov ax,data1
	cmp ax,data2
	jb next
	mov ax,data2 		;CF=0
	next:  
		mov min,ax		;存结果
	.exit 0

	data1   dw  2000h
	data2   dw  3f80h
	min      dw  ?
end

三分支

判断变量var中的值,若为正数,在result中存入1;为负数,在result中存入-1;为零,在result中存入0

.model tiny
.code
.startup
	mov ax,var
	cmp ax,0
	jz zero  				;等于0
	jg great				;大于0
	mov ax,0ffffh			;小于0
	jmp ext
	
	zero: mov ax,0
		 jmp next
	great: mov ax,0001h
	next: mov result,ax
	.exit 0
	   
	var	dw 8001h
	result  	dw 0
end	

多分支

(了解即可)

  • 可用跳跃表法,使程序根据不同的条件转移到多个程序分支中去执行

需要在数据段事先安排一个按顺序排列的转移地址表。因为转移地址为16位偏移地址,所以表地址偏移量需要加2(type=2)调整。可用JMP指令的变址寻址,或寄存器间接寻址,或基址变址寻址方式来实现跳跃表法的程序

Table dw disp1,disp2,disp3,disp4,disp5,disp6,disp7,disp8

在这里插入图片描述
:根据键盘输入的1-8数字跳转到8个不同的处理程序段

.model tiny
.code
.startup
	start1:
		mov dx,offset msg		;9号功能显示字符串
		mov ah,9
		int 21h
		mov ah,1				;1号功能获取用户输入
		int 21h
		cmp al,'1'				;输入不是1~8,则跳转回去
		jb start1
		cmp al,'8'
		ja start1
		and ax,000fh			;设置地址偏移
		dec ax
		shl ax,1				;因为是双字,所以地址偏移需要用shl来乘2
		mov bx,ax
		jmp table[bx]
	start2:
		mov ah,9
		int 21h
		.exit 0
	disp1:
		mov dx,offset msg1
		jmp start2
	disp2:
		mov dx,offset msg2
		jmp start2
	……
	disp7:
		mov dx,offset msg7
		jmp start2
	disp8:
		mov dx,offset msg8
		jmp start2
		
	Msg db 'Input Number(1~8):',0dh,0ah,'$'
	Msg1 db 'Chapter 1!',0dh,0ah,'$'
	Msg2 db 'Chapter 2!',0dh,0ah,'$'
	Msg3 db 'Chapter 3!',0dh,0ah,'$'
	Msg4 db 'Chapter 4!',0dh,0ah,'$'
	Msg5 db 'Chapter 5!',0dh,0ah,'$'
	Msg6 db 'Chapter6!',0dh,0ah,'$'
	Msg7 db 'Chapter 7!',0dh,0ah,'$'
	Msg8 db 'Chapter 8!',0dh,0ah,'$'
	Table dw disp1,disp2,disp3,disp4,
	      dw disp5,disp6,disp7,disp8
end

循环程序设计

  • 循环指令和转移指令可以实现循环控制

例1: 求1+2+3+…+100的和,存在sum字单元

.model tiny
.code
.startup
	xor ax,ax    		;被加数AX清0
	mov cx,100
	again:
		add ax,cx	    ;从100,99,...,2,1倒序累加
		loop again
	mov sum,ax   	;将累加和送入指定单元
	.exit 0
    sum	dw ?
end

例2:把BX中的数以十六进制的形式显示在屏幕上。比如BX=8F6AH,屏幕显示 8F6AH
这个例子要重点理解

  • 要把bx中数据转成ascii码
  • 用循环移位,先显示高4位的16进制数,接着继续移位处理其他位

汇编语言(九):汇编语言格式、变量定义、顺序/分支/循环程序设计_第4张图片

	mov    	ch, 4			;循环4次
rotate:       
	mov    	cl, 4			;每次移位4位
	rol   	bx, cl
	mov    	al, bl			;只取bx低4位
	and     al, 0fh
	add   	al, 30h			;’0’-’9’ ASCII 30H-39H
	cmp    	al, 3ah
	jl      printit		;有符号数的比较
	add     al, 7h			;’A’-’F’ ASCII 41H-46H
printit:      
	mov    	dl, al
	mov    	ah, 2
	int    	21h
	dec    	ch
	jnz    	rotate

例3:在数据段中从buffer单元开始存放10个16位二进制有符号数,把其中最大数找出来存于MAX单元中

.model tiny
.code
.startup
	mov bx,offset buffer
	mov cx,10
	mov ax,[bx] 
	circle:
	 	inc bx			;16位,地址一次要加2
		inc bx 
		cmp ax,[bx]
		jge next
		mov ax,[bx]
	next:	
		loop circle
		mov max,ax
	.exit 0

	buffer dw  -100,3000,-1,22,8000h
		   dw  9232,0,-3632,-3144,6322
	max    dw  ?
end

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