在代码段中使用数据
问题引入
问题1
前面我们写的程序中,只有一个代码段。
现在有一个问题是: 如果程序需要用其他空间来存放数据,我们使用哪里呢?
第5章中,我们讲到要使用一段安全的空间。 我们说0:200~0:300是相对安全的;
可这段空间的容量只有256个字节,如果我们需要的空间超过256个字节该怎么办呢? 放心,系统妈妈会给的。怎么给呢?我们粗略地讲下,但这不是必须要会的,听过就行。
问题2
考虑这样一个问题,编程计算以下8个数据的和,结果存在ax 寄存器中:
0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H。
在前面的课程中,我们都是累加某些内存单元中的数据,并不关心数据本身。 可现在我们要累加的就是已经给定了数值的数据。
解决代码
assume cs:code
code segment
dw 0123H, 0456H, 0789H, 0abcH, 0defH, 0fedH, 0cbaH, 0987Hstart:mov bx, 0mov ax, 0mov cx, 8s: add ax, cs:[bx]add bx, 2loop smov ax, 4c00Hint 21H
code ends
end start
dw命令
上述程序第一行中的 “dw”的含义是定义字型数据。
dw即define word。 在这里,我们使用dw定义了8个字型数据(数据之间以逗号分隔),它们所占的内存空间的大小为16个字节。
程序中的指令就要对这8个数据进行累加,可这8个数据在哪里呢?
由于它们在代码段中,程序在运行的时候CS中存放代码段的段地址,所以我们可以从CS中得到它们的段地址。
这8个数据的偏移地址是多少呢?
因为用dw定义的数据处于代码段的最开始,所以偏移地址为0,这8 个数据就在代码段的偏移0、2、4、6、8、A、C、E处。
程序的框架
从上面的程序,我们可以得到一个程序都会有的部分,也就是固定格式
assume cs:code
code segment:数据:
start::代码:
code ends
end start
将数据、代码、栈放入不同的段
为什么
在前面的内容中,我们在程序中用到了数据和栈,我们将数据、栈和代码都放到了一个段里面。
我们在编程的时候要注意何处是数据,何处是栈,何处是代码。
这样做显然有两个问题:
(1)把它们放到一个段中使程序显得混乱;
(2)前面程序中处理的数据很少,用到的栈空间也小,加上没有多长的代码,放到一个段里面没有问题。那如果数据很多,而一个段最大64kb,会溢出。
所以,我们应该考虑用多个段来存放数据、代码和栈。
问题引入
完成下面的程序,利用栈,将程序中定义的数据逆序存放。
assume
cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
?
code ends end
如果将数据全部存放在一个段,如下:
assume cs:code
code segment
dw 0123H, 0456H, 0789H, 0abcH, 0defH, 0fedH, 0cbaH, 0987H
dw 0H, 0H, 0H, 0H, 0H, 0H, 0H, 0Hstart:mov ax, csmov ss, axmov bx, 0mov sp, 32mov cx, 8s1: push cs:[bx]add bx, 2loop s1mov bx, 0mov cx, 8s2: pop cs:[bx]add bx, 2loop s2mov ax, 4c00Hint 21Hcode ends
end start
怎样做
我们用和定义代码段一样的方法来定义多个段,然后在这些段里面定义需要的数据,或通过定义数据来取得栈空间。
我们重新写一版上面的代码,对其进行优化,将数据,代码,栈放入不同的段
代码:
assume cs:code, ds:data, ss:stack ; 段寄存器定义data segmentdw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h ; 原始数据
data endsstack segmentdw 0, 0, 0, 0, 0, 0, 0, 0 ; 预留 8 个 word 的栈空间
stack endscode segment
start:mov ax, stack ; 设置栈段mov ss, axmov sp, 16 ; 栈指针初始化,指向栈段顶端(16 = 8*2)mov ax, data ; 设置数据段mov ds, axmov bx, 0 ; BX 用作数组索引mov cx, 8 ; 共有 8 个 word 数据; ====== 将数据依次压入栈 ======
push_loop:push ds:[bx] ; 将 data 段中的数据压入栈add bx, 2 ; 指向下一个 wordloop push_loop ; 循环 8 次,压入所有数据mov bx, 0 ; 重新指向 data 段起始位置mov cx, 8 ; 重新计数 8 次; ====== 从栈中依次弹出数据,存入 data 段,实现逆序 ======
pop_loop:pop ds:[bx] ; 从栈中弹出数据,存入 data 段add bx, 2 ; 指向下一个 word 存储位置loop pop_loop ; 继续循环直到 8 个数据全部存回; ====== 程序结束 ======mov ax, 4c00h ; 终止程序int 21hcode ends
end start
实例解释
现在,我们以一个具体的程序来再次讨论一下所谓的“代码段”、“数据段”、“栈段”。
我们在源程序中为这三个段起了具有含义的名称,用来存放数据的段我们将其命名为“data”,用来放代码的段我们将其命名为“code”,用来作栈空间的命名为“stack”。
但CPU看的懂这些名称吗? Absolutely not!!
我们在源程序中用伪指令 “assume cs:code,ds:data,ss:stack”
将cs、ds和ss分别和code、data、stack段相连。
这样做了之后,CPU是否就会将 cs指向 code,ds 指向 data,ss 指向stack,从而按照我们的意图来处理这些段呢? Absolutely not!!
若要CPU按照我们的安排行事,就要用机器指令控制它,源程序中的汇编指令是CPU要执行的内容。
那么,CPU如何知道去执行它们?
我们在源程序的最后用“end start”说明了程序的入口,这个入口将被写入可执行文件的描述信息,可执行文件中的程序被加载入内存后,CPU的CS:IP被设置指向这个入口,从而开始执行程序中的第一条指令。
标号“start”在“code”段中,这样CPU就将code段中的内容当作指令来执行了。
我们在code段中,使用指令:
mov ax,stack mov ss,ax mov sp,16
设置ss指向stack,设置ss:sp指向stack:16,
CPU 执行这些指令后,将把stack段当做栈空间来用。
CPU若要访问data段中的数据,则可用 ds 指向 data 段,用其他的寄存器(如:bx)来存放 data段中数据的偏移地址。
总之,CPU到底如何处理我们定义的段中的内容,是当作指令执行,当作数据访问,还是当作栈空间,完全是靠程序中具体的汇编指令,和汇编指令对CS:IP、SS:SP、DS等寄存器的设置来决定的。
总的来说,cpu只认识cs,ds,ss等有特殊含义的寄存器,比如cs指向的段会当成代码段,ds指向的段当成数据段,等等。
而我们将对应的内容存放到对应的段中,然后将这个段名(cpu会将这个名字解析成一个物理地址)复制给相应的寄存器,那么cpu就会正确地执行我们想要的逻辑。
就像上面,我们将数据存储到了一个叫data的段中,然后将这个段赋值给ds,那么cpu就会知道这些是数据,将他们当成数据执行
笔记
6.1在代码段中使用数据
1.dw的含义【定义字型数据:define word,16字节】
在数据段中使用dw定义数据,则数据在数据段中
在代码段中使用dw定义数据,则数据在代码段中
堆栈段也是一样
2.在程序的第一条指令前加一个标号start,并且这个标号在伪指令end后面出现
可以通知编译器程序在什么地方结束,并且也可以通知编译器程序的入口在哪里
6.2在代码段中使用栈
**补充:如果题目要求【逆序】存放,就要想到栈(FILO)
使用dw向系统申请一段空间,然后把这个空间当做栈
6.3将数据、代码、栈放入不同的段
1.在前面的6.1和6.2中,我们在程序中用到了数据和栈,我们在编程的时候要注意
何处是数据,何处是栈、何处是代码
2.这样做显然有两个问题
1.把他们放在一个段中是程序显得混乱
2.前面程序中处理的数据很少,用到的栈空间也小,放在一个段里面没有问题
但数据、栈、代码需要的空间超过64KB,就不能放在一个段中
(8086中一个段的容量不能大于64KB)
3.我们可以和定义代码段一样的方法来定义多个段
然后在这些段里面定义需要的数据,或通过定义数据来取得栈空间
4.将数据、代码、栈放入不同的段
1.我们可以在源程序中为这三个段起具有含义的名称
用来存放数据的段,我们将其命名为“data”
用来存放代码的段,我们将其命名为“code”
用来作栈空间的段,我们将其命名为“stack”
但是CPU看得懂吗?【不能】
2.我们在源程序中用伪指令
“assume cs:code,ds:data,ss:stack”将cs、ds和ss分别和code、data、stack段相连
这样做了之后,CPU是都就会将cs指向code,ds指向data,ss指向stack
从而按照我们的意图来处理这些段呢?【不能】
伪指令CPU看不懂,伪指令是给编译器看的
3.若要CPU按照我们的安排行事,就要用机器指令控制它,源程序中的汇编指令
才是CPU要执行的内容
需在在code段中给DS,CS、SS设置相应的值才能让CPU识别出数据段、代码段、堆栈段
其中汇编程序开始的地方(即代码段开始的地方)由end后面的标号所指向的地方给出
5.assume指令不可省略,至于为什么,需要以后多多体会