• [bx]与loop指令


    [bx]与loop指令


    1.[bx]与loop指令概念

    1. [bx] 的含义:[bx]同样表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中
    2. [...]的含义:[]表示内存单元,偏移地址是…

    关于[bx]与[…]的区别:主要就在于[…]是直接给偏移地址,而[bx]偏移地址在bx中

    mov ax,[0] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址为0,段地址在ds中
    mov al,[0] ;将一个内存单元内容送入al,这个内存单元长度为1字节,偏移地址为0,段地址在ds中
    mov ax,[bx] ;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在ds中
    mov al,[bx] ;将一个内存单元内容送入al,这个内存单元长度为1字节,偏移地址在bx中,段地址在ds中
    
    • 1
    • 2
    • 3
    • 4

    loop指令的格式是:loop 标号,CPU执行loop指令的时候,要进行两步操作:

    1. (cx) = (cx) - 1,这里的()是一个描述符,用来表示一个寄存器或一个内存单元中的内容,比如20000H表示20000H单元,(20000H)表示该单元下的内容
    2. ()中的元素可以是:寄存器名、段寄存器名、内存单元的物理地址
    3. 判断 cx 中的值,不为零则转至标号处执行程序,如果为零则向下执行

    例如:计算212

    assume cs:code 
    
    code segment 
    	mov ax, 2
    
    	mov cx, 11 ;循环次数
    s:  add ax, ax ;放置标号s
    	loop s     ;在汇编语言中,标号代表一个地址,标号s实际上标识了一个地址,
                   ;这个地址处有一条指令:add ax,ax。
                   ;执行loop s时,首先要将(cx)减1,然后若(cx)不为0,则向前
                   ;转至s处执行add ax,ax。所以,可以利用cx来控制add ax,ax的执行次数。
    
    	mov ax,4c00h 
    	int 21h 
    code ends 
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.[bx]和loop的联合应用

    例题:计算ffff:0 ~ ffff:b单元中的数据的和,结果存储在dx中

    问题分析:

    1. 运算后的结果是否会超出dx所能存储的范围?

      分析:可以,ffff:0~ffff:b内存单元中的数据是字节型数据,范围在0 ~ 255之间,12个这样的数据相加,结果不会大于65535,可以在dx中存下

    2. 能否将ffff:0~ffff:b中的数据直接累加到dx中?

      分析:不行,因为ffff:0~ffff:b中的数据是8位,不能直接加到16位寄存器dx中

    3. 能否将ffff:0~ffff:b中的数据累加到dl中,并设置(dh)=0,从而实现累加到dx中?

      分析:不行,因为dl是8位寄存器,能容纳的数据范围在0 ~ 255之间,ffff:0~ffff:b中的数据也都是8位,如果仅向dl中累加12个8位数据,很可能造成进位丢失

    4. 我们如何将ffff:0~ffff:b中的8位数据,累加到16位寄存器dx中?

      解决方案:用一个16位寄存器来做中介。将内存单元中的8位数据赋值到一个16位寄存器a中,再将ax中的数据加到dx

    ;解决方案代码
    assume cs:code 
    
    code segment 
    	mov ax,0ffffh 	;在汇编源程序中,数据不能以字母开头,所以要在前面加0
    	mov ds,ax 
    	mov bx,0   		;初始化ds:bx指向ffff:0
    	mov dx,0   		;初始化累加寄存器dx,(dx)= 0
    
    	mov cx,12  		;初始化循环计数寄存器cx,(cx)= 12
    s:  mov al,[bx]
    	mov ah,0
    	add dx,ax  		;间接向dx中加上((ds)* 16 +(bx))单元的数值
    	inc bx      ;ds:bx指向下一个单元
    	loop s 
    
    	mov ax, 4c00h 
    	int 21h 
    code ends 
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.段前缀概念

    mov ax, ds:[bx]  	;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在ds中
    mov ax, cs:[bx]	 	;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在cs中
    mov ax, ss:[bx]		;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在ss中
    mov ax, es:[bx]		;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址在bx中,段地址在es中
    mov ax, ss:[0]		;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址为0,段地址在ss中
    mov ax, cs:[0]		;将一个内存单元内容送入ax,这个内存单元长度为2字节,偏移地址为0,段地址在cs中
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的“ds:”,“cs:”,“ss:”,“es:”,在汇编语言中称为段前缀

    关于安全段空间的扩展:

    1. 在一般PC机中,DOS方式下,DOS和其他合法程序一般都不会使用0:200~0:2ff(00200H ~ 002ffH)的256个字节的空间,所以我们使用这段空间是安全的
    2. 为了谨慎起见,进入DOS后,先用debug查看一下,如果0:200~0:2ff单元的内容都是0,则证明DOS和其他合法程序没有使用这里

    段前缀的使用:将内存ffff:0 ~ ffff:b单元中的数据复制到0:200 ~ 0:20b单元中

    assume cs:code 
    
    code segment 
    	mov ax, 0ffffh 
    	mov ds, ax   	 ;(ds)= 0ffffh 
    	mov ax, 0020h
     mov es, ax   		 ;(es)= 0020h     0:200 等效于 0020:0
     mov bx, 0    		 ;(bx)= 0,此时ds:bx指向ffff:0,es:bx指向0020:0
    
    	mov cx,12   	;(cx)=12,循环12次
    s:  mov dl,[bx] 	;(d1)=((ds)* 16+(bx)),将ffff:bx中的字节数据送入dl 
    	mov es:[bx],dl 	;((es)*16+(bx))=(d1),将dl中的数据送入0020:bx 
    	inc bx  		 ;(bx)=(bx)+1
    	loop s 
    
    	mov ax,4c00h 
    	int 21h 
    code ends 
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4.包含多个段的程序案例

    包含多个段的程序使用案例:

    程序中对段名的引用,将被编译器处理为一个表示段地址的数值,如下

    mov ax, data 
    
    mov ds, ax 
    
    mov bx, ds:[6]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在代码段中使用数据,如下:

    ;计算 8 个数据的和存到 ax 寄存器
    assume cs:code 
    
    code segment 
    
    	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h  ;dw含义是定义字型数据,即define word
    	;8个数,偏移为:02468、A、C、E   地址为:CS:0、CS:2、CS:4、CS:6、CS:8、CS:A、CS:C、CS:E
            
    	start:	mov bx, 0  ;标号start
    			mov ax, 0  
    
    			mov cx, 8
    	s:		add ax, cs:[bx]
    			add bx, 2
    			loop s 
    
    			mov ax, 4c00h 
    			int 21h 
    code ends
    end start    ;end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方
    	     	 ;用end指令指明了程序的入口在标号start处,也就是说,“mov bx,0”是程序的第一条指令。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在代码段中使用栈,如下:

    ;利用栈,将程序中定义的数据逆序存放
        
    assume cs:codesg 
    codesg segment 
    	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ; 0-15单元
    	dw 0000000000000000 ; 16-47单元作为栈使用
    
    	start:	mov ax, cs 
    			mov ss, ax 
    			mov sp, 30h ;将设置栈顶ss:sp指向栈底cs:3030h = 48d
    			mov bx, 0
    
    			mov cx, 8
    	s:		push cs:[bx]
    			add bx, 2
    			loop s    ;以上将代码段0~15单元中的8个字型数据依次入栈
    
    			mov bx, 0
    
    			mov cx, 8
    	s0:		pop cs:[bx]		
    			add bx,2
    			loop s0   ;以上依次出栈8个字型数据到代码段0~15单元中
    
    			mov ax,4c00h 
    			int 21h 
    codesg ends 
    end start	;指明程序的入口在start处
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    将数据、代码、栈放入不同的段,如下:

    assume cs:code,ds:data,ss:stack 
    
    data segment 
    	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h ;0-15单元
    data ends 
    
    stack segment 
    	dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;0-31单元
    stack ends 
    
    code segment 
    	start:	mov ax, stack;将名称为“stack”的段的段地址送入ax
    			mov ss, ax
    			mov sp, 20h  ;设置栈顶ss:sp指向stack:2020h = 32d
    
    			mov ax, data ;将名称为“data”的段的段地址送入ax
    			mov ds, ax   ;ds指向data段
    
    			mov bx, 0    ;ds:bx指向data段中的第一个单元
    
    			mov cx, 8
    	s:	    push [bx]
    			add bx, 2
    			loop s       ;以上将data段中的0~15单元中的8个字型数据依次入栈
    
    			mov bx, 0
    
    			mov cx, 8
    	s0:		pop [bx]
    			add bx, 2
    			loop s0      ;以上依次出栈8个字型数据到data段的0~15单元中
    
    			mov ax, 4c00h 
    			int 21h 
    code ends
    end start
    ;“end start”说明了程序的入口,这个入口将被写入可执行文件的描述信息,
    ;可执行文件中的程序被加载入内存后,CPU的CS:IP被设置指向这个入口,从而开始执行程序中的第一条指令
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
  • 相关阅读:
    算法编程技巧
    【万字长文】说说电商系统常见的 9 个大坑,人麻了……
    python学习笔记(06)---(内置容器-元组)
    MySQL存储过程和函数知识点
    挖矿木马基础知识
    Java 学习和实践笔记(19):this的使用方法
    Visual Studio部署C++矩阵库Armadillo的方法
    Linux shell 从文本文件读取文件列表循环拷贝
    入门力扣自学笔记280 C++ (题目编号:1123)(二分查找)(多看看)
    配置haproxy负载均衡http
  • 原文地址:https://blog.csdn.net/qq_29678157/article/details/127929275