第六章
6.1 在代码段中使用数据
编程以下8个数据的和,结果存在ax寄存器中,用循环累加的方式
想用循环,就需要把这些数据存储在一组地址连续的内存单元中,之前提到过应该让系统来分配空间,因此我们在程序中定义希望处理的数据,这些数据最终会成为程序的一部分写到可执行文件中,可执行文件加载到内存中后,这些数据便自然获得了存储空间
assume cs:code
code segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
mov bx,0
mov ax,0
mov cx,8
s:add ax,cx:[bx]
add bx,2
loop s
mov ax,4c00H
int 21H
code ends
end
dw的含义是定义字型数据,这段代码中定义了8个字型数据,占16个字节的内存单元,由于在代码段中,且定义在代码段最开始,所以地址为CS:0,CS:2.CS:4……以此类推
在Debug中使用U命令,这些数据会被翻译为汇编指令,如果想要执行第一条真正的指令,就需要更改IP的值,这样一来,直接编译、连接而后执行的话会出现问题,因为IP初始为0,因此代码需要更改
assume cs:code
code segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
start: mov bx,0
mov ax,0
mov cx,8
s:add ax,cx:[bx]
add bx,2
loop s
mov ax,4c00H
int 21H
code ends
end start
伪指令end除了通知编译器程序结束外,还可以通知编译器程序的入口在哪
如何设置CPU中CS:IP指向第一条要执行的指令,这一点由可执行文件中的描述信息指明,上面的程序中end start指明入口地址的偏移地址为10H,这个信息被存放在可执行文件中,加载者会根据该信息设置CS:IP
6.2 在代码段中使用栈
利用栈,将程序中定义的数据逆序存放
assume cs:codesg
codesg segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;再定义16个字型数据,程序加载后
;取得16个字的内存空间
;后面的程序将这段空间当作栈来使用
start: mov ax,cs
mov ss,ax
mov sp,30H ;将cs:10~cs:2F的内存空间当作栈
;注意栈顶的设置方法
mov bx,0
mov cx,8
s:push cs:[bx]
add bx,2
loop s ;将代码段0~15单元8个字型数据入栈
mov bx,0
mov cx,8
s0:pop cs:[bx]
add bx,2
loop s0 ;依次出栈8个字型数据,达到逆序存放的目的
mov ax,4c00H
int 21H
codesg ends
end start
我们在描述dw的作用时,既可以说是用来定义数据,也可以说是用来开辟内存空间,最终效果是一样的,定义8个字型数据,也可以说开辟了8个字的内存空间
练习:
依次用内存0:0~0:15单元中的内容改写程序中的数据,数据的传送用栈来进行,栈空间设置在程序内
assume cs:codesg
codesg segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
dw 0,0,0,0,0,0,0,0,0,0 ;10个字单元用作栈空间
start: mov ax,cs
mov ss,ax
mov sp,24H
mov ax,0
mov ds,ax
mov bx,0
mov cx,8
s:push [bx] ;先把0:[bx]处的数据入栈
pop cs:[bx] ;入栈后立刻弹出存到原有数据处cs:0 cs:2等
add bx,2
loop s
mov ax,4c00H
int 21H
codesg ends
end start
6.3 将数据、代码、栈放入不同的段
在前面的内容里我们把数据、栈、代码等放到同一个段里,这样显得混乱,如果数据、栈、代码需要的空间超过64KB,就超出了一个段的最大容量(8086模式下)
因此考虑用多个段分别存放
assume cs:code,ds:data,ss:tack
data sgement
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
data ends
stack segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,20H ;设置栈顶ss:sp指向stack:20
mov ax,data
mov ds,ax ;ds指向data段
mov bx,0 ;ds:bx指向data段中的第一个单元
mov cx,8
s:push [bx]
add bx,2
loop s ;将data段0~15单元8个字型数据入栈
mov bx,0
mov cx,8
s0:pop [bx]
add bx,2
loop s0 ;依次出栈8个字型数据到data段中的0~15单元中
;达到逆序存放的目的
mov ax,4c00H
int 21H
codesg ends
end start
程序中,段名相当于一个标号,代表了段地址,mov ax,data的含义就是将名称为data段的段地址送入ax,不能使用mov ds,data,因为8086CPU不允许将一个数值直接送入段寄存器中,data和stack都被编译器处理为一个表示段地址的数值
这里命名的stcak,data,code只是我们的命名,CPU并不会因此就去把stack段当作栈,data段存放数据,即使assume cs:code,ds:data,ss:tack,CPU也不会使cs指向code,ds指向data,这些都只是标号,仅存在于源程序中
想要CPU按照我们的安排操作,需要用机器指令控制,源程序中的汇编指令是CPU需要执行的内容,我们用end start使得CPU得知第一条指令的位置
通过
mov ax,stack
mov ss,ax
mov sp,20H
设置ss:sp指向stack:20,所以把stack段当作栈空间使用
总之,CPU如何处理我们定义段的内容,当作数据还是段,完全靠汇编指令以及汇编指令对具体寄存器的设置来决定的,将源程序中code改为a,data改为b,stack改为c,start改为d也是可以的