汇编第八章
寄存器 reg: ax,bx,cx,dx,sp,dp,si,di (si,di 不能分为两个8位寄存器来使用)
段寄存器 sreg: ds,ss,cs,esw
(1)在8086CPU中只有这四个寄存器可以在[…]中进行内存单元的寻址。
比如,下面的指令都是正确的:
1 | mov ax,[bx] |
而下面都是错误的:
1 | mov ax,[cx] |
(2).在[…]中,这四个寄存器可以单独出现,或者只能以四种组合出现:bx和si、bx和di、bp和si、bp和di。
比如下面都是正确的
1 | mov ax,[bx] |
下面就是错误的
1 | mov ax,[bx+bp] |
(3)只要在[…]中使用寄存器bp,而指令汇总没有显示给出段地址,段地址就默认在ss中。 比如下面的指令。
1 | mov ax,[bp] 含义:(ax)=((ss)*16+(bp)) |
div指令
div是除法指令,使用div做除法的时候应注意以下问题:
1、除数:有8位和16位两种,在一个寄存器或者内存中。
2、被除数:默认放在AX或(DX和AX)中,如果除数为8位,被除数为16位,被除数默认在AX中存放,如果除数为16位,被除数为32位,被 除数则在(DX和AX)中存放,DX存放高16位,AX存放低16位。
3、结果:如果除数是8位,则AL存储除法操作的商,AH存储除法操作的余数;如果除数是16位,则AX存储除法操作的商,DX存储除法操作的余数。
格式如下:
div reg
div 内存单元
例子:
1 | div byte ptr ds:[0] |
以100001/100为例,100001大于65535,所以只能用dx和ax两个寄存器联合存放100001,也就是说要进行16位的除法。除数100小于255,可以在一个8位的寄存器中存放,但是被除数是32位的,除数应为16位,所以要使用一个16位的寄存器来存放除数100.
dx和ax分别存放100001的高16位和低16位值,所以将100001表示为16进制的形式:186a1h.
程序如下:
1 | DATAS |
程序执行后,ax=03e8h,dx=1(余数是1),在debug中查看如下所示:
1 | -p |
伪指令dd (double word)
dd用来定义dword(双字型)数据,占两个字
db 字节型数据 , db 'Hello' 其中每个字母占一个字节
dw 字型数据
dd dword (double word)双字型数据
1 | data |
例: 用div计算data段中第一个数据除以第二个数据后,商存放到第三个数据的存储单元中.
余数存储到第四个存储单元中.
1 | ;用div计算data段中第一个数据除以第二个数据后,商存放到第三个数据的存储单元中. |
操作符dup
dup 用来进行数据重复的
db 3 dup (0) ;定义了3个字节,相当于db 0,0,0
db 3 dup (0,1,2) ;定义了9个字节,相当于db 0,1,2,0,1,2,0,1,2
db 3 dup ('abc','ABC') 定义了18个字节, 相当于 db 'abcABCabcABCabcABC'
可见dup的使用格式如下:
db 重复的次数 dup(重复的字节型数据)
dw 重复的次数 dup(重复的字型数据)
dd 重复的次数 dup(重复的双字数据)
例: 定义一个容量为200个字节的栈段
1 | stack |
1 | ;结构体定义 |
这里发现有两个个地方不满足变化的规律,就是下面这两个地方:
1 | 1、 |
第一次bx为0的时候,是正确的,但第二次bx加了4之后,[bx+168]就变成了172了,正确的应该是170,所以这里是不满足的。那怎么办呢?
我们还有两个变址寄存器没出动呢,那我们现在就再出动 di 这个变址寄存器,来表示红笔3处的变址。上面两个不满足的地方也修改如下:
1、
; 雇员数
mov ax, ds:[di+168] ;****修改这里
mov es:[si+0ah], ax
2、
; 算人均收入,这里小心高低位,
mov ax, ds:[bx+84]
mov dx, ds:[bx+86]
push cx ; 临时用一下cx,因为不可以 div ds:[bx+168]
mov cx, ds:[di+168] ;*****也修改这里
div cx
pop cx
mov es:[si+0dh], ax
3、
; di还要记住在最后加上2
add si, 16
add bx, 4
add di, 2 ; 这里记住要加上2
loop s
做了上面这三步修改,就基本完成了
最终代码
1 | ;结构体定义 |