标签:
本博文系列参考自<<汇编语言>>第三版,作者:王爽
前面已经通过类似[0]和[bx]的方法进行了内存定位了。本章将涉及更多内存地址定位和编程的方法。
7.1 and 和 or 指令
(1) and指令,逻辑按位与指令
例如:
mov al,01100011B
and al,00111011B
执行后 al=00100011B
and指令可以用来将某个数的位置为零。
比如我们要将al的第二位置为零,则: and al,11111101B
依次类推。
(2) or指令,逻辑按位或指令
例如:
mov al,01100011B
or al,00111011B
执行后 al=01111011Bor指令可以用来将某个数的位置为1
比如我们要将al的第高位置为一,则: or al,10000000B
7.2 关于ASCII码
在计算机中所有的信息都是以二进制方式进行存储的,那么计算机是如何存储我们输入的文本,字符这些信息,然后再讲这些信息输出给用户呈现呢?
那么我们可以这样想,当我们输入到计算机的信息和输出展示给用户的信息都是通过某种规则进行转换的。输入的时候通过这样的规则将用户的信息转换为二进制存储,输出的时候将计算机中存储的二进制信息进行翻译出来给用户。那么不言而喻,要想输入的信息和输出信息表达的意思是一致的,我们必须采用某种同样的规则来对这些信息进行解释。这就称为编码。
计算机中最常用的编码方式为ASCII编码。该编码用7位二进制表示128个基本的字符,字母和数字。后来ASCII扩展到8位增加了128个编码。当然根据每个国家文字的不同,又有很多不同编码比如中国的GB2312,不过为了进一步统一编码规则,现在也逐步推广unicode编码的使用。这种编码能够涵盖世界上所有的文字,字母,字符信息。
7.3 以字符形式给出的数据
如果学过C语言,那么很好理解当我们在C语言定义字符串的时候,字符串的每个字符都是以ASCII编码的方式在计算机中进行存储的。
汇编语言与一样我们可以把字符直接存储在‘.....‘中,这样程序会将‘....‘定义的字符以ASCII码存储在计算机中。看下面的程序:
这段程序定义了一个数据段ds和代码段cs,其中数据段存储了 ‘unIX‘ 和 ‘foRK‘。
db ‘unIX‘ 相当于db 75H,6EH,49H,58H 这四个数字分别代表了unIX四个字母的ASCII码
db ‘foRK‘ 相当于db 66H,6FH,52H,4BH 这四个数字分别代表了foRK四个字母的ASCII码
mov al, ‘a‘相当于mov al,61H 61为字符a的ASCII码
mov al, ‘b‘相当于mov al,62H 62为字符b的ASCII码
接下来我们进行编译链接成vpoet并通过debug工具查看其寄存器和指令:
看到MOV AL,61和MOV BL,62可以证明实际上计算机内部的确是用ASCII来表示字符。
记下来我们在使用d命令查看数据段在内存中存储的内容:
果然数据段中定义的字符串在内存中也是按照字符的ASCII码依次存储的。
7.4 大小写转换问题
有如下代码段:
将第一个字符串‘BaSiC‘全部转换为大写,第二个字符串‘iNforMaTiOn‘全部转换为小写。
我们要考虑如下几个问题:
根据大写与小写字符的ASCII码值相差20H
小写转换为大写可以使用 小写字符ASCII码值-20H=大写字符ASCII码值
大写转换为小写可以使用 大写字符ASCII码值+20H=小写字符ASCII码值
但是问题来了我们当前还没学过汇编的加法和减法运算符。肿么办呢?
通过分析我们可以发现,当我们用二进制表示字符的ASCII码值的时候。大写与小写的诧异主要在第5位上。
比如a的ASCII值为97 二进制1100001
A的ASCII值为65 二进制1000001
它们主要的区别在第五位,当大写的字符的时候第五位为1,当小写字符的时候第五位为0.所以这里我们可以用按位与和按位或
操作进行大小写转换。
实现代码如下:
<pre name="code" class="plain">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] and al,11011111B mov [bx],al inc bx loop s mov bx,5 mov cx,11 s0:mov al,[bx] or al,00100000B mov [bx],al inc bx loop s0 mov ax 4c00h int 21h codesg ends end start
7.5 [bx+idata]
[bx]代表一个内存地址的偏移量。假设其段地址在ds中。那么[bx]可以表示值为((ds)*16+(bx))
[bx+idata]其中idata代表常量,同样表示一个地址:((ds)*16+(bx)+200)
7.6用[bx+idata]的方式进行数组的处理
我们接近着7.4的问题有如下的问题,同样是将第一个字符串转换为大写,第二个字符串转换为小写。
这次第一个字符串为‘BaSiC‘ 第二个字符串为‘MinIX‘ 两个字符串均为5个字符的字符串
在7.4中我们处理两个字符串的时候需要两次分别复制给bx字符串的起始偏移地址,第一个字符串偏移地址为mov bx,0
第二个字符串的偏移地址为mov bx,5
现在我们可以[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 mov cx,5 s:mov al,[bx] and al,11011111B mov [bx],al mov al,[bx+5] or al,00100000B mov [bx+5],al inc bx loop s mov ax 4c00h int 21h codesg ends end start
7.7 SI和DI
SI和DI与普通寄存器一样,但是SI和DI不能像AX一样分成AL和AH两个寄存器。
有如下问题,需要将‘welcome to masm!‘这个字符串复制到其之后的数据区。
代码如下:
这里我们还可以使用前面介绍的[bx+idata]方式:
7.8 [bx+si]和[bx+di]
假设段地址为ds,[bx+si]解释为((ds)*16+(bx)+(si))
假设段地址为ds,[bx+si]解释为((ds)*16+(bx)+(di))
7.9 [bx+si+idata]和[bx+di+idata]
假设段地址为ds,[bx+si+idata]解释为((ds)*16+(bx)+(si)+idata)
假设段地址为ds,[bx+di+idata]解释为((ds)*16+(bx)+(di)+idata)
7.10 不同的寻址方式的灵活应用
我们现在总结下所学的内存寻址方式:
[idata]用一个常量表示地址,可用于直接定位一个内存单元
[bx]用一个变量来保存内存地址,可用于间接定位一个内存单元
[bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间隔定位一个内存单元
[bx+si]用两个变量表示地址
[bx+si+idata]用两个变量和一个常量表示地址
请顶我一下~~~
标签:
原文地址:http://blog.csdn.net/u013018721/article/details/51232405