ShuangChenYue ShuangChenYue
首页
  • Cpp之旅
  • Cpp专栏
  • Effective_CPP
  • muduo网络库
  • Unix环境高级编程
  • Cpp提高编程
  • 计算机网络
  • 操作系统
  • 数据结构
  • Linux
  • 算法
  • 基础篇
  • MySql
  • Redis
  • 电子嵌入式通信协议
  • 深入浅出SSD
  • 文件系统
  • 汇编语言
  • STM32
  • 随笔(持续更新)
  • Git知识总结
  • Git 创建删除远程分支
  • nvm使用小结
  • 虚拟机固定 IP 地址
  • Shell 脚本学习笔记
  • VScode 插件 CodeGeeX 使用教程
  • KylinV10 将项目上传至 Github教程
  • KylinV10 安装 MySQL 教程(可防踩雷)
  • kylinV10-SP1 安装 QT
  • 高并发内存池
  • USBGUARD 项目编译环境配置
  • Power_Destory 项目
  • U 盘清除工具编译教程
  • 个人博客代码推送教程
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • MFC编程随记
  • MFC实现ini配置文件的读取
  • MFC实现点击列表头排序
  • 贴图法美化Button按钮
  • 如何高效阅读嵌入式项目代码
  • NAND Flash
  • ARM 处理器
  • 嵌入式基础知识-存储器
  • 闪存存储和制造技术概述
  • 芯片IO驱动力
  • 主流先进封装技术介绍
  • 虎牙C++技术面经
  • 金山一面复习
  • 完美世界秋招 C++ 游戏开发面经(Cpp部分)
  • 博客搭建
  • 网站收藏箱
首页
  • Cpp之旅
  • Cpp专栏
  • Effective_CPP
  • muduo网络库
  • Unix环境高级编程
  • Cpp提高编程
  • 计算机网络
  • 操作系统
  • 数据结构
  • Linux
  • 算法
  • 基础篇
  • MySql
  • Redis
  • 电子嵌入式通信协议
  • 深入浅出SSD
  • 文件系统
  • 汇编语言
  • STM32
  • 随笔(持续更新)
  • Git知识总结
  • Git 创建删除远程分支
  • nvm使用小结
  • 虚拟机固定 IP 地址
  • Shell 脚本学习笔记
  • VScode 插件 CodeGeeX 使用教程
  • KylinV10 将项目上传至 Github教程
  • KylinV10 安装 MySQL 教程(可防踩雷)
  • kylinV10-SP1 安装 QT
  • 高并发内存池
  • USBGUARD 项目编译环境配置
  • Power_Destory 项目
  • U 盘清除工具编译教程
  • 个人博客代码推送教程
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • MFC编程随记
  • MFC实现ini配置文件的读取
  • MFC实现点击列表头排序
  • 贴图法美化Button按钮
  • 如何高效阅读嵌入式项目代码
  • NAND Flash
  • ARM 处理器
  • 嵌入式基础知识-存储器
  • 闪存存储和制造技术概述
  • 芯片IO驱动力
  • 主流先进封装技术介绍
  • 虎牙C++技术面经
  • 金山一面复习
  • 完美世界秋招 C++ 游戏开发面经(Cpp部分)
  • 博客搭建
  • 网站收藏箱
  • 电子嵌入式通信协议

  • 深入浅出SSD

  • 文件系统

  • 汇编语言

    • 第1章 基础知识
    • 第2章 寄存器
    • 第3章 寄存器(内存访问)
      • 3.1 内存中的字存储
      • 3.2 DS 和 [address]
      • 3.3 字的传送
      • 3.4 mov、add、sub 指令
      • 3.5 数据段
      • 3.6 栈
      • 3.7 CPU 提供栈机制
      • 3.8 栈顶超界问题
      • 3.9 栈的总结
      • 3.10 段的综述
    • 第4章 第一个程序
    • 第5章 [BX]和loop指令
    • 第6章 包含多个段的程序
    • 第7章 更灵活的定位内存地址的方法
    • 第8章 数据处理的两个基本问题
  • STM32

  • 嵌入式软件开发
  • 汇编语言
霜晨月
2024-07-24
目录

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

# 第3章 寄存器(内存访问)

# 3.1 内存中的字存储

CPU 中用16位寄存器存储一个字,高8位存放高位字节,低8位存放低位字节。内存单元是字节单元,一个单元存放一个字节,一个字需要使用两个连续的内存单元进行存放,这个字的低位字节存放在低地址单元,高位字节存放在高地址单元

image

问题:

  1. 0地址单元存放的字节型数据是多少?20
  2. 0地址单元存放的字型数据是多少?4E20
  3. 2地址单元存放的字节型数据是多少?12
  4. 2地址单元存放的字型数是多少?0012
  5. 1地址单元存放的字型数据是多少?124E

# 3.2 DS 和 [address]

CPU 要读写一个内存单元的时候,必须给出这个内存单元的地址。内存单元的地址由段地址和偏移地址组成。DS 寄存器通常需要存放访问数据的段地址

mov bx,1000H
mov ds,bx
mov al,[0]

[0]:表示内存单元的偏移地址
指令执行的时候,CPU 自动取 ds 中的数据作为内存单元的段地址
mov al,[0]:表示数据从1000:0 单元到 al 的传送
1
2
3
4
5
6
7

mov ds,1000H 是非法的。

只能通过一个寄存器来进行中转,如 bx。

  • mov bx,1000H
  • mov ds,bx

# 3.3 字的传送

CPU 是16位结构,有16根数据线,可以一次性传送16位数据,就是一个字

image

# 3.4 mov、add、sub 指令

mov 指令可以有以下几种形式:

  • mov 寄存器,数据 比如:mov ax,8
  • mov 寄存器,寄存器 比如:mov ax,bx
  • mov 寄存器,内存单元 比如:mov ax,[0]
  • mov 内存单元,寄存器 比如:mov [0],ax
  • mov 段寄存器,寄存器 比如:mov ds,ax

add 和 sub 指令有以下几种形式:

  • add 寄存器,数据 比如: add ax,8
  • add 寄存器,寄存器 比如:add ax,bx
  • add 寄存器,内存单元 比如:add ax,[0]
  • add 内存单元,寄存器 比如:add [0],ax
  • sub 寄存器,数据 比如:sub ax,9
  • sub 寄存器,寄存器 比如:sub ax,bx
  • sub 寄存器,内存单元 比如:sub ax,[0]
  • sub 内存单元,寄存器 比如:sub [0],ax

# 3.5 数据段

image

总结

  1. 字在内存中存储,使用两个地址连续的内存单元存放,低位字节存放在低地址单元,高位字节存放在高地址单元
  2. 使用 mov 指令访问内存单元,可以在 mov 指令中只给出单元的偏移地址,此时段地址默认在DS寄存器中
  3. [address]表示一个偏移地址位 address 的内存单元
  4. 在内存和寄存器之间传动数据的时候,高地址单元和高8位寄存器,低地址单元和低8位寄存器相对应
  5. mov、add、sub 是具有两个操作对象的指令。jmp 是具有一个操纵对象的指令

# 3.6 栈

  1. 入栈:就是将一个新的元素放到栈顶
  2. 出栈:就是从栈顶取出一个新的元素
  3. 栈顶的元素总是最后入栈。
  4. 栈的这种操作规则被称为:LIFO(Last In First Out)后进先出

# 3.7 CPU 提供栈机制

基本命令就是 PUSH 和 POP,push ax 表示将寄存器 ax 中的数据送入栈中,pop ax 表示从栈顶中取出数据送入到 ax,CPU 入栈和出栈操作都是已字为单位进行的

段寄存器 SS 和 SP,栈顶的段地址存放在 SS 中,偏移地址存放在 SP 中,任意时刻 SS : SP 指向栈顶元素

下图描述了 8086CPU 对 push 指令的执行过程:

image

将 10000H ~ 1000FH 如果初始状态栈是空的,SS = 1000H,SP = ?

image

将 10000H~1000FH 这段空间当作栈段,SS = 1000H,空间大小为16节,最底部的字单元地址为 1000 : 000E。任意时刻,SS : SP指向顶,当栈中只有一个元素的时候,SS = 1000H,SP = 000EH。

栈为空,就相当于栈中唯一的元素出栈,出栈后,SP = SP + 2,SP原来为 000EH,加2后 SP = 10H,所以栈为空的时候,SS = 1000H,SP = 10H。

图3.12描述了 8086CPU 对 pop 指令的执行过程:

image

pop ax 的执行过程和 push ax 刚好相反,由下面两步完成:

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

注意:出栈后,SS : SP 指向新的栈顶 1000EH,pop 操作钱的栈顶元素,1000CH 处的2266H 依然存在,但是它已不在栈中。当再次执行 push 等入栈指令后,SS : SP 移至 1000CH,新数据将覆盖旧数据。

# 3.8 栈顶超界问题

CPU 不会保证我们对栈的操作不会超界。CPU 只知道栈顶 (SS : SP) 在何处,不知道安排的栈的空间由多大。所以编程的时候操心栈顶超界的问题。

# 3.9 栈的总结

初始化栈的代码

mov ax,1000H
mov ss,ax
mov sp,0010H	;
1
2
3
  1. 在 ss,sp 中存放栈顶的段地址和偏移地址:提供入栈和出栈的指令,他们根据 SS : SP 指示的地址,按照栈的方式访问内存单元
  2. push 指令的执行步骤:①sp = sp-2 ②向 ss : sp 指向的字单元中送入数据
  3. pop 指令的执行步骤:①从 ss :sp 指向的字单元中读取数据 ②sp = sp+2
  4. 任意时刻,ss : sp 指向栈顶元素
  5. CPU 只记录栈顶,栈空间的大小由我们自己管理
  6. 用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的相反
  7. push,pop 实质是一种内存传送指令,注意他们灵活使用

总结:栈是一种非常重要的机制,一定要深入理解,灵活掌握

image

# 3.10 段的综述

我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元

我们用一个段存放数据,可以定义为 ==数据段==

我们用一个段存放代码,可以定义为 ==代码段==

我们用一个段当作栈,可以定义为 ==栈段==

==数据段:== 将段地址存放在 DS 中

==代码段:== 将它们的段地址存放在 cs 中,将段中的第一条指令的偏移地址存放在 IP 中,这样 CPU 就将执行我们定义的代码段中的指令

==栈段:== 段地址存放在 ss 中,将栈顶单元的偏移地址存放在sp中

第2章 寄存器
第4章 第一个程序

← 第2章 寄存器 第4章 第一个程序→

Theme by Vdoing | Copyright © 2023-2024 霜晨月
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式