本篇介绍在汇编中使用多个段编写代码以及更多的寻址方式。

栈的使用

利用栈将程序中定义的数据逆序存放,代码如下:

assume cs:codesg
codesg segment
dw 0001H,0002H,0003H,0004H,0005H,0006H,0007H,0008H
dw 0,0,0,0,0,0,0,0

start: mov ax,cs
mov ss,ax
mov sp,32
mov bx,0
mov cx,8
s: push cs:[bx]
add bx,2
loop s

mov bx,0
mov cx,8
s0: pop cs:[bx]
add bx,2
loop s0

mov ax,4c00h
int 21H
codesg ends
end start

将数据、代码、栈放入不同的段

上面的程序稍加修改,改为下面的,则可将数据、代码、栈放入不同的段,代码如下:

assume cs:codesg,ds:data,ss:stack
data segment
dw 0001H,0002H,0003H,0004H,0005H,0006H,0007H,0008H
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
codesg segment
start: mov ax,stack
mov ss,ax
mov sp,16

mov ax,data
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov bx,0
mov cx,8
s0: pop [bx]
add bx,2
loop s0

mov ax,4c00h
int 21H
codesg ends
end start

从程序中看出,定义多个段和前面的定义代码一样,都是用 assume 的方法。

指令 mov ax,stack 的意义是将 stack 段的段地址放入 ax,然后 mov ss,ax 表示把 stack 段的段地址放入 ss 中,这样我们就正确的设置栈段的段地址。同理 mov ax,data 和 mov ds:ax 表示一样的意思,是将代码段的段地址放入 ds 中。

and 和 or 指令

and 表示按位与指令,or 表示逻辑或指令,进行按位或运算。

例如指令
mov al,01110000B
and al,00010000B
执行后 al 中的内容为 00010000B

再例如指令
mov al,00000000B
or al,11111110B
执行后 al 中的内容为 11111110B

更灵活的寻址方式

前面介绍过用 [idata] 的方式进行寻址,当然也可以用 [bx] 的方式寻址,同样也可以用 [bx + idata] 的方式寻址,它表示的意义为 [bx + idata] 表示一个内存单元,它的偏移地址为 bx 中的值加上 idata 的值,段地址在 ds 中。例如指令 mov ax,[bx + 200] ,它表示将一个内存单元中的内容送入 ax 中,这个内存单元的偏移地址为 bx 中的内容加上 200,段地址在 ds 中。该指令还可以用以下的形式表示:

  • mov ax,[200 + bx]
  • mov ax, 200[bx]
  • mov ax, [bx].200

SI 和 DI 是 8086CPU 中和 bx 功能相近的寄存器,但是它们不能够用作两个 8 为寄存器来使用。当然也能够用 [bx + si] 或者 [bx + di] 的方式来寻址,同样的也可以用 [bx + si + idata] 或者 [bx + di + idata] 的方式来寻址。指令 mov ax,[bx + si + 200] 的含义为:它表示一个内存单元中的内容送入 ax 中,这个内存单元的偏移地址为 bx 加 si 加 200 ,段地址在 ds 中。该指令也可以用以下常用的形式表示:

  • mov ax,[dx + 200 + si]
  • mov ax,[200 + dx + si]
  • mov ax,200[bx][si]
  • mov ax,[bx].200[si]
  • mov ax,[bx][si].200

目前为止,已经学到了很多种寻址的方法,总结如下:

  • [idata] 用一个常量定位一个内存单元
  • [bx] 用一个变量定位一个内存单元
  • [bx + idata] 用一个变量和常量定位一个内存单元
  • [bx + si] 或 [bx + di] 用两个变量来定位一个内存单元
  • [bx + si + idata] 或 [bx + di + idata] 用两个变量和一个常量来定位一个内存单元

实战:用 si 和 di 实现将字符串 ‘welcome to masm!’ 复制到它后面的数据区中,代码如下

assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!'
db '................'
datasg ends

codesg segment
start: mov ax,datasg
mov ds,ax
mov si,0
mov di,16
mov cx,8
s: mov ax,[si]
mov [di],ax
add si,2
add di,2
loop s

mov ax,4c00h
int 21H
codesg ends
end start

代码执行后,从下图可以看出复制成功了。

1
1

在 8086CPU 中只有 bx、si、di、bp 这四个寄存器能用 […] 的方式寻址。当然也可以是这组合形式,比如:bx 和 si,bx 和 di,bp 和 si,bp 和 di,而 bx 和 bp 或者 si 和 di 却是错误的。

寻址方式总结

通过前面的学习,现将 8086CPU 的寻址方式做以下总结:

寻址方式 名称
[idata] 直接寻址
[bx],[bp],[si],[di] 寄存器间接寻址
[bx+idata],[bp+idata],[si+idata],[di+idata] 寄存器相对寻址
[bx+si],[bx+di],[bp+si],[bp+di] 基址变址寻址
[bx+si+idata],[bx+di+idata],[bp+si+idata],[bp+di+idata] 相对基址变址寻址

总结

通过本次学习,我们知道了怎么在汇编中运用多个段来编写程序,了解了 and 指令和 or 指令的用法,总结了 8086CPU 的寻址方式,收获颇丰,继续努力!