汇编语言学习笔记(八):数据处理的两个基本问题

学习参考:汇编语言(第2版)王爽

  • bx、si、di 和 bp
  • 机器指令处理的数据在什么地方
  • 汇编语言中数据位置的表达
  • 寻址方式
  • 指令要处理的数据有多长
  • div 指令
  • 伪指令 dd
  • dup

计算机作为进行数据处理、运算的机器,那么有两个基本问题:

  • 处理的数据在什么地方
  • 要处理的数据有多长

我们使用 reg 来表示一个寄存器,sreg 表示一个段寄存器

  • reg 的集合包括:ax、bx、cx、dx、ah、al、bh、bl、ch、cl、dh、dl、sp、bp、si、di
  • sreg的集合包括:ds、ss、cs、es

bx、si、di 和 bp

  • 只有这四个寄存器可以用在 “[…]” 中来进行内存单元的寻址
  • 这四个寄存器可以单个出席那,或只能以四种组合出现:
    • bx 和 si
    • bx 和 di
    • bp 和 si
    • bp 和 di
  • 只要在 “[…]” 中使用寄存器 bp,而指令中没有显性地给出段地址,段地址就默认在 ss 中

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

进行数据处理的指令分为三类:

  • 读取
  • 写入
  • 运算

在机器指令这一层来讲,并不关心数据的值是多少?而关心指令执行前一刻,它将要处理的数据所在的位置

在指令执行之前,所要处理的数据可以在 3 个地方:

  • CPU 内部
  • 内存
  • 端口

指令举例

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

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

用 3 个概念表达数据的位置

  • 立即数(idata):对于直接包含在机器指令中的数据(执行前在 CPU 的指令缓冲器中)

    1
    2
    3
    4
    mov ax,1
    add bx,2000h
    or bx,00010000b
    mov al,'a'
  • 寄存器:指令要处理的数据在寄存器中

    1
    2
    3
    4
    mov ax,bx
    mov ds,ax
    push bx
    mov ds:[0],bx
  • 段地址(SA)和偏移地址(EA):指令要处理的数据在内存中,在汇编指令中可用[x]的格式给出 EA,SA 在某个段寄存器中

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

寻址方式

指令要处理的数据有多长

8086CPU 的指令,可以处理两种尺寸的数据,byte 和 word。所以在机器指令中要指名,指令进行的是字操作还是字节操作。对于这个问题,用一下方法处理

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

    下面进行的是字操作

    1
    2
    3
    4
    5
    6
    mov ax,1
    mov bx,ds:[0]
    mov ds,ax
    mov ds:[0],ax
    inc ax
    add ax,1000
下面进行的是字节操作

1
2
3
4
5
6
mov al,1
mov al,bl
mov al,ds:[0]
mov ds:[0],al
inc al
add al,100
  • 在没有寄存器名称存在的情况下,用操作符 X ptr 指明内存单元的长度,X 在汇编指令中可以为 word 或 byte

    下面的指令中,用 word ptr 指明了指令访问的内存单元是一个字单元

    1
    2
    3
    4
    mov word ptr ds:[0],1
    inc word ptr [bx]
    inc word ptr ds:[0]
    add word ptr [bx],2
下面的指令中,用 byte ptr 指明了指令访问的内存单元是一个字节单元
1
2
3
4
mov byte ptr ds:[0],1
inc byte ptr [bx]
inc byte ptr ds:[0]
add byte ptr [bx],2
  • 其他方法

    有些指令默认了访问的字单元还是字节单元,比如,push 指令只进行字操作

div 指令

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

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

格式如下

1
2
div reg
div 内存单元

现在可以有多种方法来表示一个内存单元了,比如下面的例子:

1
2
3
4
5
6
7
div byte ptr ds:[0]
含义: (al)=(ax) / ((ds)*16+0) 的商
(ah)=(ax) / ((ds)*16+0) 的余数

div word ptr es:[0]
含义: (ax)=[(dx)*10000H + (ax)] / ((es)*16+0) 的商
(dx)=[(dx)*10000H + (ax)] / ((es)*16+0) 的余数

dx*10000H 相当于将 dx 左移了 16 位

编程 利用除法指令计算 100001/100

分析:被除数大于 65535(2^16),不能用 ax 寄存器存放,所以只能使用 dx 和 ax 两个寄存器联合存放 100001,也就是说要进行 16 位的除法。除数 100 小于 255,可以在一个 8 位寄存器存放,但是,因为被除数是 32 位的,除数应为 16 位,所以要用一个 16 位寄存器来存放被除数 100

因为要分别为 dx 和 ax 赋 10001 的高 16 位值和低 16 位值,所以应先将 100001 表示为 16 进制形式:186A1H,程序如下:

1
2
3
4
mov dx,1
mov ax,86a1 ;(dx)*10000H+(ax)=100001
mov bx,100
div bx

程序执行后,(ax)=03E8H(即 1000),(dx)=1(余数为 1)

编程 利用除法指令计算 1001/100

分析:被除数 1001 小于 65535 ,所以可以用 ax 寄存器存储,除数 100 小于 255,可以用 8 位寄存器存储,也就是说要进行 8 位的除法。程序如下:

1
2
3
mov ax,1001
mov bl,100
div bl

程序执行后,(al)=0AH(即 10),(dh)=1(余数为 1)

伪指令 dd

dd 是用来定义 dword(double word,双字)型数据的。比如:

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

在 data 段中定义了 3 个数据

第一个数据为 01H,在 data:0 处,占 1 个字节
第二个数据为 0001H,在 data:1 处,占 1 个字
第三个数据为 00000001H,在 data:3 处,占 2 个字

用 div 计算data段中第一个数据除以第二个数据后的结果,商存在第三个数据的存储单元中。

1
2
3
4
5
data segment
dd 100001
dw 100
dw 0
data ends

分析:data 段中的第一个数据是被除数,为 dword(双字)型,32 位,所以在做除法之前,用 dx 和ax 存储。应将 data:0 字单元中的低 16 位存储在ax中,data:2 字单元中的高16位存
储在 dx 中。程序如下。

1
2
3
4
5
6
mov ax,data 
mov ds,ax
mov ax,ds:[0] ;ds:0字单元中的低16位存储在ax中
mov dx,ds:[2] ;ds:2字单元中的高16位存储在dx中
div word ptr ds:[4] ;用dx:ax中的32位数据除以ds:4字单元中的数据
mov ds:[6],ax ;将商存储在ds:6字单元中

dup

和 db、dw、dd 等数据定义伪指令配合使用,用来表示数据的重复

格式如下

1
2
3
db 重复次数 dup (重复的字节型数据)
dw 重复次数 dup (重复的字型数据)
dd 重复次数 dup (重复的双字节数据)
文章作者: Inno Fang
文章链接: https://innofang.github.io/2017/11/25/汇编语言学习笔记(八):数据处理的两个基本问题/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来自 Inno's Blog