汇编语言学习笔记

第一章

1.汇编语言
(1)汇编指令(汇编语言的核心
(2)伪指令
(3)其他符号
2. CPU与内存
地址总线->地址信息 决定了CPU的寻址能力
一个CPU有N根地址线,可以说地址总线的宽度为N,最多可以寻找2的N次方个地址单元。2的地址总线次方(范围:0~XXX…)=存储单元数=内存地址空间大小。
控制总线->控制信息 决定了CPU与其他器件进行数字传送时的一次数据传送量
数据总线->数据信息 决定了CPU对系统中其他器件的控制能力
3. 内存空间=由若干个存储单元组成的逻辑存储器

地址0-7FFFH的32KB空间为主随机存储器的地址空间
地址8000H-9FFFH的8KB空间为显存地址空间(数据会被输出到显示器上)
地址A000H-FFFFH的24KB空间为各个ROM的地址空间(只读存储器,写入数据无效)

主板(上的东西):存储器,外围芯片组,扩展插槽(RAM内存条和各类接口卡)通过总线与CPU连接。

CPU通过总线向接口卡发送命令,接口卡通过CPU的命令控制外设(显示器,打印机等)进行工作。

各类存储器芯片:
随机存储器(RAM):易失性,可读可写。
主随机存储器:装在主板和扩展插槽上。
接口卡上的RAM:对大批量输入,输出数据进行暂时储存。
只读存储器(ROM):永久保存。
装有BIOS(基本输入输出系统)的ROM:

4.1KB=1024B 1MB=1024KB 1GB=1024MB 1TB=1024GB(按二进制转化)
8个bit=1个Byte(一个字节)

第二章 寄存器

1.典型CPU
运算器 信息处理
寄存器 信息存储
控制器 控制各种器件进行工作
内部总线(第一章中为外部总线) 各种器件间数据传输
2.寄存器
通用寄存器 AX BX CX DX(16位=AH AL可分为两个独立的8位寄存器)
SI DI
SP BP
IP 指令指针寄存器
段寄存器 CS DS SS ES
(1)CS 代码段寄存器
IP 指令指针寄存器(读取一条指令后,IP中的值自动增加。以字节为单位)
8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行
(2)初始值:CS=FFFFH,IP=0000H
(3)转移指令
jmp指令
jmp 段地址:偏移地址 (同时修改)CS=段地址 IP=偏移地址
jmp 某一合法寄存器 (只修改IP)IP=某一合法寄存器

DS 存放要访问的数据的段地址
使用mov指令时,8086中自动取DS中的数据为内存单元的段地址
不支持将数据直接送入段寄存器的操作,要用一个寄存器进行中转。
区别:CS 用于读取指令 DS 用于存放数据

SS 段寄存器 SP 寄存器
(1)栈顶的段地址:SS 偏移地址:SP(0-FFFFH)
任意时刻,SS:SP指向栈顶元素
出栈数据在内存中不被清空,当再次执行PUSH等入栈指令时被新数据覆盖。
(2)只考虑当前情况,人工避免栈顶超界问题。
3.数制
16进制H
二进制B
十进制
4.汇编指令(不区分大小写)
相加时数据溢出
5.物理地址
8086CPU
物理地址=基础地址+偏移地址
物理地址=段地址*16(起始地址)+偏移地址
小结:
(1)一个段地址的起始地址一定是16的倍数
(2)一个段的长度最大为16KB 0-FFFFH
(3)定义:地址连续,起始地址为16的倍数的一组内存单元
(4)CPU可以用不同的段地址和偏移地址形成同一个物理地址
6.debug
R 查看、改变寄存器的内容(-r+Enter:查看/-r 某一寄存器:修改)
D 查看内存中的内容(-d 段地址:偏移地址:可以查看从指定地址开始的128个内存单元的内容/-d 段地址:起始偏移地址 结尾偏移地址:查看范围)
左边是每行的起始地址、中间是128个内存单元(字节)的内容、右边是内存单元的数据对应的可显示的ASCII码
E 改写内存中的内容(-e 起始地址 数据:修改一列/-e 起始地址:.数据+空格键:修改某个)
(-e 起始地址 数据 ‘字母’:字符/-e 起始地址 数据 “c++/IBM”:字符串)
U 将内存中的内容解释成机器指令和对应的汇编指令(-u 起始地址)
T 执行CS:IP指向的内存单元处的指令
(E向内存中写入机器码,U查看内存中机器码的含义,T执行内存中的机器码)
A 以汇编指令的形式在内存中写入机器指令(-a 起始地址/-a:从预设地址开始)
7.16/8位寄存器中所能存储的数据的最大值是多少?64KB(数量):65536(0~65535)/256(0~255)
段地址的大小怎么算?后面的数减去前面的数+1

第三章 寄存器(内存访问)

1.字节型数据、字型数据(占据2个单元)
N地址字单元:起始地址为N的字单元
2.mov指令(转载)
MOV指令允许进行如下操作:
(1)MOV 寄存器 , 寄存器/内存单元/段寄存器/立即数
(2)MOV 内存单元 , 寄存器/段寄存器/立即数
(3)MOV 段寄存器 , 寄存器/内存单元
MOV指令不允许进行下述操作:
(1). 两个操作数的类型不一致
(2). 两个操作数不能都是存储器
(3). 段寄存器的操作有一些限制:段寄存器属专用寄存器,对他们的操作能力有限
不允许立即数传送给段寄存器,例如:
MOV DS,100H ;非法指令:立即数不能传送段寄存器
不要直接改变CS值,例如MOV CS,[SI] ;
不允许使用的指令
不允许段寄存器之间的直接数据传送,例如:MOV DS,ES ;非法指令:不允许段寄存器间传送
3.add指令(待补充 段寄存器
(1)ADD 寄存器 , 寄存器/内存单元/立即数
(2)ADD 内存单元 , 寄存器
4.栈
8086中入栈出栈都是以字为单位
push指令、pop指令 寄存器、段寄存器、内存单元
(只给偏移地址,段地址默认为DS)
(1) push 指令的执行步骤: SP=SP-2 向SS:SP指向的字单元中送入数据。
(2) pop 指令的执行步骤: 从SS:SP指向的字单元中读取数据 SP=SP+2。
(3)任意时刻,SS:SP指向栈顶元素。
(4)8086CPU 只记录栈顶,栈空间的大小我们要自己管理。
(5)用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反。
(6)push、pop实质上是一种内存传送指令。
PUSH/POP 寄存器/段寄存器/内存单元:将一个内存字单元处的字入栈/出栈,出栈的数据送入内存字单元处。
5.”[数据]”表示一个内存单元,”数据”表示内存单元中的偏移地址。
“.”一字节,“[]”0字节。
6.栈段
一个栈段最大可以设为64k

段的综述
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们的安排。
用一个段存放代码,即代码段
用一个段存放数据,即数据段
用一个段当栈,即栈段
对于数据段,把段地址放在ds中,用mov,add,sub等访问内存单元的指令时,cpu就将我们定义的数据段内容当做数据来访问;
对于代码段,把段地址放在cs:ip中,用mov,add,sub等访问内存单元的指令时,cpu就将执行我们定义的代码段的指令;
对于栈段,把段地址放在ss:sp中,用push pop 等访问内存单元的指令时,cpu就将其当作堆栈来访问;

第四章 第一个程序

汇编指令+伪指令
1.伪指令
assume 假设
assume cs:段名(将有特定用途的(用segment-ends定义的)段和相关的段寄存器关联起来。)
段名 segment
。。。
mov ax,4c00H
int 21H(程序返回指令)

段名 ends(end segment)
end(结束函数)
2.command
DOS中有一个程序command.com(命令解释器),是DOS系统的shell。
在DOS中,command处理我们的各种输入:命令或要执行的程序的文件名。
command首先根据文件名找到可执行文件,然后将这个可执行文件中的程序加载入内存,设置CS:IP指向程序的入口。command停止运行,CPU运行,运行结束后返回到command。
汇编程序从写出到执行的过程:
编程(txt)-0.asm-编译(masm)-0.obj-连接(link)-0.exe-加载(command)-内存中的程序-运行(CPU)
3.PSP
DS=X PSP=X:0 程序物理地址=X+10:0
3.
一个源程序从写出到执行的过程:
1.在文本文件中用汇编语言编写源程序(产生一个“源程序文件”)
2.编译程序(编译器)-目标文件-连接程序-可执行文件(包含:1.程序:机器码 数据 2.相关信息:大小 日期)
3.执行可执行文件

第五章 [bx]和loop指令

1.[bx]和内存单元的描述:
完整描述一个内存单元:内存单元的地址 和 内存单元的(长度)字节/字型。
[bx]把bx中的数据当成偏移地址,表示一个内存单元。
debug中:[idata]是一个内存单元
编译器中:[Idata]=idata->可将地址送入寄存器bx中用[bx]表示或用ds:[idata]表示
loop指令:循环(格式:loop 标号:识别一个地址)
2.
inc指令:目标操作数+1
约定符号idata表示常量“12345等”
“()”中的元素可以是寄存器名,段寄存器名,内存单元的物理地址。
“(X)”的数据类型:字节型,字型(具体看寄存器或相关计算)。
eg.mov ax,[2] (ax)=(ax)+((ds)*16+2)
3.loop指令:循环(格式:loop 标号:识别一个地址)
步骤:
(1).(cx)=(cx)-1
(2)判断cx中的值:如果cx≠0,转至标号处执行(注意IP),否则向下执行。
通常用loop指令实现循环功能,cx中存放循环次数。
mov cx,循环次数
s:循环执行的程序段
loop s
4.汇编中,数据不能以字母开头,在前面加0
5.G指令:一次性执行完标号前的程序。
例如:“g 0012”:将使debug从当前的CS:IP指向的指令执行,一直到(IP=0012)为止。
P指令:一次性执行完循环,直到cx=0,在遇到“loop 偏移地址”时执行。
6.段前缀:
段寄存器:CS(data) SS(stack) ES(expand) DS(code)
7.一段安全的空间
DOS方式下,一般情况,0:200~0:2ff没有系统或其他程序的数据或代码。

第六章 包含多个段的程序

1.程序取得所需空间的方法:
一是在加载程序的时候为程序分配,二是程序在执行的过程中向系统申请。
2.在代码段中使用数据:
DW(define word)定义字型数据,用逗号隔开,开辟内存空间。
DB定义字节型数据。
数据存放在代码段中,CS中存放代码段的段地址。用U命令查看到的是,在汇编指令前,用DW定义的数据。
3.框架:
:assume cs:…
: … segment
: 数据
: start 代码
: … ends
:end start
4.定义多个段
不同 的段有不同的段名。程序中,段名相当于一个标号,代表了段地址。
一个段中的数据的段地址可以由段名代替,偏移地址就要看它在段中的位置。

第七章 更灵活的定位内存地址的方法( 段地址都在ds中)

  1. AND和OR指令:
    AND指令:逻辑与指令,按位进行与运算。将操作对象的相应位设为0,其余不变。
    例如:and al,1111-0111B;将al的第3位设为0
    OR指令:将操作对象的相应位设为1,其余不变。
    例如:or al,0010-0000B;将al的第5位设为1
    2.关于ASCII码:
    以字符形式给出的数据:
    用’……’的方式指明数据是以字符的形式给出,编译器将其转化为对应的ASCII码。
    大小写转换的问题:
    小写字母的ASCII码比大写字母的ASCII码大20H(十六进制)。
    小写字母的第五位为1,大写字母的第五位为0(二进制)。
    3,[bx+idata]:为一个内存单元,偏移地址(bx)+idata (bx中的数值加上idata)
    例如:mov ax,[bx+200]=mov ax,200[bx]=mov ax,[200+bx]=mov ax,[bx].200
    用[bx+idata]的方式进行数组的处理:idata起始偏移地址,bx起始偏移地址的相对地址。
    4.SI和DI:≈BX,不能拆成8位寄存器。
    注意:data:0是要处理的数据所在的位置,根据字符串的长度可以知道存放区域的偏移地址。比如:welcome 偏移地址为7(1个标点符号=1个字)
    [bx+si]和[bx+di]:偏移地址(bx)+(si)/(di) 可写成[bx][si/di]
    [bx+si+idata]:bx:行 si:起始地址的相对地址 idata:起始地址
    5.不同的寻址方式的灵活运用
    (1)【idata】用一个常量来表示地址,可用于直接定位一个内存单元;
    (2)【bx】用一个变量来表示内存地址,可用于间接定位一个内存单元
    (3)【bx+idata】用一个变量加一个常量来表示内存地址,可在一个起始地址的基础上用变量间接定位一个内存单元
    (4)【bx+si】用两个变量表示地址
    (5)【bx+si+idata】用两个变量和一个常量来表示地址
    6.一般来说,暂存数据用栈。

第八章 数据处理的两个基本问题

1.reg和sreg reg(表示一个寄存器):ax,bx,cx,dx, ah,al,bh,bl,ch,cl,dh,dl ,sp,bp,si,di sreg:ss,cs,ds,es 2.BX SI DI BP:“[…]” (1)[BX-SI/DI] [BP-SI/DI] (2)**bp+bx si+di不可以用** (3)只要在“[…]”中使用寄存器bp,而且没有显性地给出段地址,段地址就默认在ss中。(涉及栈?) bx默认在ds中。 3.机器指令处理前数据所在位置:CPU内,内存,端口。 4.汇编语言中数据位置的表达: 立即数(idata):直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中)。 寄存器:指令要处理的数据在寄存器中 段地址(SA):偏移地址(EA):指令要处理的数据在内存中 “[]”给出EA,SA在某个段寄存器中,段寄存器可以默认。 5.寻址方式:给定内存单元的偏移地址。 ![这里写图片描述](https://img-blog.csdn.net/20180111184951757?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzgyMzkyODI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 6.指令要处理的数据有多长:字/字节 通过寄存器名指明数据类型/用操作符Xptr指明内存单元长度,X在汇编指令中可以为word或byte/其他方法:(没有寄存器名) :mov word ptr [1000h],2;2000:1000 02 00 ff…;字单元
mov byte ptr[1000h],2;2000:1000 02 ff ff…;字节单元
push:字
7.寻址方式的综合应用:
确定位置:起始地址和起始地址的相对地址;字符修改:确定字符在数组中的位置。
一般来说,我们可以用[bx+si+idata]的方式来访问结构体中的数据, 用bx定位整个结构体,用idata定位结构体中的某个数据项(相对地址),用si定位数组项中的每个元素。
[bx].idata [bx].idata.si
8.DIV指令:除法:在除法算式中,除号后面的数叫做除数。
除数:有8位或16位两种,在一个寄存器reg或内存单元中。(除四个段寄存器为sreg外其他均为reg)
被除数:默认在AX或AX和DX中:如果除数为8位,被除数为16位,放在AX中;如果除数为16位,被除数为32位,高16位放在DX中,低16位放在AX中。
结果:如果除数为8位,则AL存储商,AH存储余数;如果除数为16位,则AX存储商,DX存储余数。
格式:div reg/div 内存单元
例如:div byte ptr ds:[0];(al)=(ax)/((ds)*16+0)的商
(ah)=(ax)/((ds)*16+0)的余数
: div word ptr es:[0];(ax)=[(dx)*10000h+(ax)]/((es)*16+0)的商
(dx)=[(dx)*10000h+(ax)]/((es)*16+0)的余数
9. db 定义字节型数据,
dw定义字型数据,
dd定义双字型数据:00h-0000h-0000 0000h
DUP:数据重复
dd X dup(Y);dd Y,Y,Y….:字节数=XY;X=重复次数

第九章 转移指令的原理

1.可以修改IP或同时修改CS和IP的指令统称为转移指令。概括的讲,转移指令就是可以控制CPU执行内存中某处代码的指令。
8086CPU:
段内转移:只修改IP:jmp ax/段间转移:修改CS:IP:jmp 1000:6
段内转移:短转移:-128~127/近转移:-32768~32767
转移指令:
无条件转移指令:jmp
条件转移指令
循环指令:loop
过程
中断
2.操作符 offset:(编译器:取得标号的偏移地址)
3.JMP指令(无条件转移指令):转移的目的地址+转移的距离(段间转移,段内短转移,段内近转移)
不同的给出目的地址的方法,不同的转移位置,对应有不同格式的jmp指令。
(1)依据位移进行转移的jmp指令:jmp short 标号:(转移到标号处执行指令)段内短转移 IP:-128~127
CPU在执行jmp指令时并不需要转移的目的地址。
8位位移=“标号”处的地址-jmp指令下一指令第一个字节的地址
8位位移的范围:-128~127,用补码表示
8位位移由编译程序在编译时算出
jmp near ptr标号:段内近转移 (IP)=(IP)+16
(2)转移的目的地址在指令中的jmp指令:jmp far ptr 标号:段间转移(远zhaunyi) 高位段地址,低位偏移地址。

(3)转移地址在寄存器中的jmp指令:jmp 16位寄存器(reg):(IP)=(16位寄存器)

(4)转移地址在内存中的jmp指令: :*jmp word ptr 内存单元地址*(段内转移)::从内存单元地址处开始存放一个字,是转移的目的偏移地址 (IP)=(内存单元地址) :*jmp dword ptr 内存单元地址*(段间转移):从内存单元地址处开始存放两个字,高-段地址,低-偏移地址。 (CS)=(内存单元地址+2) (IP)=(内存单元地址) 4.JCXZ指令:条件转移指令:短转移:机器码包含到目的地址的**位移**:IP:-128~T127 格式:jcxz 标号:如果(cx)=0则转到标号处执行。 操作:但(cx)=0时,(IP)=(IP)+8: 相当于If((cx==0)jmp short 标号; 5. loop指令:循环指令:短转移 操作: (cx)=(cx)-1;如果(cx)!=0,(IP)=(IP)+8: 相当于(cx)=(cx)– If((cx!=0)jmp short 标号; 6.dec指令:(dx)=(dx)-1 inc指令:(dx)=(dx)+1 7.根据位移进行转移的意义:方便程序段在内存中的滚动装配 8.编译器对转移位移超界的检测:“jmp 2000:10”是在debug中使用的汇编指令,汇编编译器并不认识。如果在源程序中使用,编译时也会报错。 **第十章 call和ret指令:编写子程序** 1.RET和RETF:使用栈中的数据 **ret指令**:修改ip,*近转移*: **pop ip** 一.(ip)=((ss)*16+(sp)) 二.(sp)=(sp)+2 push ip **retf指令**:修改cs:ip,*远转移*: **pop ip** **pop cs**(注意顺序) 一. (ip)=((ss)*16+(sp)) 二. (sp)=(sp)+2 三. (cs)=((ss)*16+(sp)) 四. (sp)=(sp)+2 push cs push ip 2.CALL指令:(不能实现短转移) 一. 将当前的IP或CS:IP压入栈中 二. 转移 (1)根据位移进行转移的call指令: 格式:*call 标号*(将当前的ip压入栈后,转到标号处执行指令) push ip jmp near ptr 标号 一.(sp)=(sp)-2 ((ss)*16+(sp))=(ip) 二.(ip)=(ip)+16位位移 16位位移=“标号”处地址-call指令下一指令第一个字节的地址: 范围:-32768~T32767 (2)转移的目的地址在指令中的call指令: *call far ptr 标号*:段间转移 push cs push ip jmp far ptr 标号 一.(sp)=(sp)-2 ((ss)*16+(sp))=cs (sp)=(sp)-2 ((ss)*16+(sp))=ip 二.(CS)=标号所在段的段地址 (IP)=标号在段中的偏移地址 (3)转移地址在寄存器中的call指令: :*call 16位寄存器* push ip jmp 16位寄存器 :(sp)=(sp)-2 ((ss)*16+(sp))=ip (ip)=(16位寄存器) (4)转移地址在内存中的call指令: *call word ptr 内存单元地址* push ip jmp word ptr 内存单元地址 *call dword ptr 内存单元地址* push cs push ip jmp dword ptr 内存单元地址 3.CALL和RET的配合使用: :assume cs:code :code segment :start: :
call Q
:
mov ax,4c00
int 21
Q:
:
ret;返回到call指令的下条指令
:code ends
:end start
4.MUL指令:乘法指令
一. 两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位寄存器或内存字节单元中。如果是16位,一个默认放在AX中,另一个放在16位寄存器或内存字单元中。
二. 结果:如果是8位乘法,结果默认放在 AX中。如果是16位乘法,结果 高位默认在DX中存放,低位在AX中存放
格式:mul reg mul 内存单元
5.模块化程序设计:
参数和结果传递的问题:
子程序根据提供的参数处理问题,处理后,将结果(返回值)提供给调用者。
参数和结果的存储:
少量:寄存器
大量:内存单元:将批量数据放在内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序。
6.子程序的标准框架:
子程序开始:子程序使用的寄存器入栈
子程序内容
子程序中使用的寄存器出栈
返回(ret、retf)

第十一章 标志寄存器

1.标志寄存器flag:8086CPU:16位:存储的信息:程序状态字(PSW)
作用:用来存储相关指令的某些执行结果,用来对CPU执行相关指令提供行为依据,用来控制CPU的相关工作方式。
这里写图片描述
ZF标志(6):零标志位,记录相关指令执行后,结果是否为0。
如果为0,则zf=1;否则,则zf=0。
注意:不影响标志寄存器的指令:push,pop,mov
影响标志寄存器的指令:add加,sub减,mul乘,div除,inc加一,or,and
PF标志(2):奇偶标志位,记录相关指令执行后,其结果的二进制中1的个数是否为偶数。如果为偶数,则pf=1;为奇数,则pf=0。
SF标志(7):符号标志位,记录相关指令执行后,结果是否为负。
如果为负,则sf=1;非负,则sf=0。
在计算机中用补码表示有符号数据:2进制8位:-128~127
注意:将结果化为2进制的16位数或8位数,看左边第一位,为0则sf=0,否则sf=1。
CF标志(0):进位标志:一般情况下,在进行无符号数运算时,它记录了运算结果的最高有效位向更高位的进位值,或向更高有效位的借位值:0~255
有进位或借位CF=1,否则CF=0。
注意:inc和loop指令不影响CF。
对位数为N的无符号数来说,其对应的二进制的最高有效位为第N-1位,而假象的第N位为更高位。
OF标志(11):溢出标志位:有溢出:of=1,否则of=0
在进行有符号数的运算时,运算结果超过了机器所能表示的范围称为溢出。
注意:有溢出/进位/借位的数要存放在OF【有符号数】/CF【无符号数】(标志寄存器)中,而不是寄存器中。
8位数的表示范围:-128~127:-80H~7FH
16位数的表示范围:-32768~32767:-8000H~7FFFH
注意:二进制8位数左边第一位如果是0则不用写补码。
二进制8位数对应的十六进制:00H~FFH
DF标志(10)和串传送指令:方向标志位
:df=0 每次操作后si,di递增
:df=1每次操作后si,di递减
串传送指令:
movsb:字节将ds:[si] 送入 es:[di],然后根据标志寄存器df位的值,将si和di递增或递减。
功能:mov es:[di], byte ptr ds:[si] ;只是一个描述
if de=0:
inc si
inc di
if de=1:
dec si
dec di
movsw:字:di,si递增2或递减2
REP MOVSB/MOVSW:循环实现(cx)个字符的传送。
s movsb/movsw
loop s
cld指令:de=0:正向传送
std指令:de=1
1.传送的原始地址
2.传送的目的地址
3.传送的长度
4.传送的方向
2.adc指令:带进位加法指令,利用了CF位上记录的进位值。
格式:adc 操作对象a,操作对象b;操作对象可以是数字
功能:a=a+b+CF
sbb指令:带借位减法指令
:sbb ax,bx;功能:(ax)=(ax)-(bx)-CF
cmp 指令:比较指令:结果保存在CPU暂存器中
做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较结果:
cmp ax,bx:无符号数:
这里写图片描述
(有/无符号数)根据ZF判断两个数是否相等。
判断逻辑上真正结果的正负与实际结果的正负,得知比较的结果:cmp ah,bh:
这里写图片描述
总结:sf=1,of=0;sf=0,of=1 ah小于bh
sf=1,of=1 ah大于bh
sf=0,of=0 ah大于等于bh
3.检测比较结果的条件转移指令:
转移:指它可以修改IP
条件:指它可以根据某种条件决定是否修改IP:条件转移指令的转移位移[-128~127]
条件转移指令和cmp:表示比较结果的标志位。
根据无符号数的比较结果进行条件转移的指令:CF ZF
根据有符号数的比较结果进行条件转移的指令:SF OF ZF
e=equal ne=not equal b=below nb=not below a=above na=not above j=jmp
这里写图片描述
4.PUSHF和POPF:
pushf将标志寄存器中的数据压入栈,popf从栈中弹出数据,送入标志寄存器。
5.标志寄存器在DEBUG中的表示:
这里写图片描述

第十二章 内中断

1.内中断的产生
cpu内部发生下面情况时,将产生相应的中断信息:
(1)除法错误:0(2)单步执行:1(3)执行int0命令:4(4)执行int命令:n
中断类型码0 1 4 n 为一个字节型数据
2.中断向量表
中断向量表就是中断处理程序入口地址的列表。保存在内存中。
对于8086中断向量表指定存在内存地址0处。从0000:0000到0000:03e8单元。共1000个字节。中断向量表中一个表项存放一个中断向量,占两个字。分别存放段地址和偏移地址。
3.中断过程
(1)从中断信息中取得中断类型码
(2)标志寄存器的值入栈
(3)设置标志寄存器的第八位TF和第九位IF的值为0
(4)CS的内容入栈
(5)IP的值入栈
(6)从内存地址为中断类型码*4和中断类型码*4 + 2 的两个字单元中读取中断处理程序的入口地址设置IP和CS
4.中断处理程序
(1)保存用到的寄存器
(2)处理中断。
(3)恢复用到的寄存器
(4)用IRET指令返回
第十三章 int指令
1. int指令
格式:int n,n为中断类型码,功能是引发中断过程
2. int指令和iret指令配合使用与call指令和ret指令配合使用具有相似的思路。
3. BIOS和DOS所提供的中断例程
BIOS主要包含以下内容:
(1)、硬件系统的检测和初始化程序
(2)、外部中断和内部中断的中断例程
(3)、用于对硬件设备进行I/O操作的中断例程
(4)、其他和硬件系统相关的中断例程
4. BIOS和DOS中断例程的安装过程
(1).开机后,cpu一加点,初始化(cs)= 0FFFFH,(IP)= 0,自动从FFFF:0单元开始执行程序。FFFF:0处有一条跳转指令,cpu执行该程序后,转去执行BIOS中的硬件检测和初始化程序。
(2).初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口登记在中断向量表中。注意,对于BIOS所提供的中断例程,只需将入口地址登记在中断向量表中即可,因为它们是固化到ROM中的内容,一直在内存中存在。
(3).硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导。从此将计算机交给操作系统控制。
(4).DOS启动后,除完成其他工作外,还将它提供的中断例程装入内存,并建立相应的中断向量。
5. DOS中断例程应用
例如 我们一直在使用的4ch号子程序,即程序返回功能。
mov ah 4ch
mov al 0
int 21h

DOS功能调用 int 21h
(1)键盘输入
1) 1号调用——从键盘输入单个字符
调用格式: MOV AH,1
INT 21H
功能: 等待从键盘输入一个字符并送入AL。
执行时系统将扫描键盘,等待有健按下,一旦有健按下,就将其字符的ASCII码读
入,先检查是否Ctrl-Break,若是,退出命令执行;否则将ASCII码送AL,同时将
该字符送显示器显示。
2) 10号调用——从键盘输入字符串
功能: 从键盘接收字符串送入内存的输入缓冲区,同时送显示器显示。
调用前要求: 先定义一个输入缓冲区
MAXLEN DB 100 ;第1个字节指出缓冲区能容纳的字符个数,即缓冲区长度,不能为0
ACLEN DB ? ;第2个字节保留,以存放实际输入的字符个数
STRING DB 100 DUP(?) ;第3个字节开始存放从键盘输入的字符串。
调用格式: LEA DX,MAXLEN(缓冲区首偏移地址)
MOV AH,10
INT 21H
(2)显示输出
1) 2号调用——在显示器上显示输出单个字符
调用格式: MOV DL,待显示字符的ASCII码
MOV AH,2
INT 21H
功能:将DL中的字符送显示器显示。
【例】显示输出大写字母A
MOV DL,41H ;或写为 MOV DL,’A’
MOV AH,2
INT 21H
2) 9号调用——在显示器上显示输出字符串
调用格式: LEA DX,字符串首偏移地址
MOV AH,9
INT 21H
功能:将当前数据区中DS:DX所指向的以’ YOUARESUCESSFUL!DATASEGMENTSTRINGDBYOUARESUCESSFUL!
DATA ENDS
CODE SEGMENT
… …
MOV AX,DATA
MOV DS,AX
LEA DX,STRING
MOV AH,9
INT 21H
… …
CODE ENDS
说明:若希望显示字符串后,光标可自动回车换行,可在定义字符串时作如下更改:
STRING DB ’ YOU ARE SUCESSFUL! ’ ,0AH,0DH,’ $ ’ ;在字符串结束前加回车换行的ASCII码0AH,0DH

第十四章 端口

1.端口的读写
在PC系统中,CPU最多可以定位64KB个不同的端口,则端口地址的范围为0~65535
端口的读写指令只有两条:in和out,分别用于从端口读写数据和往端口写入数据。
在in和out指令中,只能使用ax或al来存放从端口中读入的数据或要发送到端口中的数据。 访问8位端口时用al,访问16位端口时用ax。
对0~255以内的端口进行读写时:
in al,20h ;从20h端口读入一个字节
out 20h,al ;往20h端口写入一个字节
对256~65535的端口进行读写时,端口号放在dx中:
mov dx,3f8h ;将端口号3f8h送入dx
int al,dx ;从3f8h端口读入一个字节
out dx,al ;向3f8h端口写入一个字节
2. PC机中,有一个CMOS RAM芯片,一般简称CMOS。此芯片有以下特征:
1) 包含一个实时钟和一个有128个存储单元的RAM存储器(早期的计算机为64个字节)。
2) 该芯片靠电池供电。所以,关机后期内部的实时钟仍可正常工作,RAM中的信息不丢失。
3) 128个字节的RAM中,内部实时钟占用0~0dh单元来保存时间信息,其余大部分单元用于保存系统配置信息,供系统启动时 BIOS程序读取。BIOS也提供了相关的程序,使我们可以在开机的时候配置 CMOS RAM中的系统信息。
4) 该芯片内部有两个端口,端口地址为70h和71h。CPU通过这两个端口来读写CMOS RAM
5) 70h为地址端口,存放要访问的CMOS RAM单元的地址;71h为数据端口,存放从选定的CMOS RAM单元中读取的数据,或要写入到其中的数据。
CPU对CMOS RAM的读写分两步进行,如读 CMOS RAM 的2号单元:
1) 将2送入端口70h;
2) 从端口71h读出2号单元的内容。
3. shl和shr指令
shl是逻辑左移指令(*2),它的功能为:
1) 将一个寄存器或内存单元中的数据向左移位;
2) 将最后移出的一位写入CF中;
3) 最低位用0补充。
shr是逻辑右移指令(/2),它和shl所进行的操作刚好相反。
1) 将一个寄存器或内存单元中的数据向右移位;
2) 将最后移出的一位写入CF中;
3) 最高位用0补充。
如果移动位数大于1时,必须将移动位数放到cl中。如果只移动一位,则可以直接写出来。
4.CMOS RAM 中存储的时间信息
在CMOS RAM中,存放着当前的时间:年、月、日、时、分、秒。这6个信息的长度都为1个字节,存放单元为:
秒:0 分:2 时:4 日:7 月:8 年:9
这些数据以BCD码的方式存放。BCD码是以4位二进制数表示十进制码的编码方法。
一个字节可表示两个BCD码。则CMOS RAM存储时间信息的单元中,存储了用两个BCD码表示的两位十进制数,高4位的BCD码表示十位,低4位的BCD码表示个位。
BCD码值+30h=十进制数对应的ASCII码

第十四章 外中断

1.在PC系统中,外中断源一共有以下两类:
1) 可屏蔽中断(需要取中断类型码)
可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器的IF位的设置。当CPU检测到可屏蔽中断信息时,如果I*F=1,则CPU在执行完当前指令后响应中断,引发中断过程;如果IF=0,则不响应可屏蔽中断。*
将IF置0的原因就是,在进入中断处理程序后,禁止其他的可屏蔽中断。当然,如果在中断处理程序中需要处理可屏蔽中断,可以用指令将IF置1。
设置IF的指令:
sti 设置IF=1
cli 设置IF=0
2) 不可屏蔽中断:2(不需要取中断类型码)
不可屏蔽中断是CPU必须响应的外部中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程
2.PC机键盘的处理过程
(1)键盘中有一个芯片对键盘上的每一个键的开关状态进行扫描。按下一个键时,开关接通,该芯片就产生一个扫描码,扫描码说明了按下的键在键盘上的位置。扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60h。松开按下的键时,也产生一个扫描码,扫描码说明了松开的键在键盘上的位置。松开按键时产生的扫描码也被送入60h端口中。
一般将按下一个键时产生的扫描码称为通码,松开一个键产生的扫描码称为断码。扫描码长度为一个字节,通码的第7位为0,断码的第7位为1,即:断码=通码 + 80h
(2)键盘的输入到达60h端口时,相关的芯片就会向CPU发生中断类型码为9的可屏蔽中断信息。CPU检测到该中断信息后,如果IF=1,则响应中断,引发中断过程,转去执行int 9h中断例程
执行int 9h中断例程
BIOS提供了int 9h中断例程,用来进行基本的键盘输入处理,主要的工作如下:
1) 读出60h端口中的扫描码;
2) 如果是字符键的扫描码,将该扫描码和它所对应的字符码(即ASCII码)送入内存中的BIOS键盘缓冲区;如果是控制键(如Ctrl)和切换键(如CapsLock)的扫描码,则将其转变为状态字节(用二进制位记录控制键和切换键状态的字节)写入内存中存储状态字节的单元;
3) 对键盘系统进行相关的控制,如:向相关芯片发出应答信息。
BIOS键盘缓冲区是系统启动后,BIOS用于存放int 9中断例程所接收的键盘输入的内存区。该内存区可以存储15个键盘输入,因为int 9中断例程除了接收扫描码外,还要产生和扫描对应的字符码,所以在BIOS键盘缓冲区中,一个键盘输入用一个字单元存放,高位字节存放扫描码,低位字节存放字符码。
(3) 0040:17单元存储键盘状态字节,该字节记录了控制键和切换键的状态。键盘状态字节各位记录的信息如下:
0:右shift状态,置1表示按下右shift键;
1:左shift状态,置1表示按下左shift键;
2:Ctrl状态,置1表示按下Ctrl键;
3;Alt状态,置1表示按下Alt键;
4:ScrollLock状态,置1表示Scroll指示灯亮;
5:NumLock状态,置1表示小键盘输入的是数字;
6:CapsLock状态,置1表示输入大写字母;
7:Insert状态,置1表示处于删除态;
3. 键盘输入的处理过程:
1) 键盘产生扫描码;
2) 扫描码送入60h端口;
3) 引发9号中断;
4) CPU执行int 9中断例程(自行设计处)处理键盘输入。

第十六章 直接定址表

1.数据标号
这种标号不但表示内存单元的地址,还表示了内存单元的长度,即表示在此标号处的单元,是一个字节单元,还是字单元,还是双字单元。如
a:db 1,2,3,4,5,6,7,8 改写为 a db 1,2,3,4,5,6,7,8
b:dw 0 改变为 b dw 0
使用不带“:”的标号,它们是同时描述内存地址和单元长度的标号。这种标号包含了对单元长度的描述,所以,在指令中,它可以代表一个段中的内存单元。
2. 在其他段中使用数据标号
在后面加有“:”的地址标号,只能在代码段中使用,不能再其他段中使用。
如果想在代码段中直接用数据标号访问数据,则需要用伪指令assume将标号所在的段和一个段寄存器联系起来。否则编译器在编译的时候,无法确定标号的段地址在哪一个寄存器中。
可以将标号当做数据来定义,此时,编译器将标号所表示的地址当做数据的值。
seg操作符,功能为取得某一标号的段地址。
2.直接定址表
在建立数据映射关系时,有时在数值计算方面找不到一致性的规律或者规律过于繁琐,可以使用在内存中构建表,以查表的方式来建立这种映射。
我们将通过给出的数据进行计算或比较而得到结果的问题,转化为用给出的数据作为查表的依据,通过查表得到结果的问题。具体的查表方法,是用查表的依据数据,直接计算出所要查找的元素在表中的位置。像这种可以通过依据数据,直接计算出所要找的元素的位置的表,我们称其为:直接定址表。
3. 程序入口地址的直接定址表
我们可以在直接定址表中存储子程序的地址,从而方便地实现不同子程序的调用。
用根据功能号查找地址表的方法,程序的结构清晰,便于扩充。如果加入一个新的功能子程序,那么只需要在地址表中加入它的入口地址就可以。

第十七章 使用BIOS进行键盘输入和磁盘读写

  1. int 9 中断例程对键盘输入的处理
    键盘输入将引发9号中断,BIOS提供了int9中断例程。CPU在9号中断发生后,执行int 9中断例程,从60h端口读出扫描码,并将其转化为相应的ASCII码或状态信息,存储在内存的指定空间(键盘缓冲区或状态字节)中。
    一般的键盘输入,在CPU执行完int 9中断例程后,都放到了键盘缓冲区中。键盘缓冲区中有16个字单元,可以存储15个按键的扫描码和对应的ASCII码。
  2. 使用int16h中断例程读取键盘缓冲区
    int 16h中断例程中包含的一个最重要的功能是从键盘缓冲区中读取一个键盘输入,该功能的编号为0。下面的指令从键盘缓冲区中读取一个键盘输入,并且将其从缓冲区中删除。
    mov ah,0
    int 16h
    结果: (ah)=扫描码,(al)=ASCII码
    1) 检测键盘缓冲区中是否有数据;
    2) 没有则继续做第1步;
    3) 读取缓冲区第一个字节单元中的键盘输入;
    4) 将读取的扫描码送入ah,ASCII码送入al;
    5) 将已读取的键盘输入从缓冲区中删除。
    BIOS的int 9中断例程和int 16h中断例程是一对相互配合的程序,int 9中断例程向键盘缓冲区中写入,int 16h中断例程从缓冲区中读出。它们写入和读出的时机不同,int 9中断例程是在有键按下的时候向键盘缓冲区中写入数据;而int 16h中断例程是在应用程序对其进行调用的时候,将数据从键盘缓冲区中读出。
    3.字符串的输入(栈的方式)
    功能:
    1) 在输入的同时需要显示这个字符串;
    2) 一般在输入回车符后,字符串输入结束;
    3) 能够删除已经输入的字符。
  3. 应用int13h中断例程对磁盘进行读写
    3.5英寸软盘分为上下两面,每面有80个磁道,每个磁道又分为18个扇区,每个扇区的大小为512个字节。则:2面*80磁道*18扇区*512字节=1440KB~=1.44MB
    磁盘的实际访问由磁盘控制器进行,我们可以通过控制磁盘控制器来访问磁盘。只能以扇区为单位对磁盘进行读写。在读写扇区的时候,要给出面号、磁道号和扇区号。面号和磁道号从0开始,而扇区号从1开始。
    BIOS提供的访问磁盘的中断例程为int 13h。
  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嗨!对于逆向学习汇编语言学习笔记,我可以给你一些基本的指导。首先,汇编语言是一种低级语言,它与计算机的底层硬件密切相关。逆向工程则是通过分析和理解已编译的程序来获取程序的内部信息。 以下是一些学习汇编语言和逆向工程的建议: 1. 学习基础知识:了解计算机体系结构、寄存器、内存和指令集等基础概念是必要的。可以先阅读相关的书籍或在线教程,掌握这些基本概念。 2. 掌握汇编语言的语法和指令集:每种计算机体系结构都有自己的汇编语言语法和指令集。选择一种你感兴趣的体系结构(如x86、ARM等),并学习它的汇编语言。 3. 练习编写和调试汇编代码:通过编写简单的汇编代码来熟悉语法和指令集。使用调试器来单步执行代码并观察寄存器和内存的变化。 4. 分析已编译程序:选择一个目标程序进行逆向分析。使用反汇编器将程序转换为汇编代码,并分析代码的逻辑和功能。这有助于理解程序的结构和运行过程。 5. 使用调试器进行动态分析:通过调试器来动态地执行程序,并观察程序在运行时的行为。使用断点、内存查看器和寄存器查看器等工具来分析程序的状态和据。 6. 学习逆向工程工具和技术:了解常用的逆向工程工具和技术,如IDA Pro、OllyDbg、Ghidra等。掌握这些工具的使用可以提高你的逆向分析能力。 7. 参考优秀资源:阅读与逆向工程和汇编语言相关的书籍、论文和博客,关注相关的社区和论坛。与其他逆向工程师交流经验也是很有帮助的。 记住,逆向工程是一个需要耐心和实践的过程。持续学习和实践将帮助你提高逆向分析的技能。祝你在学习汇编语言和逆向工程的过程中取得好成果!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值