汇编语言入门学习成果万字总结

本文详细介绍了8086汇编语言在DosBox环境下的使用,包括挂载命令、调试、编译及运行程序的方法。讲解了8086CPU的寄存器、内存地址计算、数据存储方式、段寄存器、字符串操作、转移指令、除法和乘法指令、标志寄存器、中断、串传送指令等内容,深入浅出地阐述了汇编语言的基础知识和实践经验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(汇编环境是基于DosBox环境下的8086汇编)

(文章有些长,可以翻看文章目录选择需要的知识点)

一:简述一下DosBox的使用

首先将masm文件放在D盘目录下,然后打开DosBox,先输入一下内容挂接,即
mount c d:\masm
c:
(注意每次重新打开DosBox都要重新输入上面的2行代码)

然后介绍三种基本用法,都是在上面的基础上进行的。
用法一(对已有exe文件,对其进行debug调试):
在DosBox中,接着输入下面内容对某个exe文件进行调试:
debug 文件名.exe
用法二(现在不存在exe文件,要连接编译出exe文件):
masm 文件名;
link 文件名;
注意:输入masm这一行代码后如果报错,要返回代码中去修改
在这里插入图片描述
上面这张图片就报错了,原因是注释前没加;这个注释符,如果正常的话如下图:(当然出现错误还有其他原因,数量太多,不在列举)
在这里插入图片描述
只要图片中明确了0 Severe Errors即成功。
用法三(已有exe文件,但不想debug调式,直接运行):
文件名.exe
;(这条指令可以结合用法二一起使用)

另外,关于debug 下的D命令,E命令,U命令,A命令,T命令,Q命令,G命令也要掌握,这里就不再赘述,对于程序员来说,遇到不会的问题自己上网解决是一种好习惯哟!!!

开胃菜结束,下面开始上硬菜。

二:关于8086CPU的14个寄存器(每个都是16位,可以存4个16进制数或者16个2进制数)

1.通用寄存器:AX,BX,CX,DX(这4个寄存器都可以拆成两个8位寄存器使用,比如AX分成AH,AL,H存放高8位,L存放低8位)
2.变址寄存器:SI,DI
3.指针寄存器:SP,BP
4.指针指令寄存器:IP
5.段寄存器:CS,SS,DS,ES
6.标志寄存器:PSW

在debug下给寄存器赋值方式:
1)通过R指令:RAX
2)借助通用寄存器:
MOV AX,1000H
MOV CS,AX
以上两种方式普适于所有寄存器,下面还有一种方式,不过仅适用于通用寄存器:
MOV AX,1000H
每个寄存器的具体用法都会在下文展现。

三:确定内存物理地址的方法

其实就是要把两个16位的地址合成一个20位的地址(或者这样说:将2个由4个16进制数组成的小地址转换为一个由5个16进制数组成的大地址),因为在学习汇编时我们通常是以16进制进行地址转换。
举例:
CS段地址为1234,偏移地址IP的地址为5678,,那么由他们确定的地址就是12340+5678=179B8(H)
也就是内存地址=段地址*10+偏移地址(不过这个这个公式里所有数包括10都是16进制的,16进制的10转换成10进制是16)。

四:数据在内存中存放形式

这里以字在内存的存放为例(8086中一个字是16位,不要和字节概念搞混)
如果你明确了大端小端这两个概念,那我只需要告诉你8086是小端,OK,你可以直接去看第五大部分了,那如果你对小端这个概念不清楚呢,我们一起接着来学:
小端模式:是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。

0号地址单元20
1号地址单元4E
2号地址单元50

假设上面的表格右侧部分是内存中的数据,那么从0号单元地址取出长度为一个字的数据是4E20,从1号单元取出长度为一个字的数据是504E。
为什么是这个结果呢?我们可以拿出一组2进制数据‘101000010101111’,通过这个数据我们知道,越往右侧的,位数越低,最右边的是2的零次幂,最左侧的是2的14次幂,同理对于504E也是这样,左侧的比右侧的位数高,放到内存地址单元里也一样,0号单元相当于0次幂,1号单元相当于1次幂…

以此类推,数据在寄存器也是这个小端规则。举例:
MOV AX,4E20H

AH4E
AL20

五:四大段寄存器(DS,CS,SS,ES)

对于段寄存器的赋值一般分为两步(也就是上面第二个大标题中提到的向寄存器赋值的第二种方式):①通常先将地址存放进通用寄存器,②然后将通用寄存器的值整体赋给DS,而通用寄存器我们一般选用AX或DX,因为BX和CX有一些特殊用途,以下会讲到。
那么关于第一步也就是向通用寄存器赋值有以下几种方式:
常见寻址用法:
1)直接寻址
MOV AX,DS:[常数地址]
2)寄存器间接寻址
MOV AX,DS:[BX]
3)寄存器寻址
MOV AX,BX
4)寄存器相对寻址
MOV AX,[BX+常数] 等价于 MOV AX,200[BX] 等价于 MOV AX,[BX].200
5)基址变址寻址
MOV AX,[BX+SI]或者MOV AX,[BX+DI]或者MOV AX,[BP+SI]或者MOV AX,[BP+DI]
6)相对基址变址寻址
MOV AX,[BX+SI+常数] 等价于 MOV AX,常数[BX][SI] 等价于 MOV AX,[BX][SI].常数 等价于 MOV AX,[BX].常数[SI]
这里也和基址变址寻址一样,中括号里的BX和SI也都可以替换。
7)以上使用方式的注意事项:
4个通用寄存器中只有BX可以放到中括号里,其他3个都不可,可以放到中括号里的寄存器还有SI,DI,BP,这4个寄存器可以组合使用,不过BP,BX寄存器不能同时出现在一个中括号里,而且SI,DI也不能同时在一个中括号里出现。另外BX寄存器使用时不加段前缀默认是DS段,BP默认是ES段。
还有段前缀的使用,如果中括号里只有常数,一定要加上段前缀DS或者ES。反正遇到中括号就加段前缀一定是没错的。

一个小问题:
学了这么多了,真的学会了吗?检验一下吧。题目是这样的:在8086中,存储器是分段组织,那么每段最大长度是多少呢?

答案藏在下文,仔细阅读完下文答案就出现了哦。

下面具体讲一讲这三个段分别是做什么的。
数据段DS:存放数据的段(定义变量的段),可以理解成高级语言中写代码前先要定义变量和初始化数据,不过数据类型只有DB,DW,DD三种类型。
DB型数据占一个字节,DW型数据占一个字,DD型数据占两个字长度。
代码段CS:程序除了数据和栈以外的所有指令都在代码段,一个程序可以没有数据段和栈段,但一定要有代码段
栈段SS:和SP寄存器一块使用。申请一块内存区域用作栈区。
附加段ES:ES和DS的功能相同,当你觉得一个数据段不够用时即程序设有多个数据段时,可以选用ES寄存器。一般在串处理时用得比较多。可以BP寄存器一起使用。
注意:数据段和栈段的内容都可以写在代码段,不过为了规范化程序运行,一般分成3个段或4个段。

六:字符串问题

字符串放在单引号里,编译器将把他们转换成对应的ASCII(一个字符占一个字节,空格也是一个字符)
字符和字符串只能用DB型,不能用DW和DD。

DB ‘…’
如果在数据段这样定义了一个字符串,相当于高级语言定义了一个空的字符数组。单引号下有几个点,表示可以存放最大长度为几的字符串。

七:转移指令,标号,offset指令

1.分类
(1)按转移行为分类

段内转移只修改IP
段间转移同时修改IP和CS

(2)根据指令对IP修改的范围不同分类

段内短转移(8位偏移)IP∈(-128~127)
段内近转移(16位偏移)IP∈(-32768~32767)

(3)按转移指令分类

无条件转移jmp
条件转移指令jcxz
循环指令loop
过程调用call ,ret
中断int

2.jmp指令(可以只修改IP的值,也可以同时修改IP和CS的值)。
只修改IP的值有三种情况:
(1)jmp ax
(2)jmp short 地址标号(8位地址偏移)
(3)jmp near ptr 地址标号 (16位地址偏移)相当于 jmp word ptr 地址标号
同时修改CS和IP的情况:
(1)jmp 1000:0
(2)jmp far ptr 地址标号(32位地址偏移)相当于 jmp dword ptr 地址标号
另外,同样可以用jmp指令调用子程序。
3.jcxz指令
当CX寄存器值为0时跳转到地址标号位置
使用方式:jcxz 地址标号
4.loop指令
个人感觉是最贴近高级语言循环的指令。
此指令需要结合CX寄存器一起使用,一般先向CX赋初值,赋值为几就循环几次,不过有一种特殊情况:如果赋值CX值为0,并不是执行0次,而是执行FFFF+1次,这是因为当执行loop这一条指令时,首先将CX的值减一然后判断CX的值是否为0,只有等于0才能结束循环,所以如果给CX赋值为0,先减1变成FFFF,FFFF不等于0,循环继续,然后一直到CX减到0。
使用格式
地址标号:
指令

指令
loop 地址标号
5.ret指令和retf指令(用到栈)
ret指令:从栈顶取出数据修改IP的内容,从而实现段内转移,ret指令不一定必须要和call指令一起出现,只要栈中有数据即可。
retf指令:用栈中的数据修改CS和IP的值,从而实现段间转移。
6.call指令(用到栈)
使用格式:call 地址标号
执行该指令时,先将当前地址放进栈顶保存,然后跳转到地址标号处执行,也就是先push然后jmp,当执行完所有指令后一般用ret指令,这个指令时从栈顶取出地址并发生跳转,所以当我们在call和ret指令中间有进栈操作时,一定要在到达ret指令前将这些中间进栈的数据全部出栈,即进几次栈就要出几次栈,否则ret指令不能返回到正确的地址。
call指令的四种使用方式:
(1)调用子程序
call 子程序名
…(若干指令)
ret
(2)用来实现段间转移
call far ptr 标号
(3)寄存器
call 16位通用寄存器
(4)
call word ptr 内存单元地址
或者call dword ptr 内存单元地址(低地址放偏移地址,高地址放段地址)。

7.地址标号和数据标号
首先区分一下:
(1)带有冒号的是地址标号,否则就是数据标号。
(2)数据标号可同时描述内存地址和单元长度的标号,不同于仅表示地址的地址标号。
(3)地址标号只能在代码段中使用,而数据标号既可以在数据段,也可以在代码段。
(4)即使数据标号在数据段和代码段都可以使用,在使用时也不用加段前缀,数据标号自己可以识别。
比如下面一段代码:

assume cs:code
code segment
   a db 1,2,3,4,5,6,7,8
   b dw 0
  start: mov al,a[si]//mov al,cs:[0]
  		 add b,ax//add cs:[8],ax,另外inc b也是合法的
  		 ......

数据标号a的地址为code:0,因为是db,以后的内存单元都是字节。
数据标号a的地址为code:8,因为是dw,以后的内存单元都是字。
扩展用法:将标号当作数据来定义,代码如下:

data segment
    a db 1,2,3,4,5,6,7,8
    b dw 0
    c dw a,b//这里保存的分别是a和b的偏移地址,相当于c dw offset a,offset b

data segment
    a db 1,2,3,4,5,6,7,8
    b dw 0
    c dd a,b//因为是双字型,保存的是偏移地址(低4位)和段地址(高4位)
    //相当于c dw offset a,seg a,offset b,seg b

8.offset指令和seg指令
通过上面的2块代码块,相信你也已经对这两个指令的作用基本认识了。
offset就是获取标号的偏移地址(不区分地址标号和数据标号),16进制下占4位。
seg就是获取标号的段地址,16进制下占4位,也就是占一个字。
下面只对offset举例(seg类似):

//将s处的一条指令复制到s0处
assume cs:code
code segment
 s: mov ax,bx
    mov si,offset s
    mov di,offset s0
    mov ax,cs:[si]
    mov cs:[di],ax
 s0: nop//空指令,起占位作用,占一个字节
 	 nop
code ends
end

八:除法指令DIV

1)被除数:进行16位除法时默认存放在AX中(或者32位时分开存放在AX和DX中,DX存放高16位)。
2)除数:存放在比被除数位数少一倍长度的寄存器中或者内存单元中。
3)结果:商存放在AL中,余数存放在AH中(或者商存放在AX中,余数存放在DX中)。
4)被除数的位数是除数的2倍。
5)存放商和余数位数的长度等于除数位数的长度。
6)注意溢出问题(有兴趣可以自己写个解决除法溢出的子程序)。
DIV指令使用格式:
方式一:DIV 寄存器
方式二:DIV WORD(或BYTE) PTR 内存单元(除数是字节型用BYTE,字型用WORD,不会有双字型除数,因为被除数最大为双字型,而除数必须是被除数字长的一半)。

这里有衍生出一个新的知识点WORD PTR或者BYTE PTR有什么作用呢?
这个指令是用来明确要处理的数据有多长。
比如:
(1)MOV AX,1
因为AX是字型寄存器,所以这个指令要处理的数据字长是字型,是确定的。
(2)MOV AL,BL
因为AL,BL都是字节型寄存器,所以处理的数据字长是字节型,也是确定的。
(3)MOV DS:[0],1
这里DS:[0]是内存的一个起始地址,而没有结束地址,无法确定要将数据1存放在多长的空间里,这时就需要加上这个指令。
可以是MOV WORD PTR DS:[0],1或者MOV BYTE PTR DS:[0],1。

九:乘法指令MUL

1)被乘数:进行8位乘法时默认存放在AL中(或者16位时存放在AX中)。
2)乘数:存放在与被乘数位数等长的寄存器中或者内存单元中。
3)结果:积存放在AX中(或者存放在AX和DX中,DX中存放高位)。
4)被乘数的位数与乘数一致。
5)存放积的位数长度是乘数的2倍。
MUL指令使用格式:
方式一:MUL 寄存器
方式二:MUL BYTE PTR DS:[0]
因为乘法指令和除法指令类似,可以比较进行理解记忆。

十:标志寄存器PSW(或者FLAGS)

按位起作用。用来存储相关指令的某些执行结果,用来为CPU执行相关指令提供行为依据,用来控制CPU的相关工作方式。
下面是对应PSW每一个位的表格(只列出一些常用位数对应的含义)。

151413121110987654321第0 位
OFDFSFZFPFCF

OF:溢出标志位。溢出为1,否则0。
DF:方向标志位。为1时,串操作指令由高地址向低地址执行,SI和DI减。反之对应。
SF:符号标志位。结果为负是1,否则0。
ZF:零标志位。结果为0是1,否则0。
PF:奇偶标志位。记录结果中所有二进制中1的个数是否为偶数个,偶数个为1,否则0。
CF:进位标志位。是否有进位或借位。有为1,否则0。
直接访问PSW的方法:
1)pushf:将PSW的内容压栈。
2)popf:从栈中取数据放到PSW中。
一些指令和PSW的关系:
ADD,SUB,MUL,DEC(自减一),INC(自增一),OR,AND等指令的执行对PSW某些标志位有影响。(INC和DEC指令对CF标志位无影响)
MOV,PUSH,POP,DIV等对PSW无影响。

十一:不同于ADD和SUB的加减法指令

1.带进位的加法指令ADC
ADC AX,BX 实际运算是(ax)=(ax)+(bx)+CF。
一个栗子:
1EF000H+201000H,结果放在ax(高16位)和dx(低16位)中。
代码如下:
MOV AX,001EH
MOV BX,1000H
ADD BX,1000H(出现进位,CF为1)
ADC AX,0020H(因为CF等于1,所以结果等于0020+1000+1)
另外,在使用ADC指令时,如果需要通过地址偏移获取数据,尽量不要用ADD指令,因为ADD指令也会影响CF标志位,可以多次使用INC指令代替ADD指令。
如果要清除CF标志位,可以用SUB AX,AX将CF置零。
2.带借位的减法指令SBB
类似ADC指令
SBB AX,BX实际运算是(ax)=(ax)-(bx)-CF。

十二:CMP指令

1.类似减法指令,不过不保存结果,执行后对源操作数和目标操作数均无影响,这条指令的作用是改变PSW某些标志位。
2.该指令不区分比较的对象是有符号数还是无符号数,一律通吃。
3.CMP AX,AX做减法,结果为0,但不保存在AX中,PSW中的零标志位ZF为1。
4.两数的大小关系以及比较后对PSW的影响:
(1)无符号数执行指令CMP AX,BX:
等于:如果AX=BX,则AX-BX=0,所以ZF=1 。
不等于:如果AX!=BX,则AX-BX!=0,所以ZF=0。
小于:如果AX<BX,则AX-BX将产生错位,所以CF=1。
大于等于:如果AX>=BX,则AX-BX将不必借位,所以CF=0。
大于:如果AX>BX,则AX-BX既不必借位,结果又不为0, 所以CF=0且ZF=0。
小于等于:如果AX<=BX,则AX-BX既可能借位,结果也可能为0,所以CF=1或ZF=1。
(2)有符号数执行指令CMP AX,BX:
等于和不等于的情况与无符号数一样。
大于:若SF=0,OF=0 则说明了此时的值为正数,没有溢出。
小于:若SF=1,OF=0 则说明了此时的值为负数,没有溢出。
小于等于:若SF=0,OF=1 则说明了此时的值为正数,有溢出。
大于等于:若SF=1,OF=1 则说明了此时的值为负数,有溢出。
5.CMP指令通常不单独使用,常常结合一些转移指令。
形如:
CMP AX,BX(或者其他可以影响PSW的指令)
J** 标号。
这些跳转指令不同于上面提到的转移指令。如下表(无符号数):

指令含义测试条件指令解释
JE/JZ想等ZF=1E:equal , Z:zero
JNE不相等ZF=0JE指令的否定
JS结果为负SF=1S:sign
JNS结果非负SF=0JS指令的否定
JO溢出OF=1O:overflow
JNO未溢出OF=0JO指令的否定
JP奇偶位为1PF=1P:parity
JNP奇偶位不为1PF=0JP指令的否定
JB/JNAE/JC有借位/低于CF=1B:below,C:carry
JNB/JAE/JNC无借位/不低于CF=0AE:above equal
JNA/JBE不高于CF=1或ZF=1BE:below equal
JA/JNBE高于CF=0且ZF=0A:above

还有8个与有符号数数有关的转移指令,见下表:

指令含义测试条件指令解释
JL/JNGE小于SF=1,ZF=0L:less
JGE/JNL大于等于SF=0或ZF=1GE:graeter or equal
JG/JNLE大于SF=0,ZF=0G:greater
JLE/JNG小于等于SF=1或ZF=1LE:less or equal

看到这里,肯定有点累了吧,反正我写到这里是疲了,但看看目录,发现内容已经过半,字数也已经来到8000字,好,既然决定要干就要干得漂亮,集合,发起进攻!!!

十三:串传送指令和REP指令

1)DF:PSW中的方向标志位。
2)串传送指令:MOVSB以字节为单位传送(SI,DI每次变化1),MOVSW以字为单位进行传送(SI,DI每次变化2)。
3)DF=0,每次操作后SI,DI递增;DF=1,每次操作后SI,DI递减。
4)对DF进行设置的指令:
CLD:将DF设为0(clear)
STD:将DF设为1(set up)
5)REP指令,常搭配串传送指令使用。使用前先对CX寄存器赋值,然后重复执行某一指令直到CX=0。
REP MOVSB
相当于
s:
MOVSB
LOOP s

十四:移位指令(移二进制数)

1.逻辑左移(SHL)
将位数都左移一位,最左侧的一位放进CF,最右侧补0。
例:
MOV AL,01001000b
SHL AL,1
结果:AL=10010000,CF=0
2.逻辑右移(SHR)
将位数都右移一位,最右侧的一位放进CF,最左侧补0。
3.循环左移(ROL)
每一位左移,最左侧一位放进CF,同时将最左侧的值放到最右侧缺失的地方,体现循环。
4.循环右移(ROR)
每一位右移,最右侧一位放进CF,同时将最右侧的值放到最左侧缺失的地方,体现循环。
5.算术左移(SAL)
与逻辑右移一样。
6.算术右移(SAR)
注意这个不是与逻辑左移一样。每一位向右移,最右侧的移到CF,最左侧是之前最左侧的数。
例:
MOV AL,01001000b
SAR AL,1
结果:AL=00100100,CF=0
7.带进位的循环左移(RCL)
每一位左移,最左侧一位放进CF,再将CF中的数放到最右侧缺失的地方。
8.带进位的循环右移(RCR)
每一位右移,最右侧一位放进CF,再将CF中的数放到最左侧缺失的地方。
9.进行多位移动时,应将要移动的位数保存在CL中,比如要将AX的值算术右移移动5位。
不可以是SAR AX,5
而应是SAR AX,CL。

十五:DUP指令

这个指令用来进行数据的重复。一般用在数据段。
比如:
DB 3 DUP(0)相当于 DB 0,0,0
DB 3 DUP(0,1,2)相当于 DB 0,1,2,0,1,2,0,1,2
DB 3 DUP(‘abc’,‘de’) 相当于 DB ‘abcdeabcdeabcde’
现在我们从左到右分析上面的例子:
DB表示是字节型,还可以用DW,DD型;3表示的是重复的次数;括号内的数据就是要被重复的模板。
另外,我们可以用DW 4 DUP(0)或者DW 4 DUP(?)申请4个大小为一个字的空间。
这个指令相当于在高级语言里定义一个空的数组或者开辟一块内存。

十六:操作显存数据(彩色字符)

1.8086显存地址空间是A0000~BFFFF共128K的空间,其中B8000-BFFFF共32K的空间是彩色字符模式第0页的显示缓冲区(25行,80列)。
2.每一个彩色字符占2个字节(高位的一个字节表示字符颜色属性,低位的一个字节表示该字符的ASCII),所以每一行160个字节。
高位的一个字节的8位见表格:

76543210
闪烁红(底色)绿(底色)蓝(底色)高亮红(字符)绿(字符)蓝(字符)

另外,000表示黑色,111表示白色。
例:
11001010表示红底高亮闪烁绿色。

十七:直接定址表

其实就是将一些接下来可能需要遍历的并且固定不变的数据保存在自己定义的一个标号段(可以是数据标号或者地址标号),使用时直接通过地址偏移调用。

十八:中断

1.中断:CPU不在顺序执行指令,而是转去处理中断信息,CPU根据中断信息可以找到要执行的处理程序。
2.中断分为内中断和外中断。
内中断:由CPU内部发生的事件而引起的中断
外中断:由外部设备发生的事件引起的中断
3.内中断分类:
①int n (中断码:n)
②into溢出 (中断码:4)
③除法溢出 (中断码:0)
④单步 (中断码:1)
4.中断向量表:由中断类型码,查表得到中断处理程序的入口地址,从而定位中断处理程序,每个中断处理程序占连续的4个地址,其中2个高位地址存CS,低位存IP。共256个中断程序,占用1024字节。
5.8086中断程序地址区:
0000:0000~0000:03FF(0号中断依次到255号中断)
所以知道中断号,就可以知道存放中断处理程序起始地址的地址。IP=n4,CS=n4+2。
6.中断过程
(1)中断过程由CPU的硬件自动完成
(2)写中断类型码找到中断向量,并用它设置CS和IP
CPU中断过程:
①从中断信息中取得中断类型码
②PSW的值入栈(因为中断过程要改变PSW的值,需先行保护)
③设置PSW的第8位TF和第9位IF的值为0,否则会死循环
④CS的内容入栈,IP的值入栈
⑤从中断向量表读取中断处理程序的入口地址,设置CS和IP(根据中断号n)
7.单步中断过程和处理
(1)当CPU在执行完一条指令后,如果检测到PSW的TF位为1,则产生单步中断,引发中断过程,执行中断处理程序。
(2)中断过程(上一个知识点)
(3)特殊:不响应中断的情况:
在执行完向SS寄存器传送数据的指令后,即使发生中断,CPU也不会响应。因为SS:SP联合指向栈顶,而对他们的设置应连续完成,以保证对栈的正常操作。
(所以说,向SS和SP寄存器的赋值语句必须写在一起)
8.还要学会查找和使用官方的中断指令大全。
BIOS和DOS中断大全入口

N:关于一些小但很重要的问题

1.注意进位问题:
设AH=00C5H,执行ADD AL,93H后,AH=0058H,而不是0158H
2.DS和[Address]
DS保存(数据段)段地址,[ ]中保存偏移地址。
举例:将10000H中的数据读到AX中
MOV BX,1000H
MOV DS,BX
MOV AL,DS:[0];这里不用写成[0000]的形式,都是零的意思;DS:[0]就相当于1000:0000
3.关于进出栈
PUSH AX;表示将AX寄存器中的数据存放到栈顶。
POP AX;表示将栈顶一个字的数据放入AX寄存器。
(对于栈没学好的同志们不妨趁着现在补一补呀,不要下次亿定,要这次一定,这次也请一定附加给我点个赞,我不介意的,手动滑稽)
4.每段最大长度
因为段地址是由4个16进制数组成,而一个16进制数对应4个2进制数,所以段地址是由16个2进制数组成,从而每个段的最大长度也就是偏移地址的范围即2的16次幂,也就是64KB,怎么样,上面的那个小问题做对了吗?没做对的话,现在懂了吗?现在还不懂去问了吗?
搞懂之后,这里再来一个问题:一个有128B的数据区,它的起始地址是12AB:00ABH,请给出这个数据区最末一个字节的物理地址?
5.数据不能以字母开头
在汇编语言中,数据不能以字母开头,必须在字母前补一个0。
MOV AX,FFFFH是错误形式,要写成MOV AX,0FFFFH
解析:
12B5B+80-1=12BDAH。注意要减一,因为第1B的数据区地址是1-1=0,这里同理。
6.字母大小写转换
大写字母转成小写字母:小写字母与二进制11011111做与运算。
小写字母转成大写字母:大写字母与二进制00100000做或运算。
为什么是这样呢?看下面这张表格:

字母对应ASCII的二进制
A01000001
a01100001
B01000010
b01100010
C01000011
c01100011

结论:大写字母和小写字母不同点在于第6位上是0或1,那么我们可以通过做与或者或运算实现大小写转换。
7.参数传递3种方式
1)寄存器
2)内存单元
3)栈
通常我们常用或者优先选择寄存器方式,但寄存器数量有限,这就容易出现寄存器冲突问题,怎么解决呢?
①使用其他寄存器
②寄存器进栈退栈实现共享
8.关于敲码
字母不区分大小写,注释写在;后面。
9.E命令
在debug环境下用E命令向内存中写入。
E B800:0000 41 02 42 20
也就是向内存中写了0241和2042两个字。
10.如何将一个字节(即两个16进制数)分开,假设保存在AL中?
mov ah,al
mov cl,4
shr ah,cl
and al,00001111b
11.如何打印出字符
在显存中通过字符的ASCII打印。
12.偏移实现除法
比如执行MOV AX,-51指令后,要对AX的值除以2,可以用SAR AX,1
原因:除以2可以用右移实现,而-51显然是带符号的除法,用算术右移合适,右移1位就是除以2,左移一位就是乘2,以此类推。
13.
数据段可以的数据不加H默认是10进制数,存放10进制数时要注意不超出最大表示数。比如DB 287就不合法,因为DB所能表示的最大数是225。
14.lea指令
lea BX,VAR等价于mov bx,offset var
15.
DW ‘AB’,‘CD’,'EF’在内存中从低字节开始存储,在内存中是B,A,D,C,F,E。
原因:首先注意这里的字符不是16进制数,知识普通的字符,而上面讲过,字符是以ASCII的形式存在内存中的,也就是DW ‘AB’,‘CD’,'EF’实际是DW ‘6566’,‘6768’,‘6970’,再根据小端模式,存在内存中按照由低地址到高地址应是6665 6867 7069,也就是BADCFE。

写在最后:
基础知识点部分上面基本介绍完了,这里有个汇编语言钢琴程序,比较综合,可以试着阅读源码加深巩固本节知识点。
汇编语言钢琴程序入口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值