AssemblyLanguage
汇编语言——直接在硬件之上工作的编程语言
汇编指令(机器码的助记符)
cpu对存储器的读写逻辑上划分为:
地址总线:地址总线上能传送多少个不同的信息,cpu就可以对多少个存储单元进行寻址。一个cpu有N根地址总线,则可以说这个cpu的地址总线的宽度为N,这样的cpu最多可以寻找2的N次方个内存单元(8086/8088cpu的cpu地址总线宽度为20位,寻址能力为$2^{20}=1024*1024字节=1024K字节=1M字节$)(8086/80286—16位,80386—32位)
1
2
3寻址能力的判断:
寻址能力=2的N次方(N为地址总线的条数)
32位地址总线为例子,cpu的寻址能力2^32Bit=4G1
2
3
4
5
6
7
8bit单位间的换算关系:
1字节=1byte=1B=8位
1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB
1PB=1024TB
数据总线:cpu和内存或其他器件之间的数据传送是通过数据总线来进行的,数据总线的宽度决定了cpu和外界的数据传送速度
控制总线:cpu对外部器件的控制是通过控制总线来进行的。在这里控制总线是个总称,控制总线是一些不同控制线的集合。有多少根控制总线,就意味着cpu提供了对外部器件的多少种控制
原码,反码,补码:
原码:最高位(符号位0为正,1为负)+低位(数值)
反码:分正反
补码:分正反
1
2
3
4
5
6
7
8用8位表示7的原码: 00000111
-7:10000111
用8位表示7的反码:
1.对于正数来讲反码和原码是一样的 00000111
2.对于负数来讲除最高位以外,其余位进行取反 -7:11111000
用8位表示7的补码:
1.对于正数来讲补码和原码是一样的 00000111
2.对于负数来讲补码等于反码加1 11111000+1->11111001
十进制转化BCD码:
bcd码:用四位二进制表示0~9数据
也就是从右向左每四位分!
寄存器(16位寄存器组,可以存放两个字节的数据):
8个通用寄存器
- 累加器AX:算数运算的主要寄存器(AH,AL两个独立寄存器,为高位和低位)
- 基址寄存器BX:存放地址的偏移地址
- 计数寄存器CX:作为循环和串操作等指令中的计数器,存放循环次数或重复次数
- 数据寄存器DX:常用来存放双字长数据的高16位,或在间接寻址的I/O指令中存放I/O端口地址
- 堆栈指针寄存器SP:用以指出在堆栈段中当前栈顶的地址
- 基址指针寄存器BP:指出要处理的数据在堆栈段中的基地址
段寄存器
- 代码段寄存器CS:用于存放当前正在运行的程序。存放当前执行程序所在段的段地址,将其内容左移4位再加上IP指针的内容即为下一条执行指令的地址。
- 堆栈段寄存器SS:是内存中开辟的专用存储区,用来暂时保存寄存器中的数据。存放当前堆栈段的段地址,将其内容左移4位再加上SP的内容即为栈顶地址
- 数据段寄存器DS:存放当前数据段的段地址,将其内容左移4为再加上计算所得的偏移地址即为对数据段指定单元进行读/写的地址。
- 附加数据段寄存器ES:是附加的数据,在串操作指令中用于存放目的操作数
标志寄存器FLAGS
- 指令指针寄存器IP:CS和IP两个关键的寄存器,cpu将CS:IP指向的内容当作指令执行
八位标志寄存器信息如下
寄存器标志位的判断(ZF,SF,OF,CF)
- ZF:对于有符号数和无符号数都可以判断,结果为0,ZF=1;结果为1,ZF=0
- SF:对于有符号数才有意义,SF=结果最高位(溢出时,只看最高位)
- OF:对于有符号数才有意义,没有进行符号位扩展:OF=CS异或C1(CS是符号位进位,C1是最高数位进位);进行符号位扩展,双符号位位01/10时,OF=1
- CF:对于无符号数,做加法时,有进位(CF=cout)CF=1;做减法时,有借位(CF=cout)CF=1。更简单的对于减法的判断方法—->直接观察,被减数<减数时CF=1
8086/8088寻址方式(获取操作数所在地址的寻址方式):
操作数分为
立即数:立即寻址
助剂符 目的操作数(本身含有地址的含义) 源操作数(立即寻址只针对源操作数)1
MOV AX,0FFFH
存储器操作数
直接寻址”【(存放数据的偏移地址,也可以进行段重设)】“
1
2MOV BL,[1200H] ;默认DS段
MOV BL,ES:[1200H] ;段重设寄存器间接寻址
1
2
3
4
5
6MOV AX,[SI] ;SI内容为1200H,把1200H所对应的内容传给AX
BX ;默认在数据段DS
BP ;默认在堆栈段SS
SI ;DS
DI ;DS
SX ;DS寄存器相对寻址(在寄存器寻址的基础上再加一个相对位移量)用来存取表格或一维数组里的内容
1
2MOV AX,DATA[BX] ;DATA+[BX]如果DATA=0010H,BX=1200H,DS=1000H则完整地址=1000H:0010H+1200H=1000H:1210H=11210H
;DATA[BX] [BX]DATA DATA+[BX] [BX]+DATA [DATA+BX] [BX+DATA]这几种写法都行基址变址寻址
1
MOV AX [BX(BP)][SI(DI)] ;基准变址相加,BX默认DS段,BP默认SS段
基址变址相对寻址
1
MOV AX [BX(BP)][SI(DI)]+(8/16bit的偏移量)
寄存器操作数:寄存器寻址(其操作数是CPU寄存器中的数)
1
MOV SI AX
指令计算
1 | mov ax,18 ;将18送入AX AX=18 |
物理地址:8086有20位地址总线,可传输20位地址,寻址能力为1M;8086是16位结构的cpu,运算器一次最多可以处理16位的数据,寄存器的最大宽度位16位,在8086内部处理的,传输,暂存的地址也是16位,寻址能力也只有64KB
解决方案:用两个16位地址(段地址,偏移地址)合成一个20位物理地址16进制左移一位相当于16进制左移1位
- 段地址×16必然是16的倍数,所以一个段的起始地址也一定是16的倍数
- 偏移地址位16位,16位地址的 寻址能力位64K,所以一个段的长度最大位64K(0~FFFFFH)
- 从CS:IP指向内存单元读取指令,读取的指令进入指令缓冲器
- IP=IP+所读取指令的长度,从而指向下一条指令
- 执行指令转到步骤1,重复这个过程
如何修改CS,IP的指令(Debug中的R命令可以改变,但是Debug是调试手段不是程序方式)(CS和代码段的问题)
注意不能用指令mov修改
1 | ;mov cs 2000H 错误 |
转移指令可以修改ip和cs内容
1 | ;同时修改cs和ip内容 jmp 段地址:偏移地址 |
从2000H开始,执行的顺序是:
- mov ax,6622
- jmp 1000:3
- mov ax,0000
- mov bx,ax
DS(数据段寄存器)和[address]配合得出cpu要访问的内存单元的地址
1 | mov bx,1000H |
将段地址送入DS的两种方式
mov ds,1000H 错误
mov bx,1000H
mov ds,bx 正确(数据->一般寄存器->段寄存器)
1 | ;内存中:10000H 23 |
DS与数据段的问题
1 | ;累加数据段中的前3个单元中的数据,将123B0H~123BAH的内存单元定义为数据段 |
栈结构
1 | ;PUSH(入栈),POP(出栈),以字为单位对栈进行操作 |
此图为debug运行情况
CPU如何知道一段内存空间被当作栈使用?
执行push和pop的时候,如何知道哪个单元是栈顶单元?
8086cpu中,有两个与栈相关的寄存器:栈段寄存器
SS---存放栈顶的段地址栈顶指针寄存器
SP---存放栈顶的偏移地址
1 | ;按要求设置段并执行代码 |
汇编程序中的伪指令
1 | assume cs:codesg ;assume:含义是假设某一段寄存器和程序中的某一个用segment...ends定义的段相关联--assume cs:codesg指CS寄存器与codesg关联,将定义的codesg当作程序的代码段使用(伪指令2) |
[…]与(…)
- […]—-汇编语法规定表示一个内存单元
- (…)—-表示一个内存单元或寄存器中的内容
- idata表示常量
1 | mov ax,2000H ;ax=2000H |
loop指令
cpu执行loop指令时要进行的操作:
- (cx)=(cx)-1;
- 判断cx中的值,不为零则转至标号处执行程序,为零则向下执行,cx中要提前存放循环次数,因为(cx)影响着loop指令的执行结果
1 | assume cs:code |
用loop指令计算123×236,结果储存在ax中(用循环把乘法转换成加法)
1 | assume CS:code |
计算ffff:0006字节单元中的数乘以3,结果存储在dx中
1 | ;dx是16位,字节是8位,不能同时进行 |
- 运算后的结果是否会超出dx所能承受的范围:ffff:0006单元中的数是一个字节型的数据,范围在0~255之间,则用它和3相乘结果不会大于65535,不会出现越界
段前缀:在[idata]前显式地写上段寄存器
1 | mov ax,2000h |
计算ffff:0~ffff:b字节单元中的数据的和,结果存储在dx中
1 | assume cs:code |
- 是否可以将ffff:0~ffff:b中的数据直接累加带dx中?
不行:add dx ds:[addr] ;(dx)=(dx)+? 因为ds:[addr]中取出的是字节单元,而dx存储的是字单元
- 是否可以将ffff:0~ffff:b中的数据直接累加带dl中?
不行:add dl,ds:[addr] ; (dl)=(dl)+? 因为dl只能存储8位在加法的过程中进位会丢失,只能取出8位数据,加到16为寄存器
1 | mov al,ds:[addr] |
1 | assume cs:code |
将内存ffff:0到ffff:b中的数据拷贝到0:200到0:20b单元中
1 | assume cs:code |
1 | ;使用附加段寄存器es |
在代码段中使用数据
编程计算以下8个数据的和,结果存在ax寄存器中
1 | assume cs:code |
在代码段中使用栈
完成下面的程序,利用栈,将程序中定义的数据逆序存放
- 程序运行时,定义的数据存放在CS:0~CS:F单元中,共8个字单元
- 依次将这8个字单元中的数据入栈,然后再依次出栈到这8个字单元中,从而实现数据的逆序存放
1 | ;只适用于要处理的数据很少,用到的栈空间也小,加上没有多长的代码 |
1 | ;将数据,代码,栈放入不同段 |
处理字符问题
在汇编程序中,用’……’的方式指明数据是以字符的形式给出的,编译器将他们转化为相对应的ASCII码
大小写转换问题:对第一个字符串小写转大写,大写不变;对于第二个字符串大写转小写,小写不变
1 | ;技巧如下,例如让小写b转成大写B |
1 | assume cs:codesg ds:datasg |

















