汇编语言笔记8处理数据的两个基本问题
汇编语言笔记8处理数据的两个基本问题
0x00 处理的数据在什么地方?
我们定义描述性符号reg表示一个段寄存器,定义seg表示段寄存器 reg有ax,bx,cx,dx,al,ah,bl,bh,cl,ch,dl,dh,sp,bp,si,di seg有ds ss cs es
在8086cpu中 址有bx si di 和bp可以用在[…]中用来进行内存单元的寻址,下列对这四个寄存器的用法进行总结:
绝大部分汇编指令都是进行数据处理的指令,处理分为三类,读取,写入,运行,而处理的数据可以在三个地方:cpu内部,端口(端口在后面学习)和内存,举例如下:
在汇编语言中,用三个概念来表达数据的位置:
(1)立即数 idata 即数据直接包含在机器指令中,例如 mov ax,1 add bx,00000001b
(2) 寄存器 即数据在寄存器里 例如 mov ax,bx push bx mov ds:[0],bx
(3)段地址(sa)和偏移地址(ea)指要处理的数据在内存中,在汇编指令中可用[x]的格式给出ea,sa在某个段寄存器中
存放段地址的寄存器可以是默认的 比如 mov ax,[0] mov ax,[di] mov ax,[bx+8] 等指令的段地址默认在ds里 而 mov ax,[bp] mov ax,[bp+9]等指令的段地址默认在ss中 。同时也可以显式的给出存放段地址的寄存器 比如 mov ax,ds:[bp] mov ax,es[bx]
当数据在内存中时,我们可以采用多种方式来给定这个内存单元的偏移地址,这种定位内存单元的方法称为寻址方式
8086寻址方式总结如下:
0x01 指令要处理的数据有多长?
8086cpu可以处理两种尺寸的数据,byte和word。所i在汇编指令中要指明经行字操作还是字节操作,对这个问题,有以下几种方式:
(1)通过寄存器知名要处理的数据的尺寸
mov ax,1 mov bx,ds:[0] inc ax add ax,1000 是字操作
mov al,1 mov al,bl mov al,ds:[0] inc al add al,100 都是字节操作
(2) 在没有寄存器存在的情况下,用操作符 X ptr 指明内存单元的长度 X可以是word或者byte (ptr是pointer)
mov word ptr ds:[0],1 inc word ptr ds:[0] add word ptr [bx],2 这些指令访问的内存单元是一个字节
mov byte ptr ds:[0],1 inc byte ptr [bx] inc byte ptr ds:[0] 这些指令访问的内存单元是两个字节
(3)其他方法 有些指令默认了访问的是字单元还是字节单元,比如 push pop 只进行字操作
0x02 寻址方式的综合应用
8086cpu支持类似结构体式的访问内存操作 一段连续的内存,保存一个完整结构的各个信息,就是c语言中的一个结构体,如下图
使用c语言来访问这个结构体的方式如下:
可以看到 c语言使用结构体名.属性[数组序号]的方式访问结构体的具体每一个内存单元 ,8086汇编也可以使用类似的写法:
可以用 偏移地址.偏移地址.偏移地址的形式
如上图 这种写法bx idata si顺序可以交换,一样是对的
0x03 div dd和dup指令
DIV
div是除法指令,有两种格式16位数据/8位数据 32位数据/16位数据。格式是div 除数 关于被除数和结果的位置:
(1) 16位/8位时 被除数提前放到AX中 运算结果 AL储存商 AH储存余数
(2)32位/16位时 被出示高16位放在DX 低16位放在AX AX储存商 DX储存余数
例如编程计算100001/100 因为100001大于65535被除数需要用32位所以AX储存低16位 dx储存高16位。 100001-》186a1h 所以dx 是1h ax是86a1h
mov dx,1
mov ax,86a1h
mov bx,100
div bx
ax结果是03e8 也就是1000 dx是1 运算结果正确
伪指令dd
之前有伪指令db dw 分别定义一个字节和一个字型的数据,而dd则定义双字节数据(double word)
data segment
db 1
dw 1
dd 1
data ends
第一个数据为01h 占一个字节 第二个为0001h 占两个字节 第三个为00000001h占四个字节
assume cs:code,ds:data
data segment
dd 100001
dw 100
dw 0
data ends
code segment
start: mov ax,data
mov ds,ax
mov ax,ds:[0]
mov dx,ds:[2]
mov bx,ds:[4]
div bx ;标准答案用的是直接div word ptr ds:[4]
mov ds:[6],ax
mov ax,4c00h
int 21h
code ends
end start
这里我犯了一个错误就是省了ds:[6]直接写的[6]报立即数错误 要记住只有[bs]才是默认ds寄存器可以不写 [bp]默认ss
dup伪指令
dup主要在数据定义的时候用来进行数据的重复 如下:
db 3 dup (0) 定义了三个字节 值都是0
db 3 dup (0,1,2) 定义了九个字节 0,1,2,0,1,2,0,1,2
db 3 dup (‘abc’,’ABC’) 定义了18个字节 ‘abcABCabcABC…..’
db/dw/dd 重复的次数 dup (重复的数据)
stack segment
db 200 dup (0)
stack ends
轻松定义200个字节的栈区