8086汇编-30包含多个段的程序02

#pragma once
/*    30-包含多个段的程序02  在代码段中使用栈
    完成下面的程序,利用栈,将程序中定义的数据逆序存放。
        

assume cs:codesg
        codesg segment
            dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

            ?
            code ends

    程序思路
        程序的思路大致如下.程序运行时,定义的数据存放在cs:0~cs:15单元中,共8个字单元。依次将这8个字单元中的数据入栈,然后再依次出找到这8个字单元中,从而实现数据的逆序存放。
    
    问题是,我们首先要有一段可当作栈的内存空间。如前所述,这段空间应该由系统来分配。

    我们可以在程序中通过定义数据来取得一段空间,然后将这段空间当作栈空间来用。        

assume cs:codesg

        codesg segment
                dw 0123H, 0456H,0789H, 0abcH, 0defH, 0fedH, 0cbaH, 0987H
                dw 0,0,0,0,0,0,0,0            ;用dw定义8个字型数据,在程序加载后,将取得8个字的
                                            ;内存空间,存放这8个数据。我们在后面的程序中将这段
                                            ;空间当作栈来使用。            就是声明一段空间,然后我们把这段控件自己当作一个段来使用.
         start: mov ax,cs
                mov ss,ax
                mov sp, 32        ;设置栈顶ss:sp指向cs:32  ,因为栈最大是31的地方,也就是栈底,栈在没有数据的时候,栈底偏移就是栈底+1
                mov bx,0
                mov cx,8
             s: push cs: [bx]        ; 一波入栈操作
                add bx,2
                loop s        ;以上将代码段0~16单元中的8个字型数据依次入栈


                mov bx,0
                mov cx,8
            s0: pop cs: [bx]        ; 一波出栈操作
                add bx,2
                loop s0        ;以上依次出栈8个字型数据到代码段0~16单元中:
                mov ax,4c00h
                int 21h
        codesg ends
        end start            ;指明程序的入口在start处

    如果对这点还有疑惑,建议回头认真复习.

    比如对于:
        dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H我们可以说,定义了8个字型数据。
        
        也可以说,开辟了8个字的内存空间,这段空间中每个字单元中的数据依次是 : 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H。因为它们最终的效果是一样的。。  检测点
    (1) 下面的程序实现依次用内存0:0~0:15单元中的内容改写程序中的数据,完成程序:
      

 assume cs: codesg

        codesg segment 

                dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
         start: mov ax, 0 
                mov ds, ax 
                mov bx, 0

                mov cx, 8 
             s: mov ax, [bx]

                _______                mov cs:[bx],ax

                add bx, 2 
                loop s

                mov ax, 4c00h 
                int 21h

        codesg ends

        end start        

    (2) 下面的程序实现依次用内存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, ___                    36        这里也可以写成 24H

                mov ax, 0 
                mov ds, ax 
                mov bx, 0 
                mov cx, 8
              s:push [bx]

                _______                       pop cs:[bx]
                add bx, 2 
                loop s

                mov ax, 4c00h
                int 21h

        codesg ends

        end start

  将数据、代码、栈放入不同的段
    在前面的内容中,我们在程序中用到了数据和栈,我们将数据、栈和代码都放到了一个段里面。我们在编程的时候要注意何处是数据,何处是栈,何处是代码。

    这样做显然有两个问题:
        (1)把它们放到一个段中使程序显得混乱

        (2)前面程序中处理的数据很少,用到的栈空间也小,加上没有多长的代码,放到一个段里面没有问题。..

    但如果数据、栈和代码需要的空间超过64KB,就不能放在一个段中(一个段的容量不能大于64KB,是我们在学习中所用的8086模式的限制,并不是所有的处理器都这样)


    怎样做呢?

    我们用和定义代码段一样的方法来定义多个段,然后在这些段里面定义需要的数据,或通过定义数据来取得栈空间。

    具体做法如下面程序所示,这个程序实现了和上一个程序一样的功能,不同之处在于它将数据、栈和代码放到了不同的段中。          

 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,16            ; 初始化栈底
                    mov ax,data
                    mov ds,ax            ; 设置数据段地址
                    mov bx,0            ;  初始化数据段偏移地址
                    mov cx,8            ;  loop 几次
                 s: push [bx]            ; 将数据段的内容一次 push 到栈段中
                    add bx,2
                    loop s


                    mov bx,0
                    mov cx,8
                s0: pop [bx]            ; 将栈段中的数据一次pop 到 数据段对应的地址中
                    add bx,2
                    loop s0

                    mov ax,4c00h
                    int 21h
            codesg ends
            end start            ;指明程序的入口在start处


    程序中"data"段中的数据"0abch”的地址就是data:6。
        我们要将它送入bx中,就要用如下的代码:
            mov ax,data
            mov ds,ax
            mov bx,ds:[6]
        我们不能用下面的指令:
            mov ds,data                这里是错误的段寄存器不能直接用数据赋值,需要通用寄存器进行转存.
            mov ax,ds:[6]


    其中指令"mov ds,data”是错误的,因为8086CPU不允许将一个数值直接送入段寄存器中。
    
    程序中对段名的引用,如指令“mov ds,data"中的"data"将被编译器处理为一个表示段地址的数值.

    (3)“代码段”、“数据段”、“栈段”完全是我们的安排。

    
    我们在源程序中为这三个段起了具有含义的名称,用来存放数据的段我们将其命名为"data”,用来放代码的段我们将其命名为“code”,用来作栈空间的命名为"stack”。

        但CPU看的懂这些名称吗?
            Absolutely not ! ! CPU 看不懂!

    二、我们在源程序中用伪指令“assume cs:code,ds:data,ss:stack"将cs ds和ss分别和code、data、stack段相连。

        这样做了之后,CPU是否就会将cs指向code ,ds 指向 data ss指向stack ,从而按照我们的意图来处理这些段呢?,
            Absolutely not ! ! CPU 看不懂!    因为 assume 是伪指令,CPU 是看不懂的, 这是给编译器看的.


    三、若要CPU按照我们的安排行事,就要用机器指令控制它,源程序中的汇编指令是CPU要执行的内容


    那么,CPU如何知道去执行它们?
    
    我们在源程序的最后用“end start"说明了程序的入口,这个入口将被写入可执行文件的描述信息,可执行文件中的程序被加载入内存后CPU的CS:IP被设置指向这个入口,从而开始执行程序中的第一条指令。

    标号"start"在"code"段中,这样CPU就将code段中的内容当作指令来执行了。

    我们在code段中,使用指令:
        start: mov ax,stack        
        mov ss,ax            
        mov sp,16            

    设置ss指向stack ,设置ss:sp指向stack:16,CPU 执行这些指令后,将把stack段当做栈空间来用。  stack 其实被编译器翻译后,就是一个地址.    总之,CPU到底如何处理我们定义的段中的内容,是当作指令执行,当作数据访问,还是当作找空间,完全是靠程序中具体的汇编指令,和汇编指令对CS:IP、SS:SP、DS等寄存器的设置来决定的。,
    
    我们完全可以将上一个程序写成这样,实现同样的功能。上一个程序源码.
          

  assume cs:b,ds:a,ss:c        ;连续 假设 几个段标号的类型

            a segment                ; 定义为数据段
                    dw 0123H, 0456H,0789H, 0abcH, 0defH, 0fedH, 0cbaH, 0987H
            a ends

            c segment                ; 定义为栈段
                    dw 0,0,0,0,0,0,0,0    
            c ends
                        ; 每个类型段的标号 都指向这个段的首地址.
            b segment                ; 定义为代码段

             start: mov ax,c        
                    mov ss,ax            ; 设置栈段地址
                    mov sp,16            ; 初始化栈底
                    mov ax,a            
                    mov ds,ax            ; 设置数据段地址
                    mov bx,0            ;  初始化数据段偏移地址
                    mov cx,8            ;  loop 几次
                 s: push [bx]            ; 将数据段的内容一次 push 到栈段中
                    add bx,2 
                    loop s        


                    mov bx,0 
                    mov cx,8 
                s0: pop [bx]            ; 将栈段中的数据一次pop 到 数据段对应的地址中
                    add bx,2 
                    loop s0        

                    mov ax,4c00h 
                    int 21h
            codesg b 
            end start            ;指明程序的入口在start处


*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值