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章 寄存器(内存访问)
    • 第4章 第一个程序
    • 第5章 [BX]和loop指令
    • 第6章 包含多个段的程序
    • 第7章 更灵活的定位内存地址的方法
    • 第8章 数据处理的两个基本问题
      • 8.1 bx、si、di 和 bp
      • 8.2 机器指令处理的数据在什么地方
      • 8.3 汇编语言中数据位置的表达
        • 8.3.1 立即数
        • 8.3.2 寄存器
        • 8.3.3 段地址(SA)和偏移地址(EA)
      • 8.4 寻址方式
      • 8.5 指令要处理的数据有多长
      • 8.6 div 指令
      • 8.7 伪指令 dd
      • 8.8 dup
  • STM32

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

第8章 数据处理的两个基本问题

# 第8章 数据处理的两个基本问题

定义了两个描述符号:reg 和 sreg

  • reg 包含了:ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di
  • sreg 包含了:ds,ss,cs,es

# 8.1 bx、si、di 和 bp

只有 bx,si,di 和 bp 这4个寄存器可以用 [...] 中进行内存单元寻址

比如:下面的指令都是正确的:
mov ax,[bx]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp]
mov ax,[bp+si]
mov ax,[bp+di]

而下面的指令都是错误的:
mov ax,[cx]
mov ax,[ax]
mov ax,[dx]
mov ax,[ds]
1
2
3
4
5
6
7
8
9
10
11
12
13

在[...]中,这4个寄存器可以单个出现,或者只能以4中组合出现:bx 和 si,bx 和 di,bp 和si,bp和di,比如下面指令是正确的:

image

只要在[...]中使用寄存器bp,而指令中没有显性的给出段地址,段地址就默认在 ss 中,比如下面的指令

image

# 8.2 机器指令处理的数据在什么地方

在机器指令层面,不关心数据的值,只关心指令执行前一刻,将要处理的数据所在的位置。

要处理的数据可以在三个地方:CPU内部、内存、端口。

表 8.2 指令举例

机器码 汇编指令 指令执行前数据的位置
8E1E0000 mov bx,[0] 内存,ds:0单元
89C3 mov bx,ax CPU内部,ax寄存器
BB0100 mov bx,1 CPU内部,指令缓冲器

# 8.3 汇编语言中数据位置的表达

# 8.3.1 立即数

立即数:对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中),在汇编语言中称之为立即数,在汇编指令中直接给出

mov ax,1
add bx,2000h
or bx,00010000b
mov al,'a'
1
2
3
4

# 8.3.2 寄存器

寄存器:要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名

mov ax,bx
mov ds,ax
push bx
mov ds:[0],bx
push ds
mov ss,ax
mov sp,ax
1
2
3
4
5
6
7

# 8.3.3 段地址(SA)和偏移地址(EA)

指令要处理的数据存储在内存中,汇编指令可用 [x] 的格式给出 EA,SA 在某个段寄存器中。

存放段地址的寄存器可以是默认的,比如以下指令,段地址默认在ds中:

mov ax,[0]
mov ax,[di]
mov ax,[bx+8]
mov ax,[bx+si]
mov ax,[bx+si+8]
1
2
3
4
5

以下指令段地址默认在 ss 中

mov ax,[bp]
mov ax,[bp+8]
mov ax,[bp+si]
mov ax,[bp+si+8]
1
2
3
4

存放段地址的寄存器也可以是显性给出的,比如以下指令:

mov ax,ds:[bp]			含义:(ax) = ((ds)*16+(bp))
mov ax,es:[bx]			 含义:(ax) = ((es)*16+(bx))
mov ax,ss:[bx+si]		   含义:(ax) = ((ss)*16+(bx)+(si))
mov ax,cs:[bx+si+8]		   含义:(ax) = ((cs)*16+(bx)+(si)+8)
1
2
3
4

# 8.4 寻址方式

image

# 8.5 指令要处理的数据有多长

在机器指令中要指明指令进行的是字操作还是字节操作

通过寄存器名指明要处理的数据的尺寸

指明指令进行的是字操作
mov ax,1
mov bx,ds:[0]
mov ds,ax
mov ds:[0],ax
inc ax
add ax,1000

指明指令进行的是字节操作
mov al,1
mov al,bl
mov al,ds:[0]
mov ds:[0],al
inc al
add al,100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

使用操作符 X ptr 指明内存单元的长度,X 在汇编中可以指定为 word 或者 byte

用 word ptr 指明指令访问的内存单元是一个字单元
mov word ptr ds:[0],1
inc word ptr [bx]
inc word ptr ds:[0]
add word ptr [bx],2

用 byte ptr 指明指令访问的内存单元是一个字节单元
mov byte ptr ds:[0],1
inc byte ptr [bx]
inc byte ptr ds:[0]
add byte ptr [bx],2
1
2
3
4
5
6
7
8
9
10
11

在没有寄存器参与的内存单元访问指令中,用 word ptr 或 byte ptr 显性的指明所要访问的内存单元的长度是很有必要的!

假设我们用 Debug 查看内存的结果如下:

image

这是因为 mov byte ptr [1000H],1 访问的地址是 ds:1000H 的字节单元,修改的是 ds:1000H 单元的内容;

而 mov word ptr [1000H],1 访问的地址是 ds:1000H 的字单元,修改的是 ds:1000H 和 ds:1001H 两个单元的内容。

有些指令默认了访问的是字单元还是字节单元。

比如:push [1000H] 默认字单元,因为 push 指令只进行字操作。

# 8.6 div 指令

div 是除法指令,使用 div 做除法的时候注意以下问题:

要求被除数默认存放在 ax,或者 dx 和 ax 中,而且要求被除数的位数,必须是除数的2倍,比如说,除数位8位,被除数就为16位。为什么被除数的位数一定要为除数的2倍呢?

因为 CPU 只会做加法运算,把其它一切的算法都转换成加法,比如说,除数 就先转换加法,例如36/6 当 CPU 看到这个运算时,就会这样想,需要多少个 6 相加才能得到 36 呢,然后CPU就从1个6 ,2个6...........这样一种算下去,终于最后发现原来是6个6啊,从这我们可以看出,CPU 是不断的用除数相加,知道找到结果为止,这就出现问题了,如果被除数不是除数位数的2倍,再相加的过程中,就可能超出除数的位数所能表达的最大数值,从而越界,如果能保证 被除数是除数的2倍 ,这问题就能解决了,例如:8 /5 5+ 5 =10 超出所能表达的位数,08 /5 就可以解决这个问题

  1. 除数:有8位和16位两种,在一个 reg 或者内存单元中
  2. 被除数:默认放在 AX 或者 DX 和 AX 中,如果除数为8位,被除数为16位,默认在 AX 中存放;如果除数为16位,被除数为32位,在 DX 和 AX 中存放,DX 存高 16 位,AX 存低 16 位
  3. 商:如果除数为8位,AL 存储除法操作的商,AH 存储除法操作的余数;如果除数为16位,AX 存储除法操作的商,DX 村存储除法操作的余数

# 8.7 伪指令 dd

db 和 dw 定义字节型数据和字型数据,dd 用来定义 dword(double world,双字)型数据

data segment
	db 1
	dw 1
	dd 1
data ends
1
2
3
4
5

在 data 段中定义了 3 个数据

第一个数据为 01H,在 data:0 处,占1个字节;

第二个数据为 0001H,在 data:1 处,占1个字;

第三个数据为 00000001H,在 data:3 处,占2个字。

# 8.8 dup

dup 是一个操作符,和 db、dw、dd 等数据定义伪指令配合使用,用来进行数据的重复。

image

image

第7章 更灵活的定位内存地址的方法
51单片机和STM32区别

← 第7章 更灵活的定位内存地址的方法 51单片机和STM32区别→

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