• 更灵活定位内存地址的方法


    更灵活定位内存地址的方法


    1.and和or

    1. and指令:逻辑与指令,按位进行与运算(同真为真)

      • 比如:

        mov al, 01100011B
        and al, 00111011B
        ;执行后:al=00100011B即都为1才为1
        
        • 1
        • 2
        • 3
    2. or指令:逻辑或指令,按位进行或运算(同假为假)

      • 比如:

        mov al, 01100011B
        or al, 00111011B
        ;执行后:al=01111011B 即只要有一个为1就为1
        
        • 1
        • 2
        • 3

    2.以字符形式给出的数据

    关于ASCII码在内存中的存储:

    1. 世界上有很多编码方案,有一种方案叫做ASCII编码,是在计算机系统中通常被采用的。简单地说,所谓编码方案,就是一套规则,它约定了用什么样的信息来表示现实对象。比如说,在ASCII编码方案中,用61H表示“a”,62H表示“b”。一种规则需要人们遵守才有意义
    2. 在文本编辑过程中,我们按一下键盘的a键,就会在屏幕上看到“a”。我们按下键盘的a键,这个按键的信息被送入计算机,计算机用ASCII码的规则对其进行编码,将其转化为61H存储在内存的指定空间中;文本编辑软件从内存中取出61H,将其送到显卡上的显存中;工作在文本模式下的显卡,用ASCII码的规则解释显存中的内容
    3. 61H被当作字符“a”,显卡驱动显示器将字符“a”的图像画在屏幕上。我们可以看到,显卡在处理文本信息的时候,是按照ASCII码的规则进行的。这也就是说,如果我们要想在显示器上看到“a”,就要给显卡提供“a”的ASCII码,61H。如何提供?当然是写入显存中

    比如:

    assume cs:code,ds:data 
    
    data segment 
    	db 'unIx'   ;相当于“db 75H,6EH,49H,58H”
    	db 'foRK'
    data ends 
    
    code segment
    start:	mov al, 'a'  ;相当于“mov al, 61H”,“a”的ASCI码为61H;
    		mov b1, 'b'
    		
    		mov ax, 4c00h 
    		int 21h 
    code ends
    end start
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    关于字符在内存中大小写转换的问题:

    1. 小写字母的ASCII码值比大写字母的ASCII码值大20H
    2. 大写字母ASCII码的第5位为0,小写字母的第5位为1(其他一致),大小写相差32,即2^5。注:这里的位数是从0开始计算的

    请添加图片描述

    assume cs:codesg,ds:datasg 
    
    datasg segment 
    	db 'BaSiC'
    	db 'iNfOrMaTion'
    datasg end
    
    codesg segment 
    	start:	mov ax, datasg 
    			mov ds, ax	;设置ds 指向 datasg段
    		
    			mov bx, 0	;设置(bx)=0,ds:bx指向’BaSic’的第一个字母
    			
    			mov cx, 5     	 ;设置循环次数5,因为’Basic'有5个字母
    	s:		mov al, [bx]     ;将ASCII码从ds:bx所指向的单元中取出
    			and al, 11011111B;将al中的ASCII码的第5位置为0,变为大写字母
    			mov [bx], al	 ;将转变后的ASCII码写回原单元
    			inc bx		     ;(bx)加1,ds:bx指向下一个字母
    			loop s 
    			
    			mov bx, 5	;设置(bx)=5,ds:bx指向,iNfOrMaTion'的第一个字母
    			
    			mov cx, 11	;设置循环次数11,因为‘iNfOrMaTion'有11个字母
    	s0:		mov al, [bx]
    			or al, 00100000B;将a1中的ASCII码的第5位置为1,变为小写字母
    			mov [bx], al 
    			inc bx
    			loop s0
    			
    			mov ax, 4c00h 
    			int 21h 
    codesg ends
    
    • 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

    3.[bx+idata]

    [bx+idata]表示一个内存单元, 例如:mov ax, [bx+200],该指令也可以写成如下格式:

    mov ax, [200+bx] ;将一个内存单元内容送入ax,这个内存单元的长度为2个字节,偏移地址为bx中的数值加上200,段地址在ds中,(ax)=((ds)*16+(bs)+200)
    
    mov ax,[bx+200]	 ;其他格式
        
    mov ax, 200[bx]  ;其他格式
    
    mov ax, [bx].200 ;其他格式
        
    ;案例:用Debug查看内存,结果如下
    ;2000:1000H BE 00 06 00 00 00 ...
        
    mov ax,2000H	
    mov ds,ax
    mov bx,1000H
    mov ax,[bx]		;段地址:(ds)=2000H 偏移地址:(bx)=1000H  则(ax)=00BEH
    mov cx,[bx+1]	;段地址:(ds)=2000H 偏移地址:(bx+1)=1001H 则(cx)=0600H
    add cx,[bx+2]	;段地址:(ds)=2000H 偏移地址:(bx+2)=1002H 则(cx)=0606H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    用[bx+idata]的方式进行数组的处理:

    assume cs:codesg,ds:datasg 
    
    datasg segment 
    	db 'BaSiC';转为大写
    	db 'MinIx';转为小写
    datasg ends
    
    codesg segment
    	start:
    		mov ax, datasg 
    		mov ds, ax 
    		mov bx, 0  			;初始ds:bx
    
    		mov cx, 5
    	s:	mov al, 0[bx]  
    		and al, 11011111b 	;转为大写字母
    		mov 0[bx], al 		;写回
    		mov al, 5[bx]  		;[5 + bx]
    		or al, 00100000b 	;转为小写字母
    		mov 5[bx], al 
    		inc bx
    		loop s
    
    		mov ax, 4c00h 
    		int 21h
    codesg ends
    end 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

    C语言描述方式:

    int main()
    {
    	char a[] = "BaSic";
    	char b[] = "MinIX";
    
    	int i = 0;
    
    	do
    	{
    		a[i] = a[i] & 0xDF;
    		b[i] = b[i] | 0x20;
    		i++;
    	} while(i < 5);
    
    	return 0;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.SI、DI与寻址方式的灵活应用

    1. si和di是8086CPU中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用

      assume cs: codesg, ds: datasg 
                     
      datasg segment 
      	db 'welcome to masm!' ;用si和di实现将字符串‘welcome to masm!"复制到它后面的数据区中。
      	db '................' ;db是ding'y
      datasg ends
                     
      codesg segment 
      	start:	mov ax, datasg 
      			mov ds, ax 
      			mov si, 0
                     
      			mov cx, 8
      	s:		mov ax, 0[si] ;[0 + si]
      			mov 16[si], ax ;[16 + si] 使用[bx +idata]方式代替di,使程序更简洁
      			add si, 2 
      			loop s 
                     
      			mov ax, 4c00h 
      			int 21h 
      codesg ends 
      end start
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    2. [bx+si]和[bx+di]的含义相似:

      1. [bx+si]表示一个内存单元,它的偏移地址为(bx)+(si)
      2. 指令mov ax, [bx + si]的含义:将一个内存单元字数据的内容送入ax,段地址在ds中
      3. 该指令也可以写成如下格式:mov ax, [bx][si]
    3. [bx+si+idata]和[bx+di+idata]:

      1. [bx+si+idata]表示一个内存单元,它的偏移地址为(bx)+(si)+idata
      2. 指令mov ax,[bx+si+idata]的含义:将一个内存单元字数据的内容送入ax,段地址在ds中
    4. 不同的寻址方式的灵活应用

      1. [idata]用一个常量来表示地址,可用于直接定位一个内存单元
      2. [bx]用一个变量来表示内存地址,可用于间接定位一个内存单元
      3. [bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元
      4. [bx+si]用两个变量表示地址
      5. [bx+si+idata]用两个变量和一个常量表示地址
    
    ;将datasg段中每个单词改为大写字母
    assume cs:codesg,ds:datasg,ss:stacksg 
    
    datasg segment
    	db 'ibm            ' ;16
    	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 ;初始ds:bx
    
    			;cx为默认循环计数器,二重循环只有一个计数器,所以外层循环先保存cx值,再恢复,我们采用栈保存
    			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值
    			loop s0 ;外层循环的loop指令将cx中的计数值减1
    
    			mov ax,4c00H 
    			int 21H 
    codesg ends
    end start
    			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值
    			loop s0 ;外层循环的loop指令将cx中的计数值减1
    
    			mov ax,4c00H 
    			int 21H 
    codesg ends
    end 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
  • 相关阅读:
    【Paper】2022_离散时间多智能体系统编队-包围控制研究_李博凡
    第十九章·迭代器模式
    【LLM-RAG】知识库问答 | 检索 | embedding_rag embedding
    SpringCloud(15)之SpringCloud Gateway
    天脉操作系统(ACoreOS)
    redis场用命令及其Java操作
    Guava-RateLimiter详解
    git submudles 代码如果提交到一个ID 上
    【C++ 学习 ㊲】- 五种特殊类的设计
    Runable和Callable的区别?首先要搞清楚Thread以及FutureTask!
  • 原文地址:https://blog.csdn.net/qq_29678157/article/details/127929316