zoukankan      html  css  js  c++  java
  • 小甲鱼零基础汇编语言学习笔记第六章之包含多个段的程序

         在前面的几个章节中,我们的程序都是只有一个代码段,本章我们开始学习如何编写包含多个段的程序。
     
    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等寄存器的设置来决定的。
  • 相关阅读:
    去除金额千分位,还原成数字
    替换对象的key
    合并两个对象的属性
    js常用数组方法
    document对象的一些属性
    js数字四舍五入保留n位小数
    js时间日期类常用方法
    数字转换成千分位格式
    valueOf获取日期时间初始值
    常见的数据库Cause:Packet for query is too large(xxx > 1024)
  • 原文地址:https://www.cnblogs.com/getMyCodes/p/7277423.html
Copyright © 2011-2022 走看看