1.在代码段中使用数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
assume cs:codesg
codesg segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
mov bx,0
mov ax,0

mov cx,8
s: add ax,cs:[bx]
add bx,2
loop s

mov ax,4c00H
int 21h

codesg ends
end

1.dw的含义【dw 也是 define word】也就是定义字型数据

【每一个数据之前都需要用 , 隔开】

1
同样可以衍生处db 【define byte】也就是定义字节型数据

问题1:这八个字型数据是放在哪里的呢?

1
2
3
assume cs:codesg
codesg segment
dw xxxxxx
1
2
3
这8个数据肯定是放在这个定义好的cs【也就是代码段中】【所以他们的段地址肯定是cs】
那这8个的偏移地址是多少呢?
因为是在最开始的地方,所以偏移地址就是:2 4 6 8 ...

emmm,这8个字型数据放在了代码段,cpu就会把这8个字型的数据当作代码来运行【因为cpu都是去认二进制,而不会知道你这个是代码还是数据】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
assume cs:codesg
codesg segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
mov bx,0
mov ax,0

mov cx,8
s: add ax,cs:[bx]
add bx,2
loop s

mov ax,4c00H
int 21h

codesg ends
end
如果单纯的使用这个,就会错误
所以我们需要改进一下,把cs的指向mov bx,0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
assume cs:codesg
codesg segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
start: mov bx,0
mov ax,0

mov cx,8
s: add ax,cs:[bx]
add bx,2
loop s

mov ax,4c00H
int 21h

codesg ends
end start

在这里,我们在程序的第一条指令的前面加上了一个标号start,而这个标号在伪指令end的后面出现

也就是说:end的作用,除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方

就比如说这里,它通知了编译器的入口是在 start后面,所以就不会去把dw中的内容粗错

cpu 在找入口的时候,是首先去找到end 而不是去找start 因为这个start是可以改变的

在使用了这个end start这个标号之后,就可以在代码段中使用数据

1
也就是这里的dw xxx

也就是衍生出来了

1
2
3
4
5
6
7
8
9
10
11
assume cs:code
code segment
..
数据
..
startL
..
代码
..
code ends
end start

2.在代码段中使用栈

完成下面的程序,利用栈,将程序中定义的数据逆序存放

1
2
3
4
5
6
assume cs:codesg
codesg segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H

?
code ends

分析一波

1
也就是说:我们需要把cs:0~cs:15单元中,一共8个字单元。依次将这8个子单元的数据入栈,然后再依次出栈到这8个字单元中,从而实现了数据的逆序存放

问题来了:

1
我们就需要由一个空间来定义一个栈

解:

1
我们可以像之前一样,通过定义数据来取得一段空间,然后将这段空间当作栈空间来使用
1
一定要注意的是:我们是通过定义数据来取得一段空间【dw】,然后将这段空间来当作栈空间来使用

代码

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
assume cs:codesg
csdesg segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
dw 0,0,0,0,0,0,0,0 ;用dw定义空间,人为的当作栈来使用
;上面的一串就是说:cs:0~cs:15 和 cs:16~cs:1fH[31]都是数据【前面的一段当作数据段使用,后面的一段当作栈来使用】

start:
mov ax,cs
mov ss,ax ;这里就是把代码段地址给栈段地址,因为他们都是在这个cs段里面,只是偏移地址不同罢了
mov sp,32 ;这里是设置栈顶,原本的底部是31所以栈顶的位置是32【这里用的是10进制而非16进制】
mov bx,0

mov cx,8
s:
push cs:[bx] ;这里就是把cs:[bx]中的值依次放入ss:[sp]中,也就是cs:16~cs:1fH中,倒着入栈
add bx,2
loop s ;这次循环的代码就是让前面的8个数据入栈

mov bx,0 ;把bx重新定义回去

mov cx,8
s0:
pop cs:[bx] ;就是pop 把栈中的数据送入cs:[bx]中
add bx,2
loop s0 ;这一串代码就是说把原本入了栈的数据,从上往下依次出栈,送入cs[bx]中,原本最先入栈的最后出栈

mov ax,4c00H
int 21h

codesg ends
end start

检测点6.1

3.将数据,代码,栈,放入不同的段

1.在前面的内容中,我们在程序中用到了数据和栈,我们将数据,栈,代码都放到了一个段里面。我们在编程的时候要注意何处是数据,何处是栈,何处是代码。这样就很垃圾

2.放到一个段中,这样很乱,而且不能放大量的数据,因为在8086CPU中一个段也就是64KB

3.如何实现,把数据,栈,代码放到不同的段中呢?

把上面写的代码改造改造

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
assume cs:code, ds:data, ss:stack

data segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
data ends

stack segment
dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,stack
mov ss,ax
mov sp,20H ;上面是假设ss和stack联系起来,通过这一步后,就是真正的联系起来了

mov ax,data
mov ds,ax ;同理,补充-->段寄存器是不能之间被值给赋予的,必须要通过寄存器这个媒介
;data 其实本质就是地址也就是数据,得先放入ax后放入段寄存器
mov bx,0

mov cx,8
s: push [bx]
add bx,2
loop s

mov bx,0 ;总结一下
;这里 要记住:segment和ends是一段伪指令,它们中间是这个段寄存器中的内容
mov cx,2
s0: pop [bx] ;end 才是开始的地方,也就是说编译器会告诉CPU让CPU中的CS:IP去指向end xxx的位置
add bx,2 ;在这里是start,也就是说,end后面的标号,回去告诉cpu 这个命令执行开始的地方
loop s0

mov ax,4c00H
int 21h

code ends
end start

成功肯定是离不开一步一步的成长,所以我们现在来分析一下这个代码

1
2
assume cs:code, ds:data, ss:stack
假设 cs和code, ds和data, ss和stack连接起来了【给编译器看的,伪指令咯】

实验五

;编写code段中的代码,将a段和b段中的数据相加,结果保存到到c段

这里可以参考 m1.sam写的代码

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
;编写code段中的代码,将a段和b段中的数据相加,结果保存到到c段
assume cs:code

a segment
db 1,2,3,4,5,6,7,8
a ends

b segment
db 1,2,3,4,5,6,7,8
b ends

c segment
db 0,0,0,0,0,0,0,0
c ends

code segment
start:
mov ax, a
mov ds, ax ;这里把ds中指向a也就是说需要用到a中的值的时候是用的ds:[bx]来索引

mov ax, b
mov es, ax ;这里把es中指向b【段地址】

;mov ax,c
;mov ss,ax ;这里把ss中指向了c
;mov sp,8

mov bx,0

mov cx,8
s: mov dl,ds:[bx] ;这里把a中的第一个数据放进去
add dl,es:[bx] ;
;sub bx,1
;inc bx ;自己加上去
;这里已经把a和b中的值相加放到了dl中,所以现在需要把dl中的值放入c中
;也就是需要有一个 mov c地址,dl,当然这个c地址也要递增也需要用到bx,所以上面的inc bx先不慌加
;智商有限,这个只剩下了ss栈段,我们把c定义成栈,然后把数据放入栈也可以吧
;push dl
;loop s ;总体的思路就是吧c当作栈段,然后吧数据push进去,这里push的时候要注意是栈顶也就是sp指的位置,sp-2
;卧槽,写一半的时候发现push 是sp-2,这里是内存单元是8个字节,所以不能用push

;所以这里就不能用ss 也不能用push 只能用ds咯

push ds ;原本的ds是a这里零时用一下,所以需要把ds保护起来,也就是放入栈中
mov ax,c
mov ds,ax ;现在的ds是指向c
mov ds:[bx],dl
pop ds ;这里把ds还原
inc bx
loop s

mov ax,4c00H
int 21h

code ends
end start

;只能用push指令将a段中的前8个字型数据,逆序存储到b段中

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
;只能用push指令将a段中的前8个字型数据,逆序存储到b段中
assume cs:code

a segment
dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0eh,0fh,0ffh
a ends

b segment
dw 0,0,0,0,0,0,0,0
b ends

code segment
start:
;首先,只能用push说明,b段的段地址也就是我们定义的栈段的段地址,然后把a中的玩意push进去就好了三
mov ax,a
mov ds,ax

mov ax,b
mov ss,ax
mov sp,16

mov bx,0

mov cx,8
s: push ds:[bx]
add bx,2
loop s

mov ax,4c00H
int 21h
code ends
ends start