寄存器 reg: ax,bx,cx,dx,sp,dp,si,di (si,di 不能分为两个8位寄存器来使用)
段寄存器 sreg: ds,ss,cs,esw

参照表

(1)在8086CPU中只有这四个寄存器可以在[…]中进行内存单元的寻址。
比如,下面的指令都是正确的:

1
2
3
4
5
6
mov ax,[bx]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp]
mov ax,[bp+si]
mov ax,[bp+di]

而下面都是错误的:

1
2
3
4
mov ax,[cx]
mov ax,[ax]
mov ax,[dx]
mov ax,[ds]

(2).在[…]中,这四个寄存器可以单独出现,或者只能以四种组合出现:bx和si、bx和di、bp和si、bp和di。
比如下面都是正确的

1
2
3
4
5
6
7
8
9
10
11
12
mov ax,[bx]
mov ax,[si]
mov ax,[di]
mov ax,[bp]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp+si]
mov ax,[bp+di]
mov ax,[bx+si+idata]
mov ax,[bx+si+idata]
mov ax,[bp+si+idata]
mov ax,[bp+di+idata]

下面就是错误的

1
2
mov ax,[bx+bp]
mov ax,[si+di]

(3)只要在[…]中使用寄存器bp,而指令汇总没有显示给出段地址,段地址就默认在ss中。 比如下面的指令。

1
2
3
4
mov ax,[bp] 含义:(ax)=((ss)*16+(bp))
mov ax,[bp+idata] 含义:(ax)=((ss)*16+(bp)+idata)
mov ax,[bp+si] 含义:(ax)=((ss)*16+(bp)+(si))
mov ax,[bp+si+idata] 含义:(ax)=((ss)*16+(bp)+(si)+idata)

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)的余数

div byte ptr [bx+si+8]
(al)=(ax)/((ds)*16+(bx)+(si)+8)的商
(ah)=(ax)/((ds)*16+(bx)+(si)+8)的余数

div word ptr [bx+si+8]
(高十六位)+(低十六位)
(ax)=[(dx)*10000H+(ax)]/((ds)*16+(bx)+(si)+8)的商
(dx)=[(dx)*10000H+(ax)]/((ds)*16+(bx)+(si)+8)的余数

以100001/100为例,100001大于65535,所以只能用dx和ax两个寄存器联合存放100001,也就是说要进行16位的除法。除数100小于255,可以在一个8位的寄存器中存放,但是被除数是32位的,除数应为16位,所以要使用一个16位的寄存器来存放除数100.

dx和ax分别存放100001的高16位和低16位值,所以将100001表示为16进制的形式:186a1h.

程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
mov dx,1
mov ax,86a1h
mov bx,100
div bx

mov ax,4c00h
int 21h
CODES ENDS
END START

程序执行后,ax=03e8h,dx=1(余数是1),在debug中查看如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-p

AX=86A1 BX=0000 CX=0010 DX=0001 SP=0000 BP=0000 SI=0000 DI=0000
DS=0BA5 ES=0BA5 SS=0BB5 CS=0BB5 IP=0006 NV UP EI PL NZ NA PO NC
0BB5:0006 BB6400 MOV BX,0064
-p

AX=86A1 BX=0064 CX=0010 DX=0001 SP=0000 BP=0000 SI=0000 DI=0000
DS=0BA5 ES=0BA5 SS=0BB5 CS=0BB5 IP=0009 NV UP EI PL NZ NA PO NC
0BB5:0009 F7F3 DIV BX
-p

AX=03E8 BX=0064 CX=0010 DX=0001 SP=0000 BP=0000 SI=0000 DI=0000
DS=0BA5 ES=0BA5 SS=0BB5 CS=0BB5 IP=000B NV UP EI PL NZ AC PO NC
0BB5:000B B8004C MOV AX,4C00
-p

AX=4C00 BX=0064 CX=0010 DX=0001 SP=0000 BP=0000 SI=0000 DI=0000
DS=0BA5 ES=0BA5 SS=0BB5 CS=0BB5 IP=000E NV UP EI PL NZ AC PO NC
0BB5:000E CD21 INT 21
-p

伪指令dd (double word)

dd用来定义dword(双字型)数据,占两个字

db 字节型数据 , db 'Hello' 其中每个字母占一个字节
dw 字型数据
dd dword (double word)双字型数据
1
2
3
4
5
data segment
db 1 ; 一字
dw 1 ; 一字
dd 1 ; 两字
data ends

例: 用div计算data段中第一个数据除以第二个数据后,商存放到第三个数据的存储单元中.
余数存储到第四个存储单元中.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
;用div计算data段中第一个数据除以第二个数据后,商存放到第三个数据的存储单元中.
;余数存储到第四个存储单元中.
assume cs:codesg,ds:datasg
datasg segment ;储存 0B60:0 F A1 86 01 00 64 00 00 00 00 00
dd 100001
dw 100
dw 0
dw 0
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov ax,ds:[0] ;ax存储低16位
mov dx,ds:[2] ;dx存储高16位
div word ptr ds:[4] ;计算除法
mov ds:[6],ax ;商存储第3个单元
mov ds:[8],dx ;余数存储第4个单元

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

操作符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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  stack segment

    dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

    dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

    dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

    dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

    dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

  stack ends

  stack segment

    dw 200 dup (0)

  stack ends
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
;结构体定义
;char year[4] // 年
; 空格(1 Byte)
;int income (4 Bytes)// 收入
; 空格
;empoyer num (2 Bytes) // 雇员数
; 空格
;人均收入 (2 Bytes)
; 空格

; 要求:将data段的数据拷贝进table段数据,并结构化如上述格式,然后计算21年的人均收入

assume ds:data, es:table, cs:code, ss:stack

data segment
db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
db '1993', '1994', '1995'

dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514
dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000

dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
dw 11542, 14430, 15257, 17800
data ends

table segment
db 21 dup ('year summ ne ?? ')
table ends

; 弄个栈,没什么用
; 就有时候用来腾出个寄存器
stack segment
dw 2 dup(0)
stack ends

code segment

start:

; 设置data段,以及ds:bx指向data段的第一个单元,即ds:[bx]的内容就是data段第一个单元的内容
mov ax, data
mov ds, ax

; 设置table段
mov ax, table
mov es, ax

; 设置堆栈段
mov ax, stack
mov ss, ax
mov sp, 16

; 初始化三个变址寄存器
mov bx, 0
mov si, 0
mov di, 0

; 准备复制,需要用到循环,21次
mov cx, 21

s:
; 年
mov ax, ds:[bx+0] ; 这里写个0是为了下面的对照,清晰点
mov es:[si+0], ax
mov ax, ds:[bx+2]
mov es:[si+2], ax

; 空格
mov al, 32
mov es:[si+4], al

; 收入
mov ax, ds:[bx+84]
mov es:[si+5], ax
mov ax, ds:[bx+86]
mov es:[si+7], ax

; 空格
mov al, 32
mov es:[si+9], al

; 雇员数
mov ax, ds:[bx+168] ;****这里不满足
mov es:[si+0ah], ax

; 空格
mov al, 32
mov es:[si+0ch], al

; 算人均收入,这里小心高低位,
mov ax, ds:[bx+84]
mov dx, ds:[bx+86]
push cx ; 临时用一下cx,因为不可以 div ds:[bx+168] 因为内存单元中的长度为8位,实际除数应该设置为16位
mov cx, ds:[bx+168] ;*****这里同上,也不满足
div cx
pop cx
mov es:[si+0dh], ax

; 空格
mov al, 32
mov es:[si+0fh], al

add si, 16
add bx, 4
loop s

mov ax,4c00h
int 21h

code ends

end start

这里发现有两个个地方不满足变化的规律,就是下面这两个地方:

1
2
3
4
5
6
7
8
9
10
11
12
13
1、
; 雇员数
mov ax, ds:[bx+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:[bx+168] ;*****这里同上,也不满足
div cx
pop cx
mov es:[si+0dh], ax

第一次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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
;结构体定义
;char year[4] // 年
; 空格(1 Byte)
;int income (4 Bytes)// 收入
; 空格
;empoyer num (2 Bytes) // 雇员数
; 空格
;人均收入 (2 Bytes)
; 空格

; 要求:将data段的数据拷贝进table段数据,并结构化如上述格式,然后计算21年的人均收入

assume ds:data, es:table, cs:code, ss:stack

data segment
db '1975', '1976', '1977', '1978', '1979', '1980', '1981', '1982', '1983'
db '1984', '1985', '1986', '1987', '1988', '1989', '1990', '1991', '1992'
db '1993', '1994', '1995'

dd 16, 22, 382, 1356, 2390, 8000, 16000, 24486, 50065, 97479, 140417, 197514
dd 345980, 590827, 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000

dw 3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001, 1442, 2258, 2793, 4037, 5635, 8226
dw 11542, 14430, 15257, 17800
data ends

table segment
db 21 dup ('year summ ne ?? ')
table ends

; 弄个栈,没什么用
; 就有时候用来腾出个寄存器
stack segment
dw 2 dup(0)
stack ends

code segment

start:

; 设置data段,以及ds:bx指向data段的第一个单元,即ds:[bx]的内容就是data段第一个单元的内容
mov ax, data
mov ds, ax

; 设置table段
mov ax, table
mov es, ax

; 设置堆栈段
mov ax, stack
mov ss, ax
mov sp, 16

; 初始化三个变址寄存器
mov bx, 0
mov si, 0
mov di, 0

; 准备复制,需要用到循环,21次
mov cx, 21

s:
; 年
mov ax, ds:[bx+0] ; 这里写个0是为了下面的对照,清晰点
mov es:[si+0], ax
mov ax, ds:[bx+2]
mov es:[si+2], ax

; 空格
mov al, 32
mov es:[si+4], al

; 收入
mov ax, ds:[bx+84]
mov es:[si+5], ax
mov ax, ds:[bx+86]
mov es:[si+7], ax

; 空格
mov al, 32
mov es:[si+9], al

; 雇员数,小心处理
mov ax, ds:[di+168]
mov es:[si+0ah], ax

; 空格
mov al, 32
mov es:[si+0ch], al

; 算人均收入,这里小心高低位
mov ax, ds:[bx+84]
mov dx, ds:[bx+86]
push cx ; 临时用一下cx,因为不可以 div ds:[bx+168]
mov cx, ds:[di+168] ; mov cx, ds:[bx+168]错误了。。。
div word ptr cx
pop cx
mov es:[si+0dh], ax

; 空格
mov al, 32
mov es:[si+0fh], al

add si, 16
add bx, 4
add di, 2 ; 这里记住要加上2
loop s

mov ax,4c00h
int 21h

code ends

end start

https://blog.csdn.net/dylgsy/article/details/3984623