找回密码
 register

QQ登录

只需一步,快速开始

查看: 30|回复: 1

[汇编语言] [零基础入门学习]·37·更灵活定位内存地址·不同的寻址方式的灵活应用·问题7.8~7.9

[复制链接]

[汇编语言] [零基础入门学习]·37·更灵活定位内存地址·不同的寻址方式的灵活应用·问题7.8~7.9

[复制链接]
  • 打卡等级:热心大叔
  • 打卡总天数:91
  • 打卡月天数:14
  • 打卡总奖励:91
  • 最近打卡:2025-01-15 02:59:34
Waylee

主题

0

回帖

1万

积分

仙帝

积分
11890
Waylee 2025-1-11 20:05 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?register

×


问题 7.8

仔细阅读上面的程序,看看有什么想法?
思考后看分析。

分析
问题在于cx的使用,我们进行二重循环,却只有一个循环计数器,造成在进行内层循环的时候,覆盖了外层循环的循环计数值。多用一个计时器又不可能,因为loop指令默认cx为寄存器。怎么办呢?

我们应该用每次开始内存循环的时候,将外层循环的cx中的数值保存起来,在执行外层循环的loop s指令前,再恢复外层循环的cx的值。可以用存储器dx来临时存放cx中的数值,改进的程序如下。

    mov ax,datasg
    mov ds,ax
    mov bx,0

    mov cx,4

s0: mov dx,cx           ;将外层循环的cx值保存在dx中
    mov si,0
    mov cx,3            ;cx设置为内层循环的次护士

s:  mov ax,[bx+si]
    and al,11011111b
    mov [bx+si],al
    inc si
    loop s

    add bx,16
    mov cx,dx           ;用dx中存放的外层循环的计数器恢复时间cx
    loop s              ;外层循环的loop指令将在cx中的计数值+1

上面的程序用dx来暂时存放cx中的值,如果在内层循环中,dx寄存器也被使用,该怎么办?我们似乎可以使用别的寄存器,但是CPU中的寄存器数量毕竟有限的,如8086CPU只有14个寄存。在上面的程序中,si、cx、ax、bx,显然不能用来暂存cx中的值,因为这些寄存器在循环中也要使用;cs、ip、ds也不能用,因为cs:ip时刻指向当前的指令,ds指向datasg段;可用的就只有:dx、di、es、ss、sp、bp等6个寄存器了,可是如果循环中的程序比较复杂,这些寄存器也能被使用的话,那么该如何?

我们在这里讨论的问题是,程序中经常需要进行数据的暂存,怎样做将更为合理。这些数据可能是寄存器中的,也可能是内存中的。我们可以用寄存器暂时它们,但是这不是一个一般化的解决方案,因为寄存器数量有限,每个程序中可使用的寄存器都不一样。我们希望寻找一个通用的方案,来解决这种在编程中经常会出现的问题。

显然,我们不能选择寄存器,那么可以使用的就是内存。可以考虑将需要暂存的数据放到内存单元,需要使用的时候,再从内存单元中恢复。这样我们就需要开辟一段内存空间。再次改成的程序如下。

assume cs:codesg,ds:datasg
datasg segment
    db 'ibm             '
    db 'dec             '
    db 'dos             '
    db 'vax             '   
    dw 0                    ;定义一个字,用来暂存cx
datasg ends

codesg segment
start:  mov ax,datasg
        mov bx,0
        mov cx,5
s0:     mov ds:[40H],cx     ;将外层循环的cx值保存在datasg:40H单元中
        mov si,0
        mov cx,3            ;cx设置为内层循环的次数
s:      mov al,[bx+si]
        and a1,11011111B
        mov [bx+si],al
        inc si
        loop s
        add bx,16
        mov bx,16
        mov cx,ds:[40H]     ;用datasg:40H单元中的值恢复cx
        loop s0             ;外层循环的loop指令将cx中的计数值减1

        mov ax,4c00h
        int 21h
codesg ends
ent start

上面的程序中,用内存单元来保存数据,可是上面的做法却有些麻烦,因为如果需要保存多个数据的时候,你必须要记住数据放到了哪个单元中,这样程序容易混乱。

我们使用内存来暂存数据,这一点是确定了的,但是值得推敲的是,我们用怎样的结果来保存这些数据,而使我们的程序更加清晰。一般来说,在需要暂存数据的时候,我们都应使用栈。回忆一下,栈空间在内存中,采用相关的命令,如push、pop等,可对其进行特殊的操作。下面,再次改进我们的程序。

assume cs:codesg,ds:datasg,ss:stacksg

datasg segment
    db 'ibm             '
    db 'dec             '
    db 'dos             '
    db 'vax             '   
datasg ends

stacksg segment         ;定义一个段,用来做栈段,容量为16个字节
    dw 0,0,0,0,0,0,0,0
stacksg ends

codesg segment
start:  mov ax,stacksg
        mov ss,ax
        mov sp,16
        mov ax,datasg
        mov ds,ax
        mov bx,0

        mov cx,4

s0:     push cx         ;将外层循环的cx值压栈
        mov si,0
        mov cx,3        ;cx值为内层循环的次数

s:      mov al,[bx+si]
        and al,11011111b
        mov [bx+si],al
        inc si
        loop s

        add bx,16
        pop cx          ;从栈顶弹出原cx的值,恢复cx
        loop s0         ;外层循环的loop指令将cx中的计数值减1

        mov ax,4c00h
        int 21h
codesg ends
end start


问题7.9

编程,将datasg段中每个单词的前4个字母改为大写字母。

assume cs:codesg,ss:stacksg,ds:datasg

stacksg segment
    dw 0,0,0,0,0,0,0,0
stacksg ends

datasg segment
    db '1. display      '
    db '2. brows        '
    db '3. replace      '
    db '4. modify       '
datasg ends

codesg segment
    start:
codesg ends

end start

分析:
datasg中的数据的存储结果,如图7.4所示。

7.4.webp

在datasg中定义了四个字符串,每个长度为16字节(注意,为了使我们在Debug中可以直观地查看,每个字符串的后面都加上了空格符,以使它们的长度刚好为16个字节)。因为它们是连续存放的,我们可以将这4个字符串看成一个4行16列的二位数组,按照要求,我们需要修改每个单词的前4个字母,即二位数组的每一行的3~6列。

我们需要进行4x4次二重循环,用变量R定位行,常量3定位每行要修改的起始列,变量C定位相对于起始列的要修改的列。外层循环按行来进行,内层按列来进行。我们首先用R定位第1行,循环修改R行的3+C(0≤C≤3)列;然后再用R定位到下一行,再次循环修改R行的3+C(0≤C≤3)列……,如此重复直到所有的数据修改完毕。处理的过程大致如下。

    R=第一行的地址;   
    mov cx,4
s0: C=第一个要修改的列相对于起始的地址
    mov cx,4
s:  改变R行,3+C列的字母为大写
    C=下一个要修改的列相对于起始列的地址
    loop s
    R=下一行的地址
    loop s0

我们用bx来作变量,定位每行的起始地址,用si定位要修改的列,用[bx+3+si]的方式来对目标单元进行寻址。

请在实验中自己完成这个程序。

这一章中,我们主要讲解了更灵活的寻址方式的应用和一些编程方法,主要内容有:

  • 寻址方式[bx(或si、di)+idata]、[bx+si(或di)]、[bx+si(或di)+idata]的意义和应用;
  • 二重循环问题的处理;
  • 栈的应用;
  • 大小写转化的方法;
  • and、or指令。

下一章中,我们将对寻址方式的问题进行更深入的探讨。之所以如此重视这个问题,是因为寻址方式的适当应用,使我们可以以更合理的结构来看待所要处理的数据。而为所要处理的看似杂乱的数据设计一种清晰的数据机构是程序设计的一个关键的问题。

实验6 实践课程中的程序

一、将课程中所有讲解过的程序上机调试,用Debug跟踪其执行过程,并在过程中进一步理解所讲内容。
二、编程,完成问题7.9中的程序。

  • 打卡等级:热心大叔
  • 打卡总天数:91
  • 打卡月天数:14
  • 打卡总奖励:91
  • 最近打卡:2025-01-15 02:59:34
楼主
Waylee 楼主

主题

0

回帖

1万

积分

仙帝

积分
11890
Waylee 2025-1-12 14:33 | 显示全部楼层 | Google Chrome | Windows 10

实验6 第二题参考答案

assume cs:codesg,ss:stacksg,ds:datasg

stacksg segment
    dw 0,0,0,0,0,0,0,0
stacksg ends

datasg segment
    db '1. display      '
    db '2. brows        '
    db '3. replace      '
    db '4. modify       '
datasg ends

codesg segment
    start:
            mov ax,stacksg
            mov ss,ax
            mov sp,16

            mov ax,datasg
            mov ds,ax

            mov bx,0            ;定义行

            mov cx,4        
    s0:     push cx
            mov si,0            ;定义列
            mov cx,4

    s:      mov al,[bx+3+si]    ;这里是定位到每个要索引的字母,总共每行有四个字母
            and al,11011111B    ;实现使它变为大写字母
            mov [bx+3+si],al
            inc si
            loop s

            add bx,16
            pop cx
            loop s0

            mov ax,4c00h
            int 21h

codesg ends

end start
您需要登录后才可以回帖 登录 | register

本版积分规则

雪舞知识库 | 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 |天天打卡

GMT+8, 2025-1-15 07:09 , Processed in 0.145503 second(s), 9 queries , Redis On.

Powered by XueWu Licensed

Copyright © Tencent Cloud.

快速回复 返回顶部 返回列表