关于源程序书写格式:(太基础的略去,只记录一些我还不熟悉的内容,参考https://wenku.baidu.com/view/7ca70e0ef342336c1eb91a37f111f18582d00c5d.html
其他网页的参考以挂上相关连接)
关于段定义
- 堆栈段、数据段、代码段是逻辑段 汇编、连接后生成物理段 逻辑段与物理段的关系取决于伪指令ASSUME
- 一个源程序至少一个逻辑代码段和END伪指令
- 完整段定义:
- 简化段定义1:
- 注意SEGMENT/ENDS成对出现
- END:源程序文件结束
格式:END [过程名|标号] - 程序开始伪指令:.STARTUP(只能在简化段定义格式中使用)
- 结束程序:
法1:用DOS 4CH功能调用
……
MOV AH,4CH
INT 21H
……
END
法2:RET方式
<程序名>PROC FAR
PUSH DS
SUB AX,AX
PUSH AX
……
RET
<程序名>ENDP
……
END
-
关于伪操作:
它是汇编时进行的,不是计算机运行时执行的
完成处理器选择、存储模式定义、数据定义、存储器分配、指示程序开始结束等功能 -
关于变量:
- 变量的定义和预置:
格式:<变量名> 伪操作符 <操作数>
<变量名>由第一个字符不能是数字,前31个字符有效
<操作数>课时数常数、表达式、字符串、?、DUP等
伪操作符:DB, DW, DD, DF, DQ, DT
注:关于DUP和EQU
Dup用于把一个相同值赋值若干次。重复次数dup(数据项)
具体比如: - 变量的定义和预置:
s db 30 dup(0)
定义一个字节型变量,该变量占用30个字节,所有字节被初始化成0
equ是一个代码替换指令
比如:
s equ bx+si
movcx,[s]
那么上面两句代码相当于如下指令:
movcx,[bx+si]
- 例子:
DATA_BYTE DB 10,4,10H,?
DATA_WORD DW 100,100H,-5,?
-
变量的属性:
段(segment):它属于哪个段,段基址是什么
位移(offset):相对于段基址的位移是多少
类型(type):表名数据项的长度,如字节,字,双字,4字等 -
数据回送操作符的使用,如TYPE, LENGTH, SIZE, OFFSET, SEG
例子:
变量可以通过名字访问,要注意操作类型与定义时的类型一致:
-
1.立即寻址方式 MOV AH, 80H(直接给寄存器赋值)
-
寄存器寻址方式(源或者目的有一个是寄存器)
2.1) 源操作数是寄存器寻址方式
如:ADD VARD, EAX ADD VARW, AX MOV VARB, BH等。
其中:VARD、VARW和VARB是双字,字和字节类型的内存变量。
2.2) 目的操作数是寄存器寻址方式
如:ADD BH, 78h ADD AX, 1234h MOV EBX, 12345678H等。
2.3) 源和目的操作数都是寄存器寻址方式
如:MOV EAX, EBX MOV AX, BX MOV DH, BL等。 -
直接寻址方式(地址值在括号里)
MOV BX, [1234H] (默认使用DS)
MOV ES:[1000H], AX -
寄存器间接寻址方式(寄存器在括号里)
MOV BX,[DI]
操作数的有效地址用SI、DI、BX和BP等四个寄存器之一来指定,称这种寻址方式为寄存器间接寻址方式。
若有效地址用SI、DI和BX来指定,则其缺省的段寄存器为DS;
若有效地址用BP来指定,则其缺省的段寄存器为SS(即:堆栈段)。 -
寄存器相对寻址方式(一个寄存器和一个立即数在括号里,并且还要计算)
MOV BX, [SI+100H] -
基址加变址寻址方式(两个寄存器在括号里,并且还要计算)
MOV BX, [BX+SI] -
相对基址加变址寻址方式(两个寄存器在括号里和一个立即数在括号里,并且还要计算)
MOV AX, [BX+SI+200H] -
mov ax,data:
mov ax,data这句,如果是前面有assume ds:data的情况,是将地址值传给ax;
若data是一个变量,如
DATAS SEGMENT
data dw 12H;
DATAS ENDS
中的data,则是把data中的数据给ax。
在汇编语言中,MOV指令是数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址(寄存器间的数据传送本质上也是一样的)。其特点是不破坏源地址单元的内容。
例如:
MOV AX,2000H;将16位数据2000H传送到AX寄存器
MOV AL,20H;将8位数据20H传送到AL寄存器
MOV AX,BX;将BX寄存器的16位数据传送到AX寄存器
MOV AL,[2000H];将2000H单元的内容传送到AL寄存器
需要注意的是:
(1)两个存储单元之间不能直接传送数据,即:MOV指令只允许一个操作数在存储器中。MOV [SI],[2000H];这是错误的
(2)MOV指令中立即数不能直接传送给段寄存器(CS、DS、SS、ES)和IP;段寄存器之间不能直接传送。MOV IP,2000 H ;这是错误的
(3)CS和IP不能作为目的操作数。MOV CS,AX ;这是错误的
(4)MOV指令中立即数不能作目标操作数。MOV 2000H,[SI] ;这是错误的
MOV指令可以在CPU内或CPU和存储器之间传送字或字节,它传送的信息可以从寄存器到寄存器,立即数到寄存器,立即数到存储单元,从存储单元到寄存器,从寄存器到存储单元,从寄存器或存储单元到除CS外的段寄存器(注意立即数不能直接送段寄存器),从段寄存器到寄存器或存储单元。
但是注意
(1) MOV指令中的源操作数绝对不能是立即数和代码段CS寄存器;
(2) MOV指令中绝对不允许在两个存储单元之间直接传送数据;
(3) MOV指令中绝对不允许在两个段寄存器之间直接传送数据;
(4) MOV指令不会影响标志位
例:MOV AX,DATA_SEG
MOV DS,AX
注意:段寄存器(段地址)必须通过寄存器如AX寄存器进行立即数的初始化。
例: MOV AL,‘E’
把立即数(字符E的ASC码)送到AL寄存器。
例: MOV BX,OFFSET TABLE
将TABLE的偏移地址(而不是内容)送到BX寄存器中。其中OFFSET为属性操作符,表示的是将其后的符号地址的值(不是内容)作为操作数。
例 MOV AX,Y[BP][SI]
把地址为16d×(SS)十(BP)十(SI)十位移量Y的存储单元的内容送给AX寄存器
- mov ah,1 int 21h
通过给AH寄存器赋值,然后调用INT 21H指令,计算机就会根据AH寄存器中的值执行相应的操作,其中1H是键盘输入并回显,AL中有输入字符
调用其他指令参考:http://blog.csdn.net/chinazeze/archive/2007/08/10/1735621.aspx - ROL和RCL
AL=10100000时,
ROL AL,1就把最高位的 1 移到最后,使AL变成 0100 0001,同时移出的1送CF;
ROL AL,CL(CL=2),相当于2次 ROL AL,1,所以AL变成 1000 0010,最后移出的0送CF。
RCL AL,1则把AL的最高位1送给CF,使CF=1,AL其它位相应左移,成为 0100 000X,最后空下的X位被CF原来的值补齐;
同样,ROL AL,CL(CL=2),相当于2次 RCL AL,1,最后AL变成 1000 00X1,AL原第二位的0到了CF,CF原来的值补AL中的x。
- JLE是什么意思
这是条件转移指令,L是low(低的)E是equit(相等的),比如 cmp a ,b,后面再接JLE,如果a<=b的话,就跳转到别的命令上
CMP AL,'9' ;AL原来已经复制了
JLE DISPLAY
ADD AL,07H
DISPLAY:
MOV DL, AL
- 关于宏定义(转自https://blog.csdn.net/qq_27035123/article/details/51456102 )
- 简单说一下宏调用和子程序的区别:
子程序在程序执行期间调用,只占用自身大小的一段空间。
(必须到子程序的IP,好处是节省内存,效率高,但是因为要保存返回地址,转向地址,时间长,适合长代码,频繁调用的)
宏调用,在汇编期间被展开,调用一次展开一次。
宏汇编通常使用 macro 、endm这一对宏汇编伪指令来做到,格式如下:
宏名 macro [形参表]
宏定义体
endm
宏名在同一源程序中,保持唯一,宏可以带形式参数表;可选的形参表给出了宏定义中用到的形式参数(哑元,简称为形参),之间用逗号相隔。
宏定义中的注释如果是用;;分割的,则后边宏展开不再出现该注释。
宏调用的格式为:
伪指令格式:宏名[实参表]
本例中计算ah中的代码如下:
countah macro ;使用
push dx
push cx
mov ch, 8h
mov cl, 0h
mov bh, 00000001
loopa:
mov dh, ah
and dh, bh
shr dh, cl
adc bl, dh
rol bh, 1
inc cl
dec ch
jnz loopa
pop cx
pop dx
endm