灵活定位内存地址

灵活定位内存地址,灵活应用

1.0 and和or指令

  • and指令,逻辑运算 &按位与运算 都真为真

  • mov al, 0110 0011B
    and al, 0011 1011B
    
    执行后al=0010 0011B 
    
  • 通过该指令可以将操作对象的相对位设置为0

  • mov al, 1111 1111B
    and al, 1011 1111B
    
    执行后al=1011 1111B
    
    将操作对象的第6位设置为0 
    
  • or指令,逻辑运算 | 按位或运算 都假为假

  • mov al, 0110 0011B
    or  al, 0011 1011B
    
    执行后al=0111 1011B 
    
  • 通过该指令可以将操作对象的相对位设置为1

  • mov al, 0000 0000B
    or  al, 0100 0000B
    
    执行后al=0100 0000B
    
    将操作对象的第6位设置为1 
    

1.1 ASCII

1.2 以字符的形式给出数据集

  • 我们可以在编程时用‘ ...... ‘的方式指定数据是以字符的形式给出的,编译器将他们转换为ASCII码

  • db 'linux'
    db 'unix'
    

1.3 大小写转换的问题

  • 通过对比,我们可以看出小写字母的ASCII码的值比大写字母的大20H,十进制也就是32

  • 可以看出除第五位外,大小写字母的其他各位都是一样的

  • 一个字母,我们不管它之前是不是大写或者小写,我们将他的第5位置改变成0那它就变成大写字母,改为1就是小写

  • assume cs:code,ds:data
    
    data segment
    	db 'LINUX'
    	db 'UNIX'
    data ends
    
    code segment
    start:  mov ax, data
    		mov ds, ax
    	
    		mov bx, 0
    		mov cx, 5
    	
    	  s:mov al, [bx]
    		or al, 00100000B
    		mov [bx], al
    		inc bx
    		loop s
    	
    		mov ax, 4c00H
    		int 21H
    code ends
    
    end start
    

1.4 [bx+idata] [bx+SI+idata] [bx+DI+idata]

  • 为了更好更方便多的访问内存可以用 [bx+idata] 用bx加上一个常量来进行寻址

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

  • 数组是在内存中一连串的区域,这个区域都是同一类型的变量

  • 将上面程序用[bx+idata]修改,将’basic‘大写

  • assume cs:code,ds:data
    
    data segment
    	db 'LINUX'
    	db 'basic'
    data ends
    
    code segment
    start:  mov ax, data
    		mov ds, ax
    	
    		mov bx, 0
    		mov cx, 5
    	
    	  s:mov al, [bx]
    		or al, 00100000B
    		mov [bx], al
    		mov al, [bx+5]
    		and al, 11011111B
    		mov [bx+5], al
    	
    		inc bx
    		loop s
    	
    		mov ax, 4c00H
    		int 21H
    code ends
    
    end start
    
  • [bx+idata]的方式为高级语言实现数组提供了变利的条件

1.5 SI和DI

  • SI和DI和bx寄存器的功能是相近的,但是他们不能拆成两个8位的寄存器

  • 以下s三组代码实现了相同的功能

  • mov bx, 0
    mov ax, [bx]
    
    mov si,0
    mov ax, [si]
    
    mov di,0
    mov ax, [di]
    
  • 由SI和DI 实现将字符串”helloworld“复制到它后面的数据区中 看代码

  • SI指向原始字符串,DI指向复制的空间,然后循环完成复制

  • assume cs:code,ds:data
    
    data segment
    	db 'helloworld'
    	db '..........'
    data ends
    
    code segment
    
    start:	mov ax, data
    		mov ds, ax
    		
    		mov si, 0
    		mov di, 10
    		
    		mov cx, 5
    		
    	f:  mov ax, [si]
    		mov [di], ax
    		
    		add si, 2
    		add di, 2
    		
    		loop f
    		
    		mov ax, 4c00H
    		int 21H
    code ends
    
    end start
    
  • 用[bx+idata] 简化程序

  • assume cs:code,ds:data
    
    data segment
    	db 'helloworld'
    	db '..........'
    data ends
    
    code segment
    start:	mov ax, data
    		mov ds, ax
    		mov si, 0		
    		mov cx, 5	
    		
    	f:  mov ax, [si]
    		mov [si+10], ax
    		add si, 2
    		loop f
    		
    		mov ax, 4c00H
    		int 21H
    code ends
    
    end start
    

1.6 编程题

  • 1.实现定义字符的大写首字母

  • assume cs:code,ds:data
    
    data segment
    	db '1. edit   '
    	db '2. file   '
    	db '3. view   '
    	db '4. help   '
    data ends
    
    code segment
    start:	mov ax, data
    		mov ds, ax
    		
    		mov bx, 0
    		mov cx, 4
    	s:	mov al, [bx+3]
    		and al, 11011111B
    		
    		mov [bx+3], al
    		add bx, 10
    		loop s
    		
    		mov ax, 4c00H
    		int 21H
    code ends
    
    end start
    
  • 2.实现将字符全部大写,我们需要进行4*3次的双重循环

  • assume cs:code,ds:data,ss:stack
    
    data segment
    	db '1. edit   '
    	db '2. file   '
    	db '3. view   '
    	db '4. help   '
    data ends
    
    stack segment
    	dw 0,0,0,0,0,0,0,0   ;定义栈区,用来存放cx循环的值  16个字节
    stack ends
    
    code segment
    start:	mov ax, stack
    		mov ss, ax
    		mov sp, 16
    		
    		mov ax, data
    		mov ds, ax
    		
    		mov bx, 0
    		mov cx, 4		;定义外层循环
    	s0: push cx			;将cx的值进行压栈
    		mov si, 3
    		mov cx, 4		;定义内层循环
    	s:	mov al, [bx+si]
    		and al, 11011111B
    		mov [bx+si], al
    		inc si
    		loop s
    		
    		add bx,10
    		pop cx			;从栈顶弹出原来cx的值
    		loop s0			;外层循环将cx减一
    		
    		mov ax, 4c00H
    		int 21H
    code ends
    
    end start
    

1.7 word ptr

  • 下面的指令中,用word ptr指明了指令访问内存单元是一个字单元数据

  • mov word ptr ds:[0], 1
    add word ptr ds:[0], 1
    inc word ptr [bx]
    
    下面的指令中,用word ptr指明了指令访问内存单元是一个字节单元数据
    mov byte ptr ds:[0], 1   ;
    
  • 在没有寄存器参与的内存单元访问指令中,用word ptr byte ptr显性的指出所要访问内存单元的长度是很有必要的

  • 否则CPU无法得知所要访问的是字单元,还是字节单元

1.8 寻址方式的综合应用

  • 一般来说,我们用[bx+idata+si] 的方式来访问结构体中的数据
  • 用bx定义结构体,idata定义结构体中的某一个数据项,用si定位数据项中单个元素

1.9 div指令

  • division 是除法指令 注意事项

  • 除数:8位或者16位在寄存器中或者在内存单元中

  • 被除数:默认放在AX 或DX和AX中

  • 除数是8位的话 商存储在al中 余数存储到ah中
    除数是16位的话 商存储在ax中 余数存储到dx中

  • 计算10/3

  • assume cs:code,ds:data
    
    data segment
    	db 3							;定义除数
    data ends
    
    code segment
    
    start: 	mov ax, data
    		mov ds, ax
    		
    		mov ax, 10					;定义被除数
    		mov bx, 0
    		div byte ptr [bx] 			;指向定义的除数
    		
    		mov ax, 4c00H
    		int 21H
    		;除数是8位的话  商存储在al中  余数存储到ah中
    		;除数是16位的话 商存储在ax中  余数存储到dx中
    code ends
    
    end start
    		
    
  • 如果除数是16位的话

  • assume cs:code,ds:data
    
    data segment
    	db 3
    data ends
    
    code segment
    
    start: 	mov ax, data
    		mov ds, ax
    		
    		mov ax, 1				;0000 0000 0000 0001
    		mov dx, 1				;0000 0000 0000 0001
    		mov bx, 0
    		div word ptr [bx] 		;这里就是dx在高位 ax在地位 0000 0000 0000 0001 0000 0000 0000 0001 
    								;十进制65537/3
    								;商存在AX中
    								;余数存储到DX中
    		mov ax, 4c00H
    		int 21H
    code ends
    
    end start
    		
    
  • 如果除数是16位的话 被除数是32位,高16位在dx中,低16位在ax中,如上代码

2.0 伪指令 DD dd

  • dd是用来定义dword(double word)双字型数据 32个字节

  • dd 31415926  ;占32个字节     正常定义即可
    

2.1 dup duplicate 复制

  • dup是一个操作符,在汇编语言中同db dw dd一样,是由编译器处理的符号

  • 它是配合db dw dd 符号使用的,用来数据的重复

  • db 3 dup(0)  ;定义三个字节他们的值都是0
    db 0,0,0     ;相当于这样
    
    db 3 dup(0,1,2)  		;定义九个个字节他们的值是0,1,2,0,1,2,0,1,2
    db 0,1,2,0,1,2,0,1,2    ;相当于这样
    
    assume cs:code,ds:data
    
    data segment
    	db 2 dup('helloworld')    ;连续定义两个以字节为单位的helloworld
    data ends
    
    code segment
    
    start: 	mov ax, data
    		mov ds, ax
    		mov ax, 4c00H
    		int 21H
    		
    code ends
    
    end start
    

总结 实验

  • 将data中数据按格式存入table段中
  • 可以用循环来减少代码
assume cs:code,ds:data,es:table,ss:stack

data segment
	db '1990','1991','1992','1993','1994','1995','1996','1997','1998','1999','2000'
	db '2001','2002','2003','2004','2005','2006','2007','2008','2009','2010'  ;最近21年的年份
	;计算年份的偏移地址 4*21=84  十六进制54H用53H
	dd 116,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,5840  ;21年每年的收入
	;计算收入的偏移地址 54H+54H=A8H  用A7H
	dw 1,6,9,12,113,6,9,12,113,6,9,12,113,6,9,12,113,6,9,12,50				;21年每年的人数
	;计算人数的偏移地址 A8H+2A=D2  用D1
data ends		

table segment
	db 21 dup('year summ ne !! ')
table ends

stack segment
	dw 8 dup('0')
stack ends

code segment
start:	mov ax, data
		mov ds, ax		;将ds和data挂钩
		
		mov ax, table
		mov es, ax		;将es和table挂钩
		
		mov bx, 0		;初始化参数
		mov si, 0
		mov di, 0
		mov cx, 21      ;设置循环次数21次
	s:	mov al, ds:[bx]		;存放年份
		mov es:[di], al
		
		mov al, ds:[bx+1]
		mov es:[di+1], al
		
		mov al, ds:[bx+2]
		mov es:[di+2], al
		
		mov al, ds:[bx+3]
		mov es:[di+3], al
		
		mov ax, [bx+54H]	;存放收入
		mov dx, [bx+56H]
		mov es:[di+5H], ax
		mov es:[di+7H], dx
		
		mov ax, [si+0A8H]	;存放人数
		mov es:[di+0AH], ax
		
		mov ax, [bx+54H]	;存放人均收入
		mov dx, [bx+56H]
		
		div word ptr ds:[si+0A8H]
		mov es:[di+0dH], ax
		
		add bx, 4
		add di, 16
		add si, 2
		loop s
		
		mov ax, 4c00H
		int 21H
code ends

end start
上一篇:汇编语言(王爽)学习记录_第七章


下一篇:《汇编语言》——王爽实验4