小甲鱼零基础汇编语言学习笔记第六章之包含多个段的程序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小甲鱼零基础汇编语言学习笔记第六章之包含多个段的程序相关的知识,希望对你有一定的参考价值。

     在前面的几个章节中,我们的程序都是只有一个代码段,本章我们开始学习如何编写包含多个段的程序。
 
1、在代码段中使用数据
     首先考虑这样一个问题,计算以下8个数据的和,结果存放在ax寄存器中:
     0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
     在前面的课程中,我们都是累加某些内存单元中的数据,并不关心数据本身,可现在我们要累加就是已经给定了数值的数据。
     代码如下:
技术分享
 1 assume cs:codesg
 2 codesg segment
 3      dw  0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
 4      mov bx,0
 5      mov ax,0
 6      mov cx,8
 7 s:  add ax,cs:[bx]
 8      add bx,2
 9      loop s
10      mov ax,4c00h
11      int 21h
12 codesg ends
13 end
View Code

 

     在该程序第一行中的"dw"的含义是定义字型数据,即define word。在这里,我们使用dw定义了8个字型数据(数据之间用逗号分隔),它们所占的内存空间大小为16个字节。
     将代码进行编译,连接后,使用debug进行调试,我们可以看到,在地址0B4FH:0000这个地址单元中,存放了我们定义的字型数据:
     技术分享
     在0B4FH:0010开始的地址单元中,存放了我们的指令:
     技术分享
     但是我们查看0B4F:0000这个地址单元时,它却并没有存放我们的指令(按理说应该是会存放我们的指令的,但是我们的指令却是存放在0B4FH:0010开始的地址单元中):
     技术分享
     出现这样的原因是,cpu读取的是指令所对应的机器码,从0B4F:0000开始的地质单元中,存放的是由数据0123h、0456h等我们预先定义好的字型数据转换成机器码所对应的指令,这样造成了cpu的误读。要解决这个问题,我们就应该给程序指定一个入口,而不是直接从定义字型数据的指令开始,所以程序应该改为如下所示:
     
技术分享
 1 assume cs:codesg
 2 codesg segment
 3       dw  0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
 4 start:mov bx,0
 5         mov ax,0
 6         mov cx,8
 7  
 8 s:     add ax,cs:[bx]
 9         add bx,2
10         loop s
11  
12    mov ax,4c00h
13    int 21h
14 codesg ends
15 end start
View Code

 

     我们重新编译连接这个程序,然后使用debug调试后,使用r命令查看寄存器的情况,可以发现,cs:ip默认就指向了程序的第一条指令,这是因为我们在程序中定义了一个程序的入口,但是程序是根据最后的end来查找程序的入口的,这一点要特别提醒一下。debug调试如图所示:
     技术分享
 
2、在代码段中使用栈
     首先我们还是考虑一个问题,利用栈将程序定义的数据逆序存放,这个程序的代码应该如何来写?
     当我们看到逆序存放这样的字眼的时候,就应该首先想到栈,应为要实现逆序,就必定会用到栈“LIFO”这个特性(后进先出)。所以程序的代码如下所示:
技术分享
 1 assume cs:codesg
 2 codesg segment
 3      dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
 4      dw 0,0,0,0,0,0,0,0 ;这里用dw定义8个字型数据,在程序加载后,将取得8个字的内存空间,存放这8个数据,我们在后面的程序中         ;就将这段空间当做栈来使用。
 5  
 6 start:mov ax,cs
 7         mov ss,ax
 8         mov sp,32 ;这里设置栈顶ss:sp指向cs:32
 9         mov bx,0
10         mov cx,8
11 s:     push cs:[bx]
12         add bx,2
13         loop s ;这里是将代码段0~16单元中的8个字型数据依次入栈
14  
15         mov bx,0
16         mov cx,8
17  s0:  pop cs:[bx]
18         add bx,2
19         loop s0 ;这里依次出栈8个字型数据到代码段0~16单元中
20  
21         mov ax,4c00h
22         int 21h
23  
24 codesg ends
25 end start
View Code

 

     在编译连接这段程序后,我们使用debug来查看程序的运行情况:
     技术分享
     我们是用t和d命令,来看看执行指令后,内存单元中的存储情况:
     技术分享
     技术分享
     此时使用d命令来查看内存的情况:
     技术分享

 

3、将数据、代码、栈放入不同的段中
     在前面的程序中,我们将数据、代码、栈放在了同一个段中,这样使程序显得很混乱。假如程序中的数据、代码、栈不大的话,这样做没问题,但是程序变大后,程序将变得很难看。在8086CPU中,如果数据、代码、栈的空间需求大于了64kb的话,这三者就不能存放在同一个段中,需要分开来存放。那么应该如何定义多个段呢?
     我们使用定义代码段一样的方法来定义多个段,在这些段里面定义需要的数据,或通过定义数据来取得栈空间。现在我们还是考虑同样的一个问题,将栈中的数据逆序存储到一个寄存器中,代码入下所示:
技术分享
 1 assume cs:code,ds:data,ss:stack
 2  
 3 data segment
 4      dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
 5 data ends
 6  
 7 stack segment
 8       dw 0,0,0,0,0,0,0,0
 9 stack ends
10  
11 code segment
12      start:mov ax,stack
13              mov ss,ax
14              mov sp,16 ;设置ss指向stack,设置ss:sp指向stack:16,cpu执行完这些指令后,就将stack段当做一个栈空间来使用。
15              mov ax,data
16              mov ds,ax ;想要ds:bx访问数据段,ds就要指向ax
17              mov bx,0
18              mov cx,8
19         s:  push [bx]
20              add bx,2
21              loop s
22  
23              mov bx,0
24              mov cx,8
25       s0:   pop [bx]
26               add bx,2
27               loop s0
28 code ends
29 end start
View Code
     在上面的代码中,我们定义了数据段data,栈段stack,代码段code,分别用ds,ss,cs指向这些段。这样做,看上去整个程序非常清晰明了。
     CPU如何处理我们定义的段中的内容,是当做指令来执行,当做数据访问,还是当做栈空间来使用,完全是靠程序中具体的汇编指令和汇编指令对CS:IP、SS:SP、DS等寄存器的设置来决定的。

以上是关于小甲鱼零基础汇编语言学习笔记第六章之包含多个段的程序的主要内容,如果未能解决你的问题,请参考以下文章

汇编语言第六章-包含多个段的程序

王爽《汇编语言》第三版 第六章 包含多个段的程序

小甲鱼零基础汇编语言学习笔记第四章之第一个汇编程序

第六章 函数[DDT书本学习 小甲鱼]

第六章 函数[DDT书本学习 小甲鱼]

第六章 包含多个段的程序