汇编学习心得
汇编程序设计一般格式(完整版)
;注释
display equ 2 ;display赋值为2
extrn var1:byte,proadd:far,exit:far ;引用外部变量,过程名,标识
public dataname ;定义对外开放的变量
public sun ;定义对外开放的过程名
public start ;定义对外开发的标识
;——————————————————-
;宏定义
macroname1 macro p1,p2,p3
mov ax,p1
p2 p3
endm
macroname2 macro cond,lab
j&cond lab ;cond直接连接到j后面,如e,ne
endm
macroname3 macro text
cntr=cntr+1
macroname2 % cntr,text ;%后面的的变元的值作变元
endm
macroname4 macro oper
local next ;防止多次调用宏定义后,标识多重定义
cmp oper,0
je next
next:
.
.
endm
;———————————–
;重复汇编
x=0
rept 10
x=x+1
db x
endm
; db 1
; db 2
; db 3
; . .
irp x,<1,2,3,4,5,6,7,8,9,10>
db x
endm
irpc x,123456789
db x
endm
;——————————————————
;条件汇编
;实现三个数中的最值
max macro k,a,b,c
local next,out
mov ax,a
if k-1 ;k-1=0则不满足条件执行endif后面语句,满足不等于0则执行if后面直到endif之间的语句
if k-2
cmp c,ax
jle next
mov ax,c
endif ;对应k-2
next:
cmp b,ax
jle out
mov ax,b
endif ;对应k-1
out:
endm
;——————————————————-
data segment commom;不同模块下同名段连接,即在同一模块下
dataname dw 20 dup(1,?)
array dw 1,2,
+2,4,
+8 ;$表示当前地址计数器sp的值
org 0020h ;使下一偏移地址从0020h开始
even ;下一地址从偶地址开始
data ends
;——————————————————-
code segment
main proc far
assume cs:code,ds:data
start:
push ds
sub ax,ax
push ax
mov ax,data;把data的数据段地址给ax
mov dx,ax
mov ax,dataname ;把dataname数据给ax
mov ax,offset dataname;把data的地址给ax
mov ax,es:[di] ;默认es和di连用
mov ax,ds:table[si][bx] ;ds默认和si连用,相对基址变址寻址
call sun
call far prt extern_sun
jmp start
mov dl,1h
mov ah,display
int 21h
ret
main endp
;--------------------------------------------------------
sun proc near
.
.
ret
sun endp
code ends
end start
计算机系统
1 硬件:中央处理机(cpu,运算器,控制器,寄存器)具体运算器,控制和寄存器是什么需要继续学习了解, 存储器(缓存,主存,外存),输入输出(I/O),总线。
2软件:操作系统和用户软件
操作系统主要作用是对系统的硬,软件资源进行合理的管理。
操作系统主要部分是常驻内存的监督程序,是在开机启动时,bios(rom只读存储器上一段程序)启动后,指定操作系统在外存的位置,从而把操作系统由外存加载到主存上,其中操作系统的主要部分一直在内存(cpu上)运行,便于接收用户命令,使操作系统执行相应的动作。
操作系统具体的功能,将汇编数p18,其中也讲解了程序在操作系统下是如何运行的。
中央处理机: 1算术逻辑部件2 控制逻辑 3 工作寄存器 每个寄存器相当于运算器中的一个存储单元,是真正的物料地址。
80x86寄存器组
1 通用寄存器
2专用寄存器
3 标志寄存器
存储器
寻址方式:
1 实模式
2保护模式(内存保护)把最大段长由64k扩展到了4G
3 虚拟存储技术
外设:
外部设备与主机的通信是通过外设接口进行的,每一个接口都包括一组寄存器
1 数据寄存器 2状态寄存器 3 命令寄存器
各个外部设备都有以上三类寄存器,接口由外设工作方式的简易程度决定。
为了使主机访问外设方便起见,外设中的每个寄存器给于一个端口,一个独立于内存器的I/O地址空间(不知道是物理地址,还是逻辑(主存)地址,后者吧),可达64KB。
BIOS和DOS功能调用,BIOS程序是直接在ROM上,而DOS(操作系统,一种工作在实模式下的操作系统)程序是在内存(cpu)中的,BIOS的层次比DOS还低。
80x86的指令系统和寻址方式
寻址方式: EA=基址+(变址*比例因子)+位移量
立即数寻址:
Mov al,5
寄存器寻址:
Mov ax,bx
直接寻址:
Mov ax,[2000h]
寄存器间接寻址:
Mov ax,[bx]
寄存器相对寻址:
Mov ax,count[si]
基址变址寻址:
Mov ax,[bx][si]
相对基址变址寻址:
Mov ax.mask[bx][si]
比例变址寻址:
Mov eax,count[esi*4]
转移指令有关的寻址方式:
/*只有段内直接寻址适用于条件转移/
1段内直接寻址
这种方式转向的有效地址是用相对于当前ip的位移量来表示,所以跳转指令给出的相对于当前ip的位移量。
条件转移:位移量只允许8位
无条件转移指令在位移量为8位时成为短跳转,位移量为16位时称为近跳转。
短跳转:Jmp short quest
近跳转: jmp near ptr progia
2段内间接寻址
转向的有效地址是一个寄存器或是一个存储单元的内容,即不存在相对位移量的概念。
Jmp bx ;一般可以再跳转之前把跳转的地址放到bx中保存,然后后面再回到之前的ip
Jmp word ptr [bp+table]
3段间直接寻址
在指令中直接提供了转向的段地址和偏移地址,所以只要用指令中指定的偏移地址取代ip寄存器内容,用指令中指定的段地址取代cs寄存器内容,
Jmp far ptr nextroutint
4段间直接寻址
Jmp dword ptr [ insers+bx]
指令系统:
1数据传送指令(不影响标志位)
1.1Mov push pop xchg
Mov dst,src
Segreg:段寄存器,reg:一般寄存器,mem:存储器,data:立即数
mov reg/mem ,data
Mov reg/mem, reg/men 但不允许mem,mem
Mov mem/reg,segreg
Mov segreg,mem/reg 但不允许用cs段寄存器
Push src
执行操作 (sp)<-(sp)-2 ((sp)+1,(sp))<- (src) 16位指令
Pop dst
执行操作 (dst)<-((sp+1),(sp)) (sp)<-(sp)+2
1.2累加器专用传送指令(EAX,AX,AL)
IN 输入
IN al,port (8位) in ax,port(字)
OUT 输出
Out port,al out port ax
所有的I/O端口和CPU之间的通信都由IN和OUT指令来完成,其中IN指令完成I/O到CPU的信息传送,OUT完成从CPU到I/O的信息传送。外设的前256个端口可以直接在指令中指定,而对于大于256的端口则必须使用上面格式,先将端口号放到ax里面,然后用IN和OUT指令来完成信息传送。
1: mov dx,f38h 指定端口号
IN ax,dx 从f28h号端口内容读入到ax
Mov data_word,ax 把从端口读入的内容给存储单元data_word
2
Mov dx,3fch
OUT dx, bx,从bx寄存器中输出一个字节到3fch端口
OUT 5,al
1.3地址传送指令
LEA 有效地址送寄存器
LEA reg,src
LEA bx,list
Mov offset list
两条指令都是获取list的有效地址,但mov的执行速度比lea快,offset只能与简单的符号地址相连使用,不能用于 list[si][bx]等
1.4类型转换指令
CBW 字节转换为字
CWD 字转换为双字
执行操作:al的内容符号扩展到ah,形成ax的字
2算术指令
2.1加法指令
Add dst,src (dsr)<-(src)+(dst)
Adc dst,src (dsr)<-(src)+(dst) 带进位加法
Inc opr (opr)<-(opr)+1
Xadd dst,src temp<-(src)+(std) (src)<-(dst) (dst)<-temp
Add,adc xadd 指令都会影响cf标志位
2.2减法指令
Sub dst,src (dst)<-(dst)-(src)
Sbb dst,src (dst)<-(dst)-(src) 带借位的减法
Dec opr (opr)<-(opr)-1
Neg opr (opr)<- -(opr) 求补
Cmp opr1,opr2 (opr1)-(opr2) 修改标志位
2.3乘法指令
Mul src
执行操作: (ax) <-(al)*(src)
(dx,ax) <-(ax)*(src)
(edx,eax) <-(eax)*(src)
Imul src 带符号的乘法 同上
2.4除法指令
Div src
(al)<- (ax)/(src) 的商
(ah)<-(ax)/(src)的余数
(ax)<- (dx,ax)/(src) 的商
(dx)<-(dx,ax)/(src)的余数
(eax)<- (edx,eax)/(src) 的商
(edx)<-(edx,eax)/(src)的余数
Idiv src 带符号的除法 同上
3逻辑指令
3.1逻辑运算指令
And dst,src (dst) <- (dst)&(src)
Or dst,src (dst) <-(dst)|(src)
Not opr (opr) <- -(opr)
Xor dst,src (dst) <-(dst)&-(src)异或
Test opr1,opr2 (opr1)&(opr2) 操作结果不保留,只为修改标志位
3.2位移指令
Shl 逻辑左移
Shr 逻辑右移
Sal 算术左移
Sar 算术右移
Rol 循环左移
Ror循环右移
Rcl 带进位的循环左移
Rcr 带进位的循环右移
格式: 指令 opr,cnt ,其中指令代表上面几种,opr表示操作数,cnt表示移位次数
移位规则:
4串处理指令
Movs 串传送指令
Cmps 串比较指令
Scas 串扫描指令
与下面rep配合使用,
Rep 重复直到cx为0
Repz/repe 相等或为0则重复
Repne/repne 不相等或不为0则重复
执行操作:
1 如果cx=0或者zf=0时退出,否则进行下面
2 cx-1
3 执行其后的串指令
4重复1-3
Movs dst,src
执行操作:df=0时,字节操作
(dst)<- (src)
(Src) <- (src)+1
Movsb
指令与rep联用,则可将数据段中的整个串数据传送到附加段,其中源串必须在数据段,目标串必须在附加段
串传送指令准备工作
1:把存放在数据段中的源串首地址放到源变址寄存器si中
2:把将要存放数据串的的附加段中的目的首地址放到母的寄存器di中
3 把数据串长度放到寄存器cx
4 建立方向标志位 cld df=0,地址增量,std df=1,地址减量
Mov cx,18
Cld
Rep movsb
Cmps/Scas
Cmps src,dst
执行操作:df=0,字节操作
(Src) <-(dst)
(Src)<-(src)+1
(dst)<- (dst)+1
Scas dst
执行操作:df=0,字节操作
(Src) <-(dst)
(Src)<-(src)+1
(dst)<- (dst)+1
5 控制转移指令
5.1: 无条件转移指令
短跳转:Jmp short quest
近跳转: jmp near ptr progia
Jmp bx ;一般可以再跳转之前把跳转的地址放到bx中保存,然后后面再回到之前的ip
Jmp word ptr [bp+table]
Jmp far ptr nextroutint
Jmp dword ptr [ insers+bx]
5.2:条件转移指令
5.3:循环指令
Loop
Loopz/loope
Loopnz/loopne
5.4子程序
Call dst
段内直接调用
执行操作:16位
Push (ip)
(ip)<-(ip)+d16
段内间接调用
执行操作:16位
Push (ip)
(ip)<-(ea)
段间直接调用:
执行操作:16位
Push (cs)
Push (ip)
(ip)<- dst指定的偏移地址
(cs)<- dst指定的段地址
段间间接调用:
执行操作:16位
Push (cs)
Push (ip)
(ip)<- (ea)
(cs)<- (ea+2)
Ret 同上
5.5中断
Int 中断
Into 溢出中断
Iret/iretd
Int type
中断:中断例行程序的入口地址成为中断向量,早80x86的实模式工作下,存储器的最低地址的1k(00000h-003ffh)字节为中断向量区,其中存放256种中断例行程序的入口地址,每个中断向量占4个字节。类型20位程序结束的中断例行程序入口,类型21为系统功能调用的中断例行程序入口。
6 处理机转态控制指令
Clc 进位位置0 cf=0
Cmc 进位位求反
Stc 进位位置1
Cld 方向标志位置0 df=0
Std 方向标志位置1 df=1
Cli 中断标志位置0 if=0
Sti 中断标志位置1 if=1
汇编语言程序设计
1汇编语言程序上机过程
运行汇编语言过程
1编辑asm源文件
2用masm程序汇编asm文件转换成obj文件
3用link程序连接obj文件,转换成exe文件
4由dos装入存储器中,并运行。
1 masm 2 link 3 debug的使用
2 程序设计
1伪操作
1.1段定义伪操作
Segment name segment
Segment name ends
代码段必须明确指明段和寄存器的关系,用assume伪操作实现
Assume cs:code_seg,ds:data_seg1,es:data_seg2
Assume只是指定某个段非配给那个寄存器,没有把段地址存入段寄存器,还需在代码中完成地址的存入,但代码段在程序初始化时已经完成。
段的属性说明:
Segment name segement [align_type] [combine_type] [use_type] [‘class’]
1定位类型: para指定段的起始地址,bype偏移地址,word从字的边界开始,起始地址为偶数,dword为双字开始
2组合类型,在连接时段的合并方法: private 私有段,在连接时将不与其他模块中的同名段合并 pubilc common at
1.2程序的开始和结束伪操作
在程序的开始可以用name或title作为模块的开始
Start:;程序的入口地址,可以是子程序(过程)名,也可以直接用标识表示入口地址
End strat
表示start为主程序,而其他一般模块只需要用end结束,不用指定模块名
1.3数据定义及存储伪操作
[variable] mnemonic operand …operand [;comments]
变量名,数据类型 数据 注释
数据类型有:
Db:字节
Dw:字
Dd:双字
Df:6字节
Dq:4字
Dt:10字节
Data_byte db 10,4,10h
Data_word dw 100,100h,-5
Abc db 0,?,?,9
注意 :存储先后顺序从低地址到高地址,字的顺序高位在高地址
Db ‘ab’ :先存储a后存储b,则b在高位
Dw ‘ab’ :存储高位在高地址,则a在高位
Repeat_count dup(operand,…opreand)
Array1 db 20 dup(1,3,4,?)
表示连续存储dup后面20次
1.4表达式赋值伪操作equ
Expession_name equ expression
Const equ 1024
1.5地址计数器 表示当前的地址
Jne $+6
Array dw 1,2,
Org伪操作设置当前地址计数器的值
Org constant expression
Org $+4
Even伪操作使下一个变量或指令开始于偶数地址
align伪操作使下一个变量或指令开始于四字地址
循环与分支程序设计
1:循环结构(多重循环-冒泡排序)
1:设置循环的初始状态(cx与loop和用)
2:循环体
3:循环控制
Do_while:先判断后执行
Do_until:先执行后判断
2:分支程序设计-折半查找
3:跳跃表法(switch-case结构)
子程序结构
过程(函数)定义伪操作( 可以和标识一样做程序的入口地址,用于跳转)
Procedure name proc attribute
.
.
Procedure name endp
Far:不同段之间的调用用far
Near:相同段之间的调用用near
Call:sp和cs的压栈
Ret:sp和cs的出栈
子程序的参数传递
1:通过寄存器传递
2:同一源文件下直接使用
3:地址表传递参数
4:堆栈残敌参数
多模块之间的参数传递
Common 连接不同模块中的同名段
Data segment common
Public:对本文件外开放的 变量,过程,标识,段
Public symbol[,..,]
Extrn :引用本文件外开放的 变量(vyte,word,dword),过程(near,far),标识(near,far),段
Extrn symbol name :type[,..,]
Source1
Public var1
Public proadd
Public exit
Global segment Public
Source2
Extrn var1:word
Extrn proadd:far (过程名)
Extrn exit:far (标识名)
Global segment public
注意:引用本模块,或者模块外的的局部变量,在程序一开始就需要指明ds段或者用es段
Mov ax,seg_data
Mov ds,ax
高级汇编语言技术
1.1宏汇编
1.1.1宏定义 宏汇编 宏展开
宏定义
Macroname marco [dummy parameter list] ;变元
宏定义体
Endm
宏汇编
比较子程序和宏定义的区别:
子程序是在程序执行期间由主程序调用,它只占有它自身大小的一个空间,而宏定义则是在汇编期间展开,他直接占用调用函数的空间,但是省去了程序执行期间调用的开销。,所以较短的功能代码可以用宏定义来写,减少开销。
宏展开
见书中
1.1.2宏定义中的参数
可以无变元
变元可以是操作码
宏定义中&用于连接字符与变元,变元与变元
%用于使用跟在其后的变元的数值做变元参数
1.1.3 lacal伪操作
宏定义里面允许使用标号(入口地址),但是程序中多次调用该宏定义的话,则会出现标号的多重定义,这是不允许的。提供lacal伪操作来局部标识。
1.1.4宏定义里面定义宏
需注意的是先定义后调用
1.1.5列表伪操作
Masm提供.xall .lall .sall 来控制汇编清单中宏展开的列出情况,默认为.xall
.xall :汇编清单.Lst文件中列出产生目标码的宏展开。
.lall :汇编清单.lst文件中列出包括注释在内的宏展开。
.sall :汇编清单.lst文件中不列出任何信息。
1.1.6宏库的建立与调用
宏库的扩展名为mac或inc ,类似于c中的头文件的作用
Include c:\macro.mac
1.2重复汇编
1.2.1重复伪操作
Rept expression
重复块(此处就是汇编语句,同样可以是宏定义)
endm
1.2.2不定重复伪操作
Irp dummy, ;自变量,<变量值> 值以数值形式
Endm
Irpc dummy,string ;自变量,<变量值> 值以字符串形式
Endm
1.3条件汇编
Ifxxxx argument
满足条件汇编块
[Else]
不满足条件汇编块,可以缺省
Endif
If : 汇编程序求出的表达式不为0,则满足条件
Ife : 汇编程序求出的表达式为0,则满足条件