汇编语言_访问寄存器和内存

2023-11-10 10:34:06 浏览数 (1)

运算器进行信息处理 寄存器进行数据的存储 控制器协调各种器件进行工作 寄存器是CPU内存信息存储单元

这些寄存器都是16位的 可以存放两个字节 16位可以存储的最大值是多少,16位都为1即最大 也就是

同时为了保证兼容性 将16位寄存器分为两个独立的8位寄存器 ax可以分为ah和al

字在寄存器中的存储 8086的字长是16位 我们平时说的多少位说的就是字长 8086cpu的一个字可以存储在一个16位寄存器中 这个字的高位字节存放在这个寄存器的高八位寄存器 这个字的低位字节存在这个寄存器的低八位寄存器 为我们操作高位字节和低位字节提供了便利

mov和add指令

mov ax,bx 将bx的数据传入ax add ax,bx ax = ax bx

CPU访问内存单元时要给出内存单元的地址 所有的内存单元构成了一个一维的线性空间 每个内存单元在这个空间中 都有自己唯一的地址 这个地址称为物理地址 8086 CPU有二十位地址总线,所以他的寻址能力位1mb 8086是16位结构以的cpu 运算器一次性最多可以处理16位的数据 寄存器的最大宽度为16位 在8086内部处理的传输暂存的地址也是16位 寻址能力只有64kb 对于寻址能力和内存传输以及暂存的地址之间的差异 解决办法是可以通过两个16位地址合成一个20位的物理地址 即物理地址 = 段地址X16 偏移地址

十六进制左移一位相当于二进制左移四位

内存的分段表示法

段的分段来自CPU并不是内存分段

如图 起始地址为10000H 段地址为1000H大小为100H 也可以分为两段 这主要看CPU如何将内存分段使用

一个段的起始地址是16的倍数

偏移地址为16位 16为的寻址能力为64K 所以一个段最长为64K 即0~FFFFh的长 例如我们给定段地址 2000H 用偏移地址寻址的范围是20000H~2FFFFH共64K 存储地址的表示方法:

数据在内存2000:1f60单元中

数据在2000段中的1f60单元

偏移地址 = 物理地址-段地址X16 由此看出我们的段地址是非常重要的 所以CPU也有专门存储段地址的寄存器 CS-代码段寄存器 DS-数据段寄存器 SS-栈段寄存器 ES-附加段寄存器

DEBUG

通过e写入机器码 然后U命令可以将机器码转换为汇编指令 a命令可以直接写入汇编指令 d可以查看内存数据 t可以执行cs:ip处的指令 我们可以修改 cs ip达到目的

CS IP 代码段

CS:代码段寄存器 IP:指令指针寄存器 CS:IP:CPU将内存中CS:Ip指向的内容当作指令执行 过程: 1) 从CS:IP指向内存单元读取指令 读取的指令进入指令缓器 2) IP = IP 所读取指令的长度 从而指向下一条指令 3) 执行指令 转到步骤1),重复这个过程 区分数据和代码在CPU看来 CS:IP指向的内容都是指令

JMP指令

通过修改cs ip内容 来修改CPU要执行的目标指令 我们首先想到的是debug模式下的修改方式 然而这只是一种调试手段 如果用指令修改的话 如

代码语言:javascript复制
mov cs,2000h
mov ip,000h

这是不允许的 CPU并没有提供给我们这种修改方式 可以使用转移指令jmp jmp段地址:偏移地址 jmp 2ae3:3 用jmp后的段地址和偏移地址修改cs和ip 如果只修改IP的内容 可以使用jmp寄存器的方法

内存中字的存储

16位字存储在16位的寄存器- 高八位放在高字节 第八位放在低字节 16位的字在内存中需要两个连续字节存储 低位字节在低地址单元 高位字节在高地址单元 字型数据指的是以字长为单位的内存长度 这也是我们在C语言中提到的小端模式 低地址存放低字节 高地址存放高字节

利用DS和[address]实现字的传输

cpu要读取一个内存单元的时候,必须先给出这个内存单元的地址 由段地址和偏移地址组成 这时候我们就可以通过ds和[address]配合 段地址由ds存放 []内有偏移地址 即

代码语言:javascript复制
mov bx,1000h
mov ds,bx
mov al,[0]

将10000H(1000:0)中的数据读到al中 8086CPU不支持将数据直接放入段寄存 器当中 而是需要一个通用寄存器作为过度 同时需要根据操作数的位数 需要注意的是如果我们

代码语言:javascript复制
mov ax,[1]

表示获取ds:[0001]的字单位数据 也就是高八位地址和第八位地址 即0002和0001组成的十六位地址 这点需要注意 并不是0001是高位地址 0000是地址是低位地址

DS与数据段

对于8086CPU 可以根据需要将一组内存单元定义为一个段 将一个长度为N且地址连续的,同时起始地址是16倍数的内存单元当作专门存储数据的内存空间 比如我们将123B0H~123B9H来存储数据 段地址:123BH 起始偏移地址:0000H 长度为10个字节 段地址:1230H 起始偏移地址:00B0H 长度为10个字节 用DS存放数据段的段地址 用相关指令访问数据段中的具体单元 单元地址由[address]指出 累加数据段前三个字节的数据

代码语言:javascript复制
mov ax,123B0H
mov ds,ax
mov al,0
add al,[0]
add al,[1]
add al,[2]

累加数据段前三个字型数据

代码语言:javascript复制
mov ax,123B0H
mov ds,ax
mov al,0
add al,[0]
add al,[2]
add al,[4]

练习 给出00000H-0001f的数据 并根据一下代码写出执行结果

代码语言:javascript复制
mov ax,[0000]
mov bx,[0001]
mov ax,bx
mov ax,[0000]
mov bx,[0002]
add ax,bx
add ax,[0004]
mov ax,0
mov al,[0002]
mov bx,0
mov bl,[000c]
add al,bl

预设的数据为 70 80 F0 30 EF 60 30 E2 00 00 12 66 20 22 60

26 E6 D6 CC 2E 3C 3B AB BA 00 00 26 06 66 68 总共有32个字节作为数据段的数据 我们自己算出来的al = 56 我们可以用dosbox验证一下

总结一下mov指令操作数据的形式 mov 寄存器,数据 mov 寄存器,寄存器 mov 寄存器,内存单元 mov 内存单元,寄存器 mov 段寄存器,寄存器

这几种形式也是可以的 add指令操作数据形式 add 寄存器,数据 add 寄存器,寄存器 add 寄存器,内存单元 add 内存单元,寄存器 sub指令操作数据形式 sub 寄存器,数据 sub 寄存器,寄存器 sub 寄存器,内存单元 sub 内存单元,寄存器 访问内存中数据段方法小结 1) 字在内存中存储时,要用两个地址连续的内存单元来存放 字的低位字节存放在低地址单元中,高位字节存放在高地址单元中 2) 用mov 指令要访问内存单元,可以在mov指令中只给出单元的偏移地址 此时 段地址默认在DS寄存器 3) [address]表示一个偏移地址为address的内存单元 4) 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器 低地址单元和低8位寄存器相对应 5) mov add sub是具有两个操作对象的指令 访问内存中的数据段

栈及栈操作的实现

我们之前已经说过栈这种结构 对于其特性我们就不详细介绍了 CPU提供的栈机制

现今的CPU中都有栈的设计

8086CPU提供相关指令 支持用栈的方式访问内存空间

基于18086CPU的编程 可以将一段内存当作栈来使用 Push 和 Pop指令 我们主要需要了解以下的问题 1) CPU如何知道一段内存空间被当作栈使用 2) 执行push和pop的时候 如何知道哪个单元是栈顶单元 8086CPU中 有两个与栈相关的寄存器 栈段寄存器SS - 存放栈顶的段地址 栈顶指针寄存器sp - 存放栈顶的偏移地址 任何时刻-ss:sp指向栈顶元素

通过栈的机制

代码语言:javascript复制
mov ax,100h
mov ss,ax
mov sp,0010h
mov ax,001ah
mov bx,001bh
push ax
push bx
pop ax
pop bx

以上代码 我们执行之后发现交换了ax和bx的值

push ax sp = sp-2 同时将ax的内容送入ss:sp指向的内存单元 ss:sp指向新的栈顶 pop ax sp = sp 2 同时将ss:sp指向的内容送入寄存器ax 同时指向新的栈顶

段的复习

物理地址 = 段地址X16 偏移地址 编程时,需要将一组内存单元定义为一个段 可以将起始地址为16的倍数 长度为N (N<=64k) 的一组地址连续的内存单元 定义为一个段 这都由程序员安排 三种段 数据段 将段地址放在DS中 用mov add sub等访问内存单元的指令时,CPU将定义的内容作为数据来访问 代码段 将段地址放在CS中 偏移地址放在IP地址 栈段 段地址放在ss中 栈顶指针放在sp中 CPU在需要进行栈操作push pop时,就将我们定义的栈段当作栈空间来用 综合示例

代码语言:javascript复制
mov bx,1000h
mov ds,bx
mov bx,1001h
mov ss,bx
mov sp,10h
mov ax,[0]
mov bx,[2]
push ax
push bx
pop ax
pop bx
mov [0],ax
mov [2],bx

执行完时候是交换了偏移地址为0和2的数据段的数据

经过机器验证我们可以知道确实是如我们想的一样

0 人点赞