- and指令: 逻辑与指令, 按位进行与运算
mov al,01100011B
and al,00111011B
执行后: al = 0010011B
- or指令: 逻辑或指令, 按位进行或运算
mov al,01100011B
or al,00111011B
执行后: al=01111011B
编码方案,就是一套规则, 约定了用什么样的信息来表示现实对象. 一个文本编辑过程中,就包含着按照ASCII编码规则进行的编码和解码.
在文本编辑过程中, 按下键盘的a
键,就会在屏幕上看到a
,这是怎样一个过程:
- 按下
a
键, 这个按键信息被送入计算机, 计算机用ASCII码的规则对齐进行编码, 将其转化为61h
存储在内存空间中 - 文本编辑器软件从内存中取出
61h
,将其送到显卡上的显存中 - 工作在文本模式下的显卡, 用ASCII码的规则解释显存中的内容,
61h
被当做字符a
,显卡驱动显示器,将字符a
的图像绘制到屏幕上.
在汇编程序中,用'...'
单引号的方式指明数据是以字符的形式给出的, 编译器将它们转化为相对应的
ASCII码
如:
assume cs:code,ds:data
data segment
db 'unIX' ;相当于`db 75h,6eh,49h,58h`
db 'foRK' ;相当于`db 66h,6fh,52h,4bh`
data ends
code segment
start: mov al,'a' ;相当于`mov,al,61h`
mov bl,'b' ;相当于`mov,al,62h`
mov ac,4c00h
int 21h
code ends
end start
在codesg
中填写代码,将datasg
中的第一个字符串转换为大写,第二个字符串转化为小写
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
s0:mov al,[bx]
or al,00100000b ;将al中的ASCII码的第5位设置为1,变为小写字母
mov [bx],al
inc bx
loop s0
mov ax,4c00h
int 21h
codesg ends
end
[bx+idata]
表示一个内存单元,它的偏移地址为(bx)+idata(bx中的数值加上idata)
mov ax,[bx+200]
含义:
将一个内存单元的内容送入ax,这个内存单元的长度为2个字节(子单元),存放一个字,偏移地址为bx中的数值加上200,段地址在ds中
(ax)=((ds)*16+(bx)+200)
也可以写成如下格式:
mov ax,[200+bx]
mov ax,200[bx]
mov ax,[bx].200
在codesg
中填写代码,将datasg
中的第一个字符串转换为大写,第二个字符串转化为小写
assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC'
db 'MinIX'
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码写回原单元
mov al,[5+bx] ;定位下一个字符串中的字符 也可以表示为 mov al,5[bx]
or al,00100000b
mov [5+bx],al ;也可以表示为 mov 5[bx],al
inc bx ;[bx]加1,ds:bx指向下一个字母
loop s
mov ax,4c00h
int 21h
codesg ends
end
用c语言来表示该程序
char a[5]="BaSiC";
char b[5]="MinIX";
main()
{
int i;
i=0;
do
{
a[i]=a[i]&0xdf;
b[i]=b[i]|0x20;
i++;
}while(i<5);
}
对于定位字符串中�字符的方式
c语言: a[i],b[i]
汇编语言: 0[bx],5[bx]
si和di是8086CPU中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用.下面的3组指令实现了相同的功能.
mov bx,0
mov ax,[bx]
mov ax,[bx+123]
mov si,0
mov ax,[si]
mov ax,[si+123]
mov di,0
mov ax,[di]
mov ax,[di+123]
用si和di实现将字符串welcome to masm!
复制到它后面的数据区中
assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!'
db '................'
datasg ends
codesg segment
mov ax,datasg
mov ds,ax
mov si,0
mov cx,8
s:mov ax,0[si]
mov 16[si],ax
add si,2
loop s
mov ax, 4c00h
int 21h
codesg ends
[bx+si]和[bx+di]
表示一个内存单元, 它的偏移地址为(bx)+(si)(即bx中的数值加上si中的数值)
mov ax,[bx+si]
含义: 将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为bx中的数值加上si中的数值,段地址在ds中. (ax)=((ds)*16 + (bx) + (si))
[bx+si+idata]和[bx+di+idata]表示一个内存单元, 偏移地址为(bx)+(si)+idata
mov ax,[bx+si+idata]
含义: 将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为bx中的数值加上si中的数值再加上idata,段地址在ds中. (ax)=((ds)*16+(si)+idata)
该指令也可以写成如下格式:
mov ax,[bx+200+si]
mov ax,[200+bx+si]
mov ax,200[bx][si]
mov ax,[bx].200[si]
mov ax,[bx][si].200
前面用到的几种定位内存地址的方法,可称为寻址方式
[idata]
用一个常量来表示地址,可用于直接定位一个内存单元[bx]
用一个变量来表示内存地址,可用于间接定位一个内存单元[bx+idata]
用一个变量和常量表示地址, 可在一个起始地址的基础上用变量间接定位一个内存单元[bx+si]
用两个变量表示地址[bx+si+idata]
用两个变量和一个常量表示地址
从[idata]
一直到[bx+si+idata]
,我们可以用更加灵活的方式来定位一个内存单元的地址.这使我们可以从更加结构化的角度来看待所要处理的数据
将datasg
段中每个单词的头一个字母改为大写字母
assume cs:codesg,ds:datasg
datasg segment
db '1. file '
db '2. edit '
db '3. search '
db '4. view '
db '5. options '
db '6. help '
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,6 ;设置循环次数为6
s: mov al,[bx+3] ;将首字母送入寄存器al
and al,11011111b ;与运算,将al中的数据转化成大写字母
mov [bx+3],al
add bx,16
loop s
mov ax,4c00h
int 21h
codesg ends
end start
将datasg段中每个单词改为大写字母
思路: 双重循环, 逐个转换
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
dw 0 ;定义一个字,用来暂存cx
datasg ends
codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4 ;外层循环次数为4
s0: mov ds:[40h],cx ;将外层循环cx值保存在datasg:40h单元中
mov di,0 ;设置字符偏移初始值为0
mov cx,3 ;内层循环次数为3
s1: mov al,[bx+di]
and al,11011111b
mov [bx+di],al
inc di
loop s1
mov cx,ds:[40h] ;内层循环完成之后, 还原cx的值
and bx,16 ;将bx指向下一个字符串
loop s0 ;继续执行外层循环
mov ax,4c00h
int 21h
codesg ends
end start
上面的程序, 用内层来保存数据, 但是做法还需要改进, 因为如果需要保存多个数据的时候, 上述程序需要记住数据放到了哪个单元中, 这样程序容易混乱. 一般来说, 在需要暂存数据的时候, 我们都应该使用栈
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
stacksg segmennt ;定义一个段,用来做栈段,容量为16个字节
dw 0,0,0,0,0,0,0,0
stacksg ends
codesg segment
start: mov as,stacksg
mov ss,ax
mov sp,16
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4 ;外层循环次数为4
s0: push cx ;将外层循环cx的值压栈
mov di,0 ;设置字符偏移初始值为0
mov cx,3 ;内层循环次数为3
s1: mov al,[bx+di]
and al,11011111b
mov [bx+di],al
inc di
loop s1
and bx,16 ;将bx指向下一个字符串
pop cx ;从栈顶弹出原cx的值,恢复cx
loop s0 ;外层循环的loop指令将cx中的计数值减一
mov ax,4c00h
int 21h
codesg ends
end start