[025][汇编语言]实验5 编写、调试具有多个段的程序

程序6.4 : 实现数据的逆序存放

data segment
    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
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
  • 段名code data stack 代表了段地址
  • startcode段 内,这样CPU就将code段中的内容当做指令来执行

实验5

问题(1)

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,0,0
stack ends

code segment
    start:  mov ax,stack
            mov ss,ax
            mov sp,16
            
            mov ax,data
            mov ds,ax
            
            push ds:[0]
            push ds:[2]
            pop ds:[2]
            pop ds:[0]
            
            mov ax,4c00H
            int 21H
code ends
end start
DS SS CS
段地址X , stack段的段地址为 X-2 , data段的段地址为 X-3

问题(2)

assume cs:code,ds:data,ss:stack

data segment
    dw 0123H,0456H
data ends

stack segment
    dw 1111H,1111H
stack ends

code segment
    
    start:  mov ax,stack
            mov ss,ax
            mov sp,16
            
            mov ax,data
            mov ds,ax
            
            push ds:[0]
            push ds:[2]
            
            pop ds:[2]
            pop ds:[0]
            
            mov ax,4c00H
            int 21H
code ends
end start
  • 书上的源码用0000,0000 填充初始的栈空间,我认为这样不方便理解题目,于是修改成了2个字型数据 1111H,1111H
DS SS CS
  • ④ 如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为 ________? 答: (N/16+1)x16,意思就是填满16的倍数(在DEBUG里面截图看上去就是整行、整行的),比如,本题中data段的数据占用了4个内存单元(即4个字节),也仍旧需要往后填零,补齐剩余12个内存单元
(N/16+1)X16
  • 题目(1)与(2)代码区别在于,data段以及stack段数据所占字节不同,目的是为我们展示这种背后隐藏的“整行补齐”效果

问题(3)

assume cs:code,ds:data,ss:stack

code segment
    start:  mov ax,stack
            mov ss,ax
            mov sp,16
            
            mov ax,data
            mov ds,ax
            
            push ds:[0]
            push ds:[2]
            
            pop ds:[2]
            pop ds:[0]
            
            mov ax,4C00H
            int 21H
    code ends
    
    data segment
        dw 0123H,0456H
    data ends
    
    stack segment
        dw 1111H,1111H
    stack ends
    
    end start
SS DS CS
data段补齐一行了, stack段并没有补齐的样子
  • 问题(3)与前两题源代码不同之处在于,data段以及stack段的代码是放在 code段 代码之后的;

问题(4)

  • 问题(3) 的代码可以正确执行。如果去掉入口start,编译器就会从上往下顺序地执行。

问题(5):将a段和b段中的数据依次相加, 将结果存到c段中

assume cs:code
a segment
    db 1,2,3,4,5,6,7,8
a ends

b segment
    db 1,2,3,4,5,6,7,8
b ends

c segment
    db 0,0,0,0,0,0,0,0
c ends

code segment

    start:
        mov ax,a
        mov es,ax
    
        mov ax,c
        mov ds,ax
        
        mov bx,0
        mov cx,4
    
    s1: mov ax,es:[bx]
        add [bx],ax
        add bx,2
        loop s1
        
        mov ax,b
        mov es,ax
        
        mov ax,c
        mov ds,ax
            
        mov bx,0
        mov cx,4
    
    s2: mov ax,es:[bx]
        add [bx],ax
        add bx,2
        loop s2
    
        
            
        mov ax,4C00H
        int 21H
    
    code ends
    end start
mov cx 4.png
  • 遇到loop指令,按下debug 【P命令】全部执行
  • 问题(5)使用db关键词定义的是字节型数据,是8位的, 只占用1个内存单元
  • db 1,2,3,4,5,6,7,8 本质上其实是,db 01,02,03,04,05,06,07,088个数据 就占用 8个内存单元
  • loop 循环中使用 add bx,2,其实是在用字型(16位)进行传输,或者说叫做,看做一个字为单元进行传输
  • 可以这样做是因为,刚好低位内存会送到低位寄存器,高位内存地址会送到高位寄存器
  • 这样的话每个loop的循环次数 其实只需要4次(8个数据相加,4=8÷2),代码要写 mov cx,4

add bx,2 到底发生了什么?

  • 我对题目的源代码进行了3处修改来观察真正的循环次数
db 1,2,3,4,5,6,7,8,9,9,9,9,9,9,9,9

mov cx,8
mov cx,8

  • 可以看到,如果循环次数设置为8,本质上是访问了16个内存单元,不光前8个数据被运算,后面的8个数据也被运算了
  • 试想一下,因为代码里是先写a段再b段,所以在内存里其实是a段数据+(可能的补齐整行)+b段数据+(可能的补齐整行),使用es:[bx]去遍历,如果是add bx,2,那么也是依次走两个内存单元,这里的关键在于是依次走,如果恰好没有补齐整行的零怎么办?这里是有空余的零的, 所以结果暂时感觉没有错,但是循环次数就是循环次数,要求加8个数据就是8个数据运算,不能连后面的数据也一起操作了
mov cx 8 结合 add bx 2 本质 遍历了16个内存单元.png

如果要用技巧,那就要用对!

mov ax,es:[bx]
add [bx],ax
add bx,2
  • es:[bx] 计算出来一个物理地址
  • mov ax,es:[bx],将上面这个物理地址起始的2个内存单元(看做一个字)写入ax(低地址送入低位寄存器,高地址送入高位寄存器)
  • 虽然使用db定义的时候,是按照01 然后 02 接着03、04、05、06、07、08,这样独立的8个数据,但是在传输的时候可以看做是4个字型数据0201、0403、0605、0807送入寄存器,循环次数就相对减半了
以字为单元打包进行传输而已

冷静一下

  • 因为《汇编语言》这本书在说的是8086 CPU,而8086CPU的寄存器就是存16位的数据,在之前的实验和习题里,基本上自己脑子的思路都是默认用字传输数据,问题(5)突然用db关键词这么一晃,反倒让我有点懵

问题(6) :用push指令将a段中的前8个字型数据,逆序存储到b段中

assume cs:code

a segment
    dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0cH,0Eh,0fH,0ffH
a ends

b segment
    dw 0,0,0,0,0,0,0,0
b ends

code segment
    start:  mov ax,a    
            mov ds,ax
    
            mov ax,b
            mov ss,ax
            mov sp,10h
        
            mov bx,0
            mov cx,8
    s:  push [bx]
        add bx,2
        loop s
            
        mov ax,4c00H
        int 21H
    
    code ends
    end start
逆序存储结果
  • 问题(6)定义的是字型数据,要逆序移动的也是字型数据,所谓字型,是16位的,是占2个内存单元的,是使用dw关键词的,要与问题(5)使用db关键词定义字节数据区分开
  • 问题(6),dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0cH,0Eh,0fH,0ffH,本质上其实就是dw 0001,0002,0003,0004,0005,0006,0007,0008,0009,000ah,000bh,000cH,000Eh,000fH,00ffH
  • 因此,不难理解最后运行截图里,是08 00 07 00 这样的数据,00就来自于字型的补零

inc bx 与 add bx,2 的区别

  • 可复习 https://www.jianshu.com/p/c47c4d86d425
  • inc bx 等于 add bx,1
  • [bx] 本质上是DS:[bx] 计算得到一个物理地址
  • add ax,bx ,是字型的加法,也就是2个内存单元,高位+高位,低位+低位的运算
  • 数据传输的时候,要看清楚是以字为单元还是以字节单元,1个字型等于2个字节
  • mov al,[bx] 传输字节,搭配inc bx
  • mov ax,[bx]传输字,搭配 add bx,2

你可能感兴趣的:([025][汇编语言]实验5 编写、调试具有多个段的程序)