【汇编语言】更灵活的定位内存地址的方法(一)—— 字符操作:and与or指令、ASCII码及大小写转换-LMLPHP

前言

前面,我们用[0]、[bx]的方法,在访问内存的指令中,定位内存单元的地址。本章我们主要通过具体的问题来讲解一些更灵活的定位内存地址的方法和相关的编程方法。我们的讲解将通过具体的问题来进行。

1. and和or指令

首先,介绍两条指令 and和or,因为我们下面的例程中要用到它们。

1.1 and指令

例如指令:

mov al,01100011B
and al,00111011B

执行后:al=00100011B

通过该指令可将操作对象的,其他位不变。

例如:

  • 将al的第6位设为0的指令是:and al,10111111B

  • 将al的第7位设为0的指令是:and al,01111111B

  • 将al的第0位设为0的指令是:and al,11111110B

1.2 or指令

例如指令:

mov al,01100011B
or al,00111011B

执行后:al=01111011B

通过该指令可将操作对象的,其他位不变。

例如:

  • 将al的第6位设为1的指令是:or al,01000000B

  • 将al的第7位设为1的指令是:or al,10000000B

  • 将al的第0位设为1的指令是:or al,00000001B

2. 关于ASCII码

我们可能已经学习过 ASCII码的知识了,这里进行一下复习。

计算机中,所有的信息都是二进制,而人能理解的信息是已经具有约定意义的字符。比如说,人在有一定上下文的情况下看到“123”,就可知道这是一个数值,它的大小为123;看到“BASIC”就知道这是在说BASIC这种编程语言;看到“desk”,就知道说的是桌子。

而我们要把这些信息存储在计算机中,就要对其进行,将其转化为二进制信息进行存储。而计算机要将这些存储的信息再显示给我们看,就要再对其进行。只要编码和解码采用同样的规则,我们就可以将人能理解的信息存入到计算机,再从计算机中取出。

世界上有很多编码方案,有一种方案叫做ASCII编码,是在计算机系统中通常被采用的。简单地说,所谓编码方案,就是一套规则,它约定了用什么样的信息来表示现实对象。比如说,在ASCII编码方案中,用61H表示“a”,62H表示“b”。一种规则需要人们遵守才有意义。

一个文本编辑过程中,就包含着按照ASCII编码规则进行的编码和解码。

在文本编辑过程中,我们按一下键盘的a键,就会在屏幕上看到“a”。这是怎样一个过程呢?

我们按下键盘的a键,这个按键的信息被送入计算机,计算机用ASCII码的规则对其进行编码,将其转化为61H存储在内存的指定空间中;文本编辑软件从内存中取出61H,将其送到显卡上的显存中;工作在文本模式下的显卡,用ASCII码的规则解释显存中的内容,61H 被当作字符“a”,显卡驱动显示器,将字符“a”的图像画在屏幕上。

我们可以看到,显卡在处理文本信息的时候,是按照ASCII码的规则进行的。这也就是说,如果我们要想在显示器上看到“a”,就要给显卡提供“a”的ASCII码,61H。如何提供?当然是写入显存中。

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

我们可以在汇编程序中,。

3.1 示例代码

如下面的程序。

assume cs:code ds:data
data segment
	db 'unIX'
	db 'foRK'
data ends

code segment
start:	mov al,'a'
		mov bl,'b'

		mov ax,4c00h
		int 2lh
code ends

end start

3.2 分析代码

3.2.1 相关代码的含义

上面的源程序中:

  • db 'unIX' ” 相当于“db 75H,6EH,49H,58H”, “u”、 “n”、 “I”、 “X”的ASCII码分别为75H、6EH、49H、58H。

  • db 'foRK' ” 相当于“db 66H,6FH,52H,4BH”, “f”、 “o”、 “R”、 “K”的ASCII码分别为66H、6FH、52H、4BH。

  • mov al,'a'”相当于“mov al,61H”,”a”的ASCII码为61H。

  • mov al,'b'”相当于“mov al,62H”,”b”的ASCII码为62H。

3.2.2 查看代码段中的内容

将示例代码编译为可执行文件后,用Debug 加载査看 data 段中的内容,如下图所示。

【汇编语言】更灵活的定位内存地址的方法(一)—— 字符操作:and与or指令、ASCII码及大小写转换-LMLPHP

上图中,先用r命令分析一下 data 段的地址,因“ds=0B2D”,所以程序从0B3DH段开始,data段又是程序中的第一个段,它就在程序的起始处,所以它的段地址为0B3DH。

d命令查看data段,Debug 以十六进制数码和ASCII码字符的形式显示出其中的内容,从中,可以看出 data 段中的每个数据所对应的ASCII字符。

4. 大小写转换的问题

4.1 问题引入

下面考虑这样一个问题,在codesg中填写代码,将datasg 中的第一个字符串转化为大写,第二个字符串转化为小写。

4.2 问题代码

assume cs:codesg,ds:datasg
datasg segment
	db 'BaSiC'
	db 'iNfOrMaTiOn'
datasg ends

codesg segment
start:	
codesg ends

end start

4.3 分析与解决问题

4.3.1 对比ASCII码值寻找规律

首先分析一下,我们知道同一个字母的大写字符和小写字符对应的ASCII码是不同的,比如“A”的ASCII码是41H,“a”的ASCI码是61H。要改变一个字母的大小的,写,实际上就是要改变它所对应的ASCII码。我们可以将所有的字母的大写字符和小写字符所对应的ASCI码列出来,进行一下对比,从中找到规律。

【汇编语言】更灵活的定位内存地址的方法(一)—— 字符操作:and与or指令、ASCII码及大小写转换-LMLPHP

通过对比,我们可以看出来,。

这样,我们可以想到,如果将“a”的ASCII码值减去20H,就可以得到“A”;如果将“A”的 ASCII 码值加上20H 就可以得到“a”。

按照这样的方法,可以将 datasg 段中的第一个字符串“BaSiC”中的小写字母变成大写,第二个字符串“iNfOrMaTiOn”中的大写字母变成小写。

4.3.2 探讨程序流程

要注意的是,对于字符串“BaSiC”,应只对其中的小写字母所对应的ASCII 码进行减20H的处理,将其转为大写,而对其中的大写字母不进行改变;对于字符串“iNfOrMaTiOn”,我们应只对其中的大写字母所对应的ASCII码进行加 20H 的处理,将其转为小写,而对于其中的小写字母不进行改变。

以“BaSiC”讨论,程序的流程将是这样的:

assume cs:codesg,ds:datasg
datasg segment
	db 'BaSiC'
	db 'iNfOrMaTiOn'
datasg ends

codesg segment
start:	mov ax,datasg
		mov ds,ax
		mov bx,0
		mOv cx,5
	s:  mov al,[bx]
		如果(al)>61H,则为小写字母的ASCII码,则:sub al,20H
		mov [bx],al
		inc bx
		loop s
		:
		:
codesg ends

end start

4.3.3 面临的问题

判断将用到一些我们目前还没有学习到的指令。现在面临的问题是,用已学的指令来解决这个问题,则不能对字母的大小写进行任何判断。

但是,现实的问题却要求程序必须要。

那么怎么办呢?

4.3.4 重新思考问题,寻找解决方案

如果一个问题的解决方案,使我们陷入一种矛盾之中。那么,很可能是我们考虑问题的出发点有了问题,或是说,我们起初运用的规律并不合适。

这使我们最终落入了这样一个矛盾之中:必须判断是大写字母还是小写字母,才能决定进行何种处理,而我们现在又没有可以使用的用于判断的指令。

我们应该重新观察,寻找新的规律。可以看出,就ASCII码的二进制形式来看,除第5位(位数从0开始计算)外,大写字母和小写字母的其他各位都一样。大写字母ASCII码的第5位为0,小写字母的第5位为1。

在这个方法中,我们不需要在处理前判断字母的大小写。比如:对于“BaSiC”中的“B”,按要求,它已经是大写字母了,不应进行改变,将它的第5位设为0,它还是大写字母,因为它的第5位本来就是0。

用什么方法将一个数据中的某一位置0还是置1?

当然是用我们刚刚学过的or 和 and指令。

4.3.5 正确的完整代码实现

完整的程序如下。

assume cs:codesg,ds:datasg
datasg segment
	db 'BaSiC'
	db 'iNfOrMaTiOn'
datasg ends

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		;将al中的ASCII码的第5位置为1,变为小写字母
	   mov [bx],al
	   inc bx
	   loop s0
	   
	   mov ax,4c00h
	   int 2lh
codesg ends

end start

结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。

也可以点点关注,避免以后找不到我哦!

Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

【汇编语言】更灵活的定位内存地址的方法(一)—— 字符操作:and与or指令、ASCII码及大小写转换-LMLPHP

11-17 05:35