汇编语言-王爽01

1.学习汇编语言的理由

汇编语言仍在发挥不可替代的作用

  • 效率
    • 运行效率:开发软件的核心部件,快速执行和实时响应
    • 开发效率:做合适的事,开发效率无敌
  • 底层:计算机及外围设备的驱动程序
    • 操作系统的内核
    • 嵌入式系统:家用电器、仪器仪表、物联网。。
      -汇编语言在学习计算机中起到独特作用
    • 加深对计算机组成原理和操作系统等的独到理解
    • 向上理解各种软件系统的原理
    • 向下掌握硬件系统的原理

3由机器语言到汇编语言

机器语言 是机器指令的集合
机器指令 是一台机器可以正确执行的命令
机器指令 是一台二进制数。使用电平脉冲来表示0和1。
但是机器语言:不易纠错。

汇编语言
汇编语言的主体是汇编指令
汇编指令和机器指令的差别在于指令的表示方法上
汇编指令是机器指令便于记忆的书写格式。
汇编指令是机器指令的助记符。

寄存器:CPU中可以存储数据的器件,一个CPU中有多个寄存器

汇编语言程序:伪指令,汇编指令,其他符号、
汇编阶段:汇编器将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。

4.计算机的组成

主板上有
- CPU
- 总线
- 内存(内存条)
- 扩展槽(接外部设备)
CPU由三条总线控制内存
地址总线,数据总线,控制总线。

计算机的组成
在这里插入图片描述
CPU是计算机的核心部件,控制整个计算机的运作并进行运算,要想让一个CPU工作,必须向它提供指令和数据。指令和数据是存放在内存中的。

指令和数据的表示
数据和指令都是二进制信息。
数据表示方法:
B(二进制)
H(十六进制)
O(八进制)
D(十进制)

计算机中的存储单元
存储器被划分为若干个存储单元,每个存储单元从0开始编号。
8086有20条数据线,寻址空间为2^20,1MB

电子计算机的最小信息单位是bit,也就是一个二进制位,8个bit组成一个byte,也就是一个字节。

计算机中总线
在计算机中有专门连接CPU和其他芯片的导线,这个称为总线。
物理上:一根根导线的集合
逻辑上:地址总线,数据总线,控制总线。
在这里插入图片描述
CPU想要进行数据的读写,必须和外部期间进行信息交互
1.存储单元的地址(地址信息)
2.器件的选择,读或写的命令(控制信息)
3.读或写的数据(数据信息)
地址总线
CPU是通过地址总线来指定存储单元的。
地址总线:CPU是通过地址总线来指定存储单元的。
地址总线宽度,决定了可寻址的存储单元大小
N根地址总线(宽度为N),对应寻址空间2^N
数据总线
CPU与内存或者其他器件之间的数据传送是通过数据总线来进行的。
数据总线的宽度决定了CPU和外界的数据传送的速度。

控制总线
CPU通过控制总线控制外部器件
控制总线是不同控制线的集合
控制总线宽度决定了CPU对外部器件的控制能力

在这里插入图片描述
32位地址总线的CPU,寻址能力为4GB。

5.内存的读写与地址空间

CPU对存储器的读写
CPU想要进行数据的读写,必须和外部器件进行三类信息的交互:
存储单元的地址(地址信息)
器件的选择,读或写的命令(控制信息)
读或写的指令(数据信息)

内存地址空间
在这里插入图片描述
RAM:随机存储器,能读能写。临时存放数据用的,关机后啥也没有了
ROM:只读存储器,只能读不能写,存放有固定数据,且删不掉也无法覆盖其他数据

将各类存储器看作一个逻辑存储器-统一编址
所有的物理存储器被看作一个由若干存储单元组成的逻辑存储器。
每个物体存储器在这个逻辑存储器中占有一个地址段,即一段地址空间。
CPU在这段(逻辑)地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据,
在这里插入图片描述
在这里插入图片描述

7.访问寄存器和内存

在这里插入图片描述
在这里插入图片描述

8.寄存器及数据存储

寄存器是CPU内部的信息存储单元
8086CPU中有14个寄存器
通用寄存器:AX,BX,CX,DX
变址寄存器:SI,DI
指针寄存器:SP,BP
指令指针寄存器:IP
段寄存器:CS,SS,DS,ES
标志寄存器:PSW
8086CPU中所有寄存器都是16位的,可以存放两个字节

AXaccumulator	累加寄存器	通常用来执行加法,函数调用的返回值一般也放在这里面
BX	base    	基址寄存器	读写I/O端口时,edx用来存放端口号
CX	counter    	计数寄存器	通常用来作为计数器,比如for循环
DX	data    	数据寄存器	数据存取
SI	source index	源变址寄存器	字符串操作时,用于存放数据源的地址
DI	destination index	目标变址寄存器	字符串操作时,用于存放目的地址的,和esi两个经常搭配一起使用,执行字符串的复制等操作
SP	stack pointer	栈指针寄存器	栈顶指针,指向栈的顶部
BP	base pointer	基址指针寄存器	栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量
eip: 指令寄存器可以说是CPU中最最重要的寄存器了,它指向了下一条要执行的指令所存放的地址,CPU的工作其实就是不断取出它指向的指令,然后执行这条指令,同时指令寄存器继续指向下面一条指令,如此不断重复
ES	extra segment	附加段寄存器
CS	code segment	代码段寄存器
SS	stack segment	栈段寄存器
DS	data segment	数据段寄存器

横看成岭侧成峰
问题:8086上一代CPU中的寄存器都是8位的,如何保证程序的兼容性 。
方案:通用寄存器均可以分为两个独立的8位寄存器使用。
细化:
AX:AH,AL
BA:BH,BL
CX:CH,CL
DX:DH,DL
在这里插入图片描述
字在存储器中的存储

  • 8086是16位CPU,字长为16bit
  • 一个字可以存储在一个16位寄存器中,
  • 这个字的高位字节存储在这个寄存器的高8位寄存器
  • 这个字的低位字节存储在这个寄存器的低8位寄存器
  • 一个寄存器,大小为16位,可以存放两个字节,可以存放一个字。
    (上面这种存储方式就是小端存储)
这里。。。看看如何区分大端or小端
小端:低位字节存放在内存的低地址端,高位字节存放在内存的高地址端(CPU对操作数的存放方式是从低字节到高字节)
大端:高位字节存放在内存的低地址端,低位字节存放在内存的高地址端(CPU对操作数的存放方式是从高字节到低字节)

在这里插入图片描述

#include<stdio.h>
int main()
{
	int a = 0x44332211;
	char* b = (char*)&a;
	
	(*b == 0x11) ? printf("Little-endian\n") : printf("Big-endian\n");
	return 0;
}

9.mov和add指令

在这里插入图片描述
在这里插入图片描述
最后一个,低8位会溢出,不可进位

10.确定物理地址的方法

物理地址

  • CPU访问内存单元时要给出内存单元的地址。

  • 所有的内存单元构成的存储空间是一个一维的线性空间。

  • 每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址就是物理地址

  • 8086有20位地址总线,可以传送20位地址,寻址能力为1M,

  • 8086是16位结构的CPU(数据总线为16位),运算器一次最多可以处理16位的数据,寄存器的最大宽度为16位。

  • 在8086内部处理的、传输、暂存的地址也是16位,寻址能力也只有64KB。
    如果处理在寻址空间上的这个矛盾,8086CPU的解决方法:

  • 用两个16位地址(段地址,偏移地址)合成一个20位的物理地址。

  • 地址加法器合成物理地址的方法:物理地址=段地址*16+偏移地址。

在这里插入图片描述
物理地址=段地址*16+偏移地址

解决的问题:
- 用两个16位的地址(段地址,偏移地址)相加得到一个20位的物理地址。
- CPU在访问内存时,用一个基础地址(段地址*16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

11.内存的分段表示法

用分段的方式管理内存
8086CPU中使用(段地址*16)+偏移地址=物理地址 的方式给出内存单元的物理地址。
内存并没有分段,段的划分来自于CPU。

同一段内存,具有多种多段方案

1)段地址*16,必然是16的倍数,因此,一个段的起始地址也一定是16的倍数
2)偏移地址为16位,16位地址的寻址能力为64K,所以一个段的最大长度为64K
存储单元地址的表示方法:
例:数据在21F60内存单元中,段地址是2000H,
a)数据存在内存2000:1F60单元中
b)数据存在内存的2000H段中的1F60H单元中

物理地址=段地址*16+偏移地址
段地址–用来存放段地址。

4个段寄存器
CS-代码段寄存器
DS-数据段寄存器
SS-栈段寄存器
ES-附加段寄存器

13.CS、IP与代码段

CS:代码段寄存器
IP:指令指针寄存器
CS:IP:CPU将内存中CS:IP指向的内容当作指令执行

8086PC工作过程的简要描述
1)从CS:IP指向内存单元读取指令,读取的指令进入指令缓冲器
2)IP=IP+所读取指令的长度,从而指向下一条指令
3)执行指令,转到步骤1)重复这个过程。

接上最开始的问题,计算机如何知道一个二进制信息是数据还是指令?
CPU将CS:IP指向的内存单元中的内容看作指令。

14.jmp指令(跳转指令)

执行何处的指令,取决于CS:IP,因此可以通过改变CS:IP中的内容,来控制CPU要执行的目标指令。
如何改变CS:IP中的值呢?
1)DEBUG中的R命令可以改变寄存器的值–RCS RIP。(只是调试手段)
2)用指令修改(8086CPU不提供对IP的修改的指令)
3)转移指令jmp

转移指令jmp
1)同时修改CS,IP的内容 (jmp 段地址:偏移地址)
用jmp中给出的段地址修改CS,jmp中给出的偏移地址修改IP
2)仅修改IP的内容 (jmp 某一合法寄存器)jmp ax。
用寄存器中的值修改IP

15内存中字的存储

8086CPU中,16位作为一个字
1)16位的字存储在一个16位的寄存器中,如何存储
高8位放高字节,低8位放低字节

2)16位的字在内存中需要两个连续字节存储,怎么存放
低位字节存放在低地址单元,高位字节存放在高地址单元

字单元:由两个地址连续的内存单元组成,存放一个字型数据(16位)

16用DS和[address]实现字的传送

CPU从内存单元中要读取数据
1)CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址。
2)8086CPU中,内存地址(物理地址)= 段地址:偏移地址。
3)可以使用,DS 和 [address]配合。
DS寄存器:要访问数据的段地址
[…]:要访问数据的偏移地址。

1)必须使用通用寄存器给段寄存器赋值
在这里插入图片描述

mov al, [0]
段地址:DS中
偏移地址:0
al为ax的低位字节,只读取一个字节,将该处的字节型数据读到al中

mov ax, [0]
将该处的字型数据读到ax中(16位)

17DS与数据段

8086CPU中(这个条件是前提!!!,整个课程的前提)
数据段:将一组长度为N(N<64k)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间

DS:[address]
DS:存放数据段的段地址
[address]:偏移地址

用 DS:[address] 形式访问内存中数据段方法
。。

18栈及栈操作的实现

栈的操作规则:先进后出
CPU中提供了栈机制:
push ax:将ax中的数据传入栈中。
pop ax:从栈顶取出数据送入ax,(以字为单位对栈进行操作)

8086CPU中,有两个与栈相关的寄存器
栈段寄存器SS:存放栈顶的段地址
栈顶指针寄存器SP:存放栈顶的偏移地址。
任意时刻,SS:SP指向栈顶元素

push和pop指令执行过程
栈是从高地址向低地址扩展
push ax:

  1. SP=SP-2;
    2)将ax中的内容送入SS:SP指向的内存单元,SS:SP此时指向新栈顶。

pop ax:
1)将 SS:SP指向的内存单元处的数据送入ax中,
2)SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。
在这里插入图片描述

19关于“段”的总结

物理地址=段地址*16+偏移地址
三种段:
数据段:
- 将段地址放在DS中。

代码段:
- 将段地址存放在CS中,将段中第一条指令的偏移地址放在IP中。

栈段:
- 将段地址放在SS中,将栈顶单元的偏移地址存在SP中,
- CPU在需要进行栈操作(push,pop)时,就可以将我们定义的栈段当做栈空间来使用。

21用汇编语言写的源程序

汇编程序:包括汇编指令和伪指令
在这里插入图片描述
伪指令:没有对应的机器码的指令,最终不被CPU所执行。
伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。

在这里插入图片描述
assume(假设):
假设某一段寄存器和程序中的某一个用 segment … ends 定义的段相关联
assume cs:codesg 指 CS寄存器与codesg关联,将定义的codesg当作程序的代码段使用。

段定义:
一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或当作栈空间来使用。
一个有意义的汇编程序中至少要有一个段,这个段用来存放代码。
定义程序中的段:每个段都需要有段名
段名 segment ——段的开始

段名 ends ——段的结束

end (不是ends):
汇编程序的结束标记。若程序结尾处不加end,编译器在编译程序时,无法知道程序在何处结束。

22由源程序到程序执行

源程序 到 可执行文件 的过程
源程序文件.asm (编译)-- 目标文件.obj (连接)-- 可执行文件.exe

编译
在这里插入图片描述
目标文件(.OBJ):对一个源程序进行编译要 得到的最终结果。
列表文件(
.LST):编译器将源程序编译为目标文件的过程中产生的中间结果。
交叉引用文件(*.CRF):同 列表文件 一样,是编译器将 源程序编译为目标文件 过程中产生的中间结果。

对源程序的编译结束,编译器输出的最后两行告诉 我们这个源程序没有警告 错误和必须要改正的错误。

连接
在这里插入图片描述
可执行文件(.EXE):对一个程序进行连接要得到的最终结果。
映像文件(.MAP):连接程序将目标文件连接为可执行文件过程中产生的中间结果。
库文件(.LIB):包含了一些可以调用的子程序,如果我们的程序中调用了某一个库文件中的子程序,就需要在连接的时候,将这个库文件和我们的目标文件连接到一起,生成可执行文件。
no stack segment,一个“没有栈段”的警告错误 ,可以不理会这个错误。

23运行及跟踪

–debug的运行跟踪
继续命令P(Proceed): 类似T命令,逐条执行 指令、显示结果。但遇子程序、中断等时,直接执行,然后显示结果。
运行命令G(Go):从指定地址处开始运行程序, 直到遇到断点或者程序正常结束.
在这里插入图片描述

24[…]和(…)

[…]——(汇编语法规定)表示一个内存单元
在这里插入图片描述
(…)——(为学习方便做出的约定)表示一个内存单元或寄存器中的内容
在这里插入图片描述
在这里插入图片描述

25Loop指令

定义一个标号
loop 标号
cx中提前存放循环次数
CPU 执行loop指令时要进行的操作
①(cx)=(cx)-1;
②判断cx中的值
不为零则转至标号处执行程序
如果为零则向下执行
在这里插入图片描述

loop 标号
实际上改变的是ip地址。

在这里插入图片描述

26Loop指令使用再例

:问题:计算ffff:0006 字节单元中的数乘以3,结果存储在dx中
在这里插入图片描述

27段前缀的使用

Debug中,mov al, [0]的功能是
——将DS:0存储单元的值传给AL

但是在写好程序编译并连接后,编译好的程序中,
mov al, [0] 变成了将常量0传给AL

这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的“ds:”、“cs:”、“ss:”或“es:”,在汇编语言中称为段前缀

计算ffff:0~ffff:b字节单元中的数据的和,结果存储在dx中
(1)运算后的结果是否会超出 dx 所能存储的范围?
ffff:0~ffff:b内存单元中的数据是字节型数据,范围在0~255之间,12个
这样的数据相加,结果不会大于 65535,可以在dx中存放下。
(2)是否可以将 ffff:0~ffff:b中的数据直接累加到dx中?
add dx, ds:[addr] ;(dx)=(dx)+?
实际:取出的是内存中的16位数据
(3)是否可以将 ffff:0~ffff:b中的数据直接累加到dl中?
add dl, ds:[addr] ;(dl)=(dl)+?
实际:取出的是内存中的8位数据,但很有可能造成进位丢失
(4)对策:取出8位数据,加到16位的寄存器
mov al, ds:[addr]
mov ah, 0
add dx, ax

28在代码段中使用数据

应用案例
在这里插入图片描述

29在代码段中使用栈

问题:完成下面的程序,利用栈,将程序中定义的数据逆序存放。
程序的思路大致如下:
1)程序运行时,定义的数据存放在cs:0~cs:F单元中,共8个字单元。
2)依次将这8个字单元中的数据入栈,然后再依次出栈到这 8 个字
单元中,从而实现数据的逆序存放。
3)栈需要的内存空间,在程序中通过定义“空”数据来取得
在这里插入图片描述
push ax:

  1. SP=SP-2;
    2)将ax中的内容送入SS:SP指向的内存单元,SS:SP此时指向新栈顶。

pop ax:
1)将 SS:SP指向的内存单元处的数据送入ax中,
2)SP=SP+2,SS:SP指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

30将数据,代码,栈放入不同段

在这里插入图片描述
SS:SP:
栈段寄存器SS:存放栈顶的段地址
栈顶指针寄存器SP:存放栈顶的偏移地址。

DS:数据段 段地址
CS:自动赋值,不用指定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值