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 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
| 一定要注意的是:我们是通过定义数据来取得一段空间【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
|