一文读懂汇编程序的多个分段的程序--详解

先贴上程序
首先要知道cpu是不知道到底哪里的数据是代码 那里是数据那里是堆栈因此实现这些要靠程序员来告诉CPU
当然还有小小的汇编程序:汇编中的嵌套循环

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, 20h

        mov ax,data
        mov ds,ax

        mov bx, 0
        mov cx,8
    s:  push [bx]
        add bx, 2
        loop s

        mov bx, 0
        mov cx,8
    s0: pop [bx]
        add bx,2
        loop s0

        mov ax, 4c00H
        int 21H
code ends
end start  ;end指定 start是代码段的开始
;程序的开始是由end指定的,end后面跟的什么程序的入口就会在那里

下面是程序的分段详解

开头
assume cs:code,ds:data,ss:stack
假设程序分别有  代码段  数据段  堆栈段
assume 假设  
声明一个数据段
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   ;程序的 ip指针会指向 start初
                        ;因为8086cpu不允许将数据直接送入段寄存器中因此使用通用寄存器进行
        mov ss, ax      ;也就是相当于将stack中的数据送入到ss中
        mov sp, 20h     ;因为数据和堆栈占用了32个字节的大小一次sp堆栈的指针指向32处

        mov ax,data    ;通过寄存器ax将数据段的地址赋值给ds即段寄存器
        mov ds,ax

        mov bx, 0
        mov cx,8   ;在循环的时候cx就是循环的计数器  每次循环就会将cx的数值进行减一直到为零为止
    s:  push [bx]     ;该语句说的是将ds中的数据进栈也就相当于使用push ds:[bx]  (说明push 是对堆栈的操作也就是push和pop会对堆栈进行操作)具体见文下注释;实现的过程就是将数据段中的数据压入堆栈 ,也就是对ss:sp指向的数据进行操作
        add bx, 2
        loop s  //跳到s处进行循环

        mov bx, 0
        mov cx,8
    s0: pop [bx]
        add bx,2
        loop s0

        mov ax, 4c00H      ;加上下一句实现程序的返回
        int 21H
code ends    ;代码段结束
end start   //整段程序结束

注释:push-pop

 堆栈操作指令 PUSHPOP

 格式: PUSH OPRD
 ----  POP  OPRD

 功能: 实现压入操作的指令是PUSH指令;实现弹出操作的指令是POP指令.
 ----
说明: 1. OPRD为16位(字)操作数,可以是寄存器或存储器操作数.
 ----
       2. PUSH的操作过程是: (SP)<--(SP)-2,((SP))<--OPRD 即先修改堆栈指针SP(压入时为自动减2),然后,将指定的操作数送入新的栈顶位置.
          此处的((SP))<--OPRD,也可以理解为:
          [(SS)*16+(SP)]<--OPRD 或 [SS:SP]<--OPRD

       3. 示例: PUSH DX
                PUSH BP
                PUSH CS
                PUSH DATA1
                PUSH ALFA[BX][SI]
          注意: 每进行一次压入操作,都压入一个字(16位).

       4. PUSHPOP指令对状态标志位没有影响。

       5. 什么是堆栈
          堆栈被定义为一种先进后出的数据结构,即最后进栈的元素将被最先弹出来.这很像许多人进入一条窄得只能容纳一个人通过的小道,如果要从这条道往回退出           来的话,那么最先退出来的人是最后一个进入小道的人.

知识小百科:

 数据传送指令 MOV

 格式: MOV OPRD1,OPRD2
 ----

 功能: 本指令将一个源操作数送到目的操作数中,即OPRD1<--OPRD2.
 ----
 说明: 1. OPRD1 为目的操作数,可以是寄存器、存储器、累加器.
 ----     OPRD2 为源操作数,可以是寄存器、存储器、累加器和立即数.

       2. MOV 指令以分为以下四种情况:
          <1> 寄存器与寄存器之间的数据传送指令
              示例: MOV AX,BX
                    MOV DS,AX
                    MOV BP,SI

              注意: 代码段寄存器CS及指令指针IP不参加数的传送,其中CS可以作为
                    源操作数参加传送,但不能作为目的操作数参加传送.

          <2> 立即数到通用寄存器数据传送指令
              立即数只能作源操作数使用,不能作目的操作数.
              示例: MOV AL,25
                    MOV SI,OFFSET DATA1

              注意: 由于传送的数据可能是字节,也可能是字,源操作数与目的操作
                    数的类型应一致。

          <3> 寄存器与存储器之间的数据传送指令
              示例: MOV AL,BUFFER
                    MOV AX,[SI]
                    MOV LAST[BX+DI],DL
                    MOV SI,ES:[BP]

          <4> 立即数到存储器的数据传送
              示例: MOV ALFA,24
                    MOV DS:MEMS[BP],300AH
                    MOV BYTE PTR[SI],15
                    MOV LAST[BX][DX],0FFH

       3. 本指令不影响状态标志位.

       4. MOV指令执行时的数据传送方向.
          <1> 立即数只能作为源操作数,不允许作目的操作数,立即数也不通送至段寄存                器.
          <2> 通用寄存器可以与段寄存器,存储器互相传送数据,寄存器之间也可以互相                传送.但CS段不能作为目的操作数.
          <3> 值得再次强调的是存储器与存储器之间不能进行数据直接传送.若要实现                 存储单元间的数据传送,可以借助于通用寄存器作为中介来进行.
 加法指令 ADD(Addition)

 格式: ADD OPRD1,OPRD2
 ----

 功能: 两数相加
 ----
  说明: 1. OPRD1为任一通用寄存器或存储器操作数,可以是任意一个通用寄存器,而且还可  ----     以是任意一个存储器操作数.这给程序的编写带来了很大的方便. 
          OPRD2为立即数,也可以是任意一个通用寄存器操作数.立即数只能用于源操作数

       2. OPRD1和OPRD2均为寄存器是允许的,一个为寄存器而另一个为存储器也是允许的           ,但不允许两个都是存储器操作数.理由是指令代码的寻址方式中规定了两个操            作数(除立即数)至少有一个是寄存器操作数.

       3. 加法指令运算的结果对CF、SF、OF、PF、ZF、AF都会有影响.以上标志也称为结           果标志.加法指令适用于无符号数或有符号数的加法运算.操作数可以是8位,也            可以是16位.

       4. 示例: ADD AL,25         ;(AL)<--(AL)+25 
                ADD BX,0A0AH      ;(BX)<--(BX)+0A0AH 
                ADD DX,DATA1[BX] 
                ADD DI,CX         ;(DI)<--(DI)+(CX)
                ADD BETA[BX],AX 
                ADD BYTE PTR[BX],28 

          注意: 上述第一条指令及第六条指令为字节相加指令,其它四条均为字(双字节)                 相加指令.
                未加注解的三条指,都与存储器操作数有关.第三条指指令中,存储器操作                 数是源操作数,采用变址寻址方式;第五条指令中,存储器操作数是目的操                 作数,采用变址寻址方式;第六条指令中存储器操作数也是目的操作数,采                 用寄存器间接寻址方式,当立即数与存储器操作数做加法时, 类型必须一                 致,故此处用BYTE PTR[BX],将存储器操作数的类型重新指定为字节类型,                 以保证两个操作数类型一致.
 数据传送指令 MOV

 格式: MOV OPRD1,OPRD2
 ----

 功能: 本指令将一个源操作数送到目的操作数中,即OPRD1<--OPRD2.
 ----
 说明: 1. OPRD1 为目的操作数,可以是寄存器、存储器、累加器.
 ----     OPRD2 为源操作数,可以是寄存器、存储器、累加器和立即数.

       2. MOV 指令以分为以下四种情况:
          <1> 寄存器与寄存器之间的数据传送指令
              示例: MOV AX,BX
                    MOV DS,AX
                    MOV BP,SI

              注意: 代码段寄存器CS及指令指针IP不参加数的传送,其中CS可以作为
                    源操作数参加传送,但不能作为目的操作数参加传送.

          <2> 立即数到通用寄存器数据传送指令
              立即数只能作源操作数使用,不能作目的操作数.
              示例: MOV AL,25
                    MOV SI,OFFSET DATA1

              注意: 由于传送的数据可能是字节,也可能是字,源操作数与目的操作
                    数的类型应一致。

          <3> 寄存器与存储器之间的数据传送指令
              示例: MOV AL,BUFFER
                    MOV AX,[SI]
                    MOV LAST[BX+DI],DL
                    MOV SI,ES:[BP]

          <4> 立即数到存储器的数据传送
              示例: MOV ALFA,24
                    MOV DS:MEMS[BP],300AH
                    MOV BYTE PTR[SI],15
                    MOV LAST[BX][DX],0FFH

       3. 本指令不影响状态标志位.

       4. MOV指令执行时的数据传送方向.
          <1> 立即数只能作为源操作数,不允许作目的操作数,立即数也不通送至段寄存                器.
          <2> 通用寄存器可以与段寄存器,存储器互相传送数据,寄存器之间也可以互相                传送.但CS段不能作为目的操作数.
          <3> 值得再次强调的是存储器与存储器之间不能进行数据直接传送.若要实现                 存储单元间的数据传送,可以借助于通用寄存器作为中介来进行.
段定义伪操作 SEGMENT和ENDS

 格式: <段名>SEGMENT[<定位类型>],[<组合类型>],[<'类别名'>] 
 ----   …:段体 
     <段名>ENDS 

 功能: SEGMENT和ENDS伪操作命令可用来把程序分成若干逻辑段,这些逻辑段按用途不同   ----  ,通常包括代码段、数据段、堆栈和附加段,它分别装入由CS、DS、SS和ES寄存器        所指定的物理段中。
 说明: 1. 定位类型 
 ----   定位类型表示某段装入内存时,对段的起始边界有何要求,有以下四种选择: 
        BYTE:表示本段起始单元可以从任一地址开始,段间不留空隙,存储器利用率最                高。 
        WORD:表示本段起始单元从一个偶字节地址开始,即段起始地址的最后一位二进                制数一定是0,如02152H、0A156H等。这种定位方式适合于数据项的类型                 为字的数据段。
        PARA:这是隐含选择,表示本段起始地址从一个字节的边界开始。一个节为16个                字节,所以段的起始地址一定能被16整除,亦即是以0H结尾的地址,如                  024D0H、07A20H等。 
        PAGE:表示本段起始地址从一个页的边界开始。一页为256个字节,所以段的起                 始地址一定能被256整除,以即是以00H结尾的地址,如02400H、07A00H等

     2. 组合类型(Combine Type)
        NONE:这是隐含选择,表示本段与其他段无组合关系,每段都有自己的段基址
        PUBLIC:表示在满足定位类型的前提下与其他模块的同名段邻接在一起,形成                    一个新的逻辑段,公用一个段基址,所有偏移量调整为相对于新逻辑                    段的起始地址。
        COMMON:表示产生一个覆盖段。也就是说,当一两个段连接时,把本段与其他                    也用COMMON说明的同名段置成相同的起始地址,共享相同的存储区。                    共享存储区的长度由其中最大的段确定。
        STACK:表示把所有同名段连接成一个连续段,自动初始化SS和SP,使SS 的内                   容为该连续段的首地址,SP指向堆栈底部+1的存储单元。
        MEMORY:表示本段在存储器中应定位在所有其他段的最高地址。

     3. 类别名(Class) 类别名可以是任何合法的名字,必须用单引号括起来。 
 模块定义伪操作 NAME和END

 格式: [NAME<模块名>]
 ----     ...
       END[标号]

 功能: 定义一个模块
  说明: 模块命名伪操作命令NAME可以省略。这时,该模块的命名规则是:如果模块中使   ----   用了TITLE语句(列表输出的页标题命令),则TITLE语句中页标题的前六个字符          就是模块名;如果模块中没有使用TITLE语句,则该模块的源程序文件名就是模块         名。
 加法指令 ADD(Addition)

 格式: ADD OPRD1,OPRD2
 ----

 功能: 两数相加
 ----
 说明: 1. OPRD1为任一通用寄存器或存储器操作数,可以是任意一个通用寄存器,而且还可  ----     以是任意一个存储器操作数.这给程序的编写带来了很大的方便. 
          OPRD2为立即数,也可以是任意一个通用寄存器操作数.立即数只能用于源操作数

       2. OPRD1和OPRD2均为寄存器是允许的,一个为寄存器而另一个为存储器也是允许的           ,但不允许两个都是存储器操作数.理由是指令代码的寻址方式中规定了两个操            作数(除立即数)至少有一个是寄存器操作数.

       3. 加法指令运算的结果对CF、SF、OF、PF、ZF、AF都会有影响.以上标志也称为结           果标志.加法指令适用于无符号数或有符号数的加法运算.操作数可以是8位,也            可以是16位.

       4. 示例: ADD AL,25         ;(AL)<--(AL)+25 
                ADD BX,0A0AH      ;(BX)<--(BX)+0A0AH 
                ADD DX,DATA1[BX] 
                ADD DI,CX         ;(DI)<--(DI)+(CX)
                ADD BETA[BX],AX 
                ADD BYTE PTR[BX],28 

          注意: 上述第一条指令及第六条指令为字节相加指令,其它四条均为字(双字节)                 相加指令.
                未加注解的三条指,都与存储器操作数有关.第三条指指令中,存储器操作                 数是源操作数,采用变址寻址方式;第五条指令中,存储器操作数是目的操                 作数,采用变址寻址方式;第六条指令中存储器操作数也是目的操作数,采                 用寄存器间接寻址方式,当立即数与存储器操作数做加法时, 类型必须一                 致,故此处用BYTE PTR[BX],将存储器操作数的类型重新指定为字节类型,                 以保证两个操作数类型一致.

猜你喜欢

转载自blog.csdn.net/andrewgithub/article/details/78929586