抄书笔记-汇编语言 第五章[BX]和loop指令

1.[bx]和内存单元的描述

mov ax,[0] 将一个内存单元的内容送入到ax中,内存单元的大小是2字节(字单元),存放一个字,偏移地址为0,段地址存放在ds中

mov al,[0] 功能同上,只是内存单元的大小是1字节

所以,要完整的描述一个内存单元,需要两种信息:

  1. 内存单元的地址
  2. 内存单元的长度(类型)

所以,使用[bx],表示偏移地址是存放在BX里面的

mov ax,[bx] 表示将一个内存单元的内容送入到ax,这个内存单元的大小是2字节(字单元),存放一个字,偏移地址在bx中,段地址在ds中。

mov al,[bx] 功能同上,只是内存单元的大小是一个字节

2.loop

循环指令

3.我们定义的描述行符号“()”

用符号“()”来表示一个寄存器或者是一个内存单元中的内容。

4.约定idata表示常量

比如:

mov ax,[idata] 表示:mov ax,[1] mov ax [2]

mov ax,idata 表示:mov ax,1 mov ax,2

mov ds,idata 表示:mov ds,1 mov ds,2 非法的

5.1[BX]

指令的功能:

mov ax,[bx]

功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将SA:EA处的数据送入到ax中,即:(ax)=((ds)*16+(bx));

mov [bx],ax

功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将ax中的数据送入内存SA:EA处,即:((ds)*16+(bx))=(ax)

inc bx

功能:bx中的内容加1

5.2Loop指令

CPU在执行loop指令的时候要进行两个操作:

  1. (cx)=(cx)-1
  2. 判断cx中的值,不为零则跳转至标号处执行程序,如果为零了则向下执行。

任务1:编程计算22,结果放在ax中

assume cs:code
code segment
    mov ax,2
    add ax,ax
    
    mov ax,4c00h
    int 21h

任务2:编程计算23,结果放在ax中

assume cs:code
code segment
    mov ax,2
    add ax,ax
    add ax,ax
    
    mov ax,4c00h
    int 21h

现在使用loop循环来实现

assume cs:code
code segment
    mov ax,2
    mov cx,11
s:add ax,ax
loop s

mov ax,4c00h
int 21h

结论:

  1. 在cx中存放循环的次数;
  2. loop指令中的标号所标识地址要在前面;
  3. 要循环执行的程序段,要写在标号和loop指令之间。

loop指令的基本框架

mov cx,循环的次数
s:
    循环执行的程序段
    loop s

编程实现123*236

assume cs:code
code segment
    mov ax,0
    mov cx,236
s:add ax,123
    loop s
    mov ax,4c00h
    int 21h

改进:

assume cs:code
code segment
    mov ax,0
    mov cx,123
s:add ax,236
    loop s
    mov ax,4c00h
    int 21h

这样就只是循环123次

5.3在debug中使用loop指令

在汇编源程序中不能以数字开头,所以要在前面加0

5.4debug和汇编编译器masm对指令的不同处理

在汇编源程序中,如果要访问一个内存单元,则在指令必须使用[],如果是内存单元,[]里面表示偏移地址,需要指明段寄存器。

5.5loop和[bx]的联合使用

需求:计算ffff:0~ffff:b单元中的数据的和,结果保存在dx中

问题:12内存单元的数据相加会不会超过dx的最大限制,一个字节的数据怎们保存到16寄存器中。

答案:第一个不会超过,第二个使用一个中专

assume cs:code
code segment
    mov ax,ffffh
    mov ds,ax
    
    mov dx,0
    
    mov al,ds:[0]
    mov ah,0
    add dx,ax
    
    mov al,ds:[1]
    mov ah,0
    add dx,ax
    .....重复12次
    
    mov ax,4c00h
    int 21h
    
code ends
end

上面的代码在于出现大量的重复,其实就只有一个变量的不同,可以优化:

assume cs:code
code segment
    mov ax,0ffffh
    mov ds,ax
    mov bx,0
    mov cx,12
s:mov al,[bx]
    mov ah,0
    add dx,ax
    inc bx
    loop s
    
    mov ax,4c00h
code ends
end

5.6段前缀

指令"mov ax,[bx]"中,内存地址的偏移地址由bx给出,而段地址默认是在ds里面,我们也可以在访问内存单元的时候显式地给出内存单元的段地址所在的段寄存器。

(1)mov ax,ds:[bx]

将一个内存单元的内容送入到ax,这个内存单元的长度是2个字节,存放一个字,偏移地址在bx中,段地址在ds中。

(2)mov ax,cs:[bx]

将一个内存单元的内容送入到ax中,这个内存单元的长度是2个字节,存放一个字,偏移地址在bx中,段地址在cs中。

用于显式地指明内存单元的段地址的ds,cs,ss,es 在汇编语言中称为段前缀。

5.7一段安全的空间

  1. 我们需要向一段内存中写入数据;
  2. 这段内存中不应该存放系统或者是其他的数据或者是代码,否则写入操作可能引发错误;
  3. dos方式下,一般情况;0:200~0:2ff空间中没有系统或者其他程序的数据或者代码;
  4. 以后往内存写东西,就在上面的地址空间里写

5.8段前缀的使用

需求:将内存ffff:0~ffff:b单元的数据复制到0:200~0:20b中。

分析:注意0:200~0:20b 等同于0020:0~0021:b,这样就可以看到从源ffff:x到目标0020:x,它们有同样的偏移地址x

实现代码:

assume cs:code
code segment:
    mov bx,0
    mov cx,12
s:mov ax,0ffffh
    mov ds,ax
    mov dl,[bx]
    
    mov ax,0020h
    mov ds,ax
    mov [bx],dl
    
    inc bx
    loop s
    
    mov ax,4c00h
    int 21h
code ends
end

但是上面的代码有一个问题,就是需要设置多次的ds,这样做是正确的,但是效率不高,我们使用段前缀来优化一下:

assume cs:code
code segment
    mov ax,0ffffh
    mov ds,ax
    
    mov ax,0020h
    mov es,ax
    
    mov bx,0
    mov cx,12
    
s:mov dl,[bx]
    mov es:[bx],dl
    inc bx
    loop s
    
    mov ax,4c00h
    int 21h
code ends
end

这样就不用重复的设置ds了~

共有 0 条评论

Top