本次介绍指令要处理的数据长度,div 指定,dup 和 offset 操作符等相关知识。

指令要处理的数据长度

指令要处理的数据有多长呢?汇编语言通过以下方法来处理:

1.通过寄存器名称

例如下面的指令表明是字操作

mov ax,1
mov bx,[0]

而下面的指令则表明是字节操作

mov al,1
mov al,[0]

2.在没有寄存器名称存在的情况下,用操作符 X ptr 指明内存单元的长度,X 可以是 word 或 byte。

例如下面的指令表明的是字操作

mov word ptr ds:[0],1
add word ptr [bx],2

而下面的指令表明的是字节操作

mov byte ptr ds:[0],1
add byte ptr [bx],2

3.其它方法

例如 push 和 pop 指令只能进行字操作。

div 指令

div 是除法指令,在使用 div 的时候:

  • 被除数默认放在 ax 或 dx 和 ax 中,这个由除数决定。如果除数为 8 位,被除数则为 16 位,默认在 ax 中存放;如果除数为 16 位,则被除数为 32 位,在 dx 和 ax 中存放,dx 存储高 16 位,ax 存储低 16 位。

  • 除数有 8 位和 16 位两种,存放在寄存器或内存中

  • 商:如果除数为 8 位,则 al 存储商,ah 存储余数;如果除数为 16 位,则 ax 存储商,dx 存储余数

div 使用举例:计算 100001/100,100001 大于 65525,只能放在 dx 和 ax 中存储,dx 存放高 16 位,ax 存放低 16 位,100001 转换为 16 进制为 186a1H,则 dx 中存放高 16 位,即 dx 存放 1H,ax 存放低 16 ,即 86a1H,商存放在 ax 中,dx 存放 余数,通过口算可知商为 1000,表示成 16 进制为 03e8H,余数为 1, 代码如下:

assume cs:codesg
codesg segment
mov dx,1
mov ax,86a1H
mov bx,100
div bx
codesg ends
end

验证结果:

1
1

dup

dup 是一个操作符,和 db、dw、dd 配和使用用来定义重复的数据。例如 db 3 dup (0) 表示定义了 3 个字节,值都为 0,相当于 db 0,0,0

操作符 offset

offset 是编译器要处理的符号,意义为取得标号处的偏移地址。
例如下面的代码

assume cs:codesg
codesg segment
start: mov ax,offset start
s: mov ax,offset s

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

mov ax,offset start 相当于 mov ax,0

mov ax,offset s 相当于 mov ax,3

在 debug 中可以得到验证:

2
2

如果没有 debug ,怎么能判判断处标号处的偏移地址呢,可知关键的是要知道指令的长度,指令的长度的判断有以下方法:

  • 没有操作数的指令,指令长度为 1 字节。如:es ,ds,cbw,xlat 等
  • 操作数只涉及寄存器的指令,指令长度为 2 字节。如:mov al,[si]、mov ax,[bx+si]、mov ds,ax 等
  • 操作数涉及内存地址的指令,指令长度为 3 字节。如:mov al,[bx+1]、mov ax,[bx+si+3]、lea di,[1234]、mov [2345],ax 等
  • 操作数涉及立即数的指令,指令长度为:寄存器类型 + 1。8 位寄存器,寄存器类型 = 1;16 位寄存器,寄存器类型 =2。如 :mov al,8 ;指令长度为 2,mov ax,8 ;指令长度为 3
  • 跳转指令,分3种情况,指令长度分别为 2、3、5 字节。
    • 段内跳转,指令长度 =(目标地址-指令当前地址)+1。
      • 目标地址 - 指令当前地址若能用 1 个字节表示,则占用 1 个字节,整体指令长度为2字节,如 0113 jmp 0185 ;0185h-0113h = 72h,72h 可用 1 个字节表示,整体指令长度为2字节;
      • 目标地址 - 指令当前地址若能用 2 个字节表示,则占用 2 个字节,整体指令长度为 3 字节,如 0113 jmp 0845 ;0845h-0113h = 732h,732h 需用 2 个字节表示
    • 段间跳转,指令长度为 5 字节。如:jmp 1234:5678