汇编语言笔记7更灵活的定位内存地址的方法
汇编语言笔记7更灵活的定位内存地址的方法
0x00 and和or指令和ascii码
and 指令:逻辑与指令,按位进行与运算
mov al,01100001b and al,00111011b
最终al的结果是 00100011b 可以将操作对象的相应位设为0,其他位不变
or指令:逻辑或运算,按位进行或运算
mov al,01100011b or al,00111011b
最终al的结果是01111011b 可以将操作对象的相对应为设为1,其他位不变
关于ascii码 计算机为了能将文字信息储存,要将其二进制编码,方案有很多中ascii码是其中一种,例如61h就代表‘a’,ascii 只包括英语大小写字母与部分符号,每个字符8位表示
我们按下键盘a建,这个按键事件被送入计算机,计算机利用ascii码规则找到对应编码61h,储存到内存空间,文本编辑器从内存中取出61h,将其送到显卡的显存中,显卡用ascii码的规制解释显存中的内容,61h被当作字符a,驱动显示器,将‘a’画到屏幕上
以字符形式给出数据
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 21h
code ends
end start
通过查看编译后的结果我们知道,masm在编译时遇到字符会直接编译成对应ascii码
大小写转换问题
assume cs:code,ds:data
data segment
db 'BaSic'
db 'iNfOrMaTiOn'
data ends
code segment
...
如何补充代码将data区里第一个字符串变成大写,第二个字符串变小写?
c语言时用的方法是判断ascii的区间65-90为大写字母 +32变成对应小写字母 97-122是小写 -32变对应大写,但是 我们现在没有学汇编的判断指令,所以不能用这个方法
通过观察上图可以看出 二进制表示时 第5位(从右到左从0开始数)为0即是大写字母,反之为小写,那么很简单了,我们要将字符串大写就全部将第5为变0 其余不变 也就是 and 11011111b 反之变小写就是 or 00100000b了
那么我们的代码如下
assume cs:code,ds:data
data segment
db 'BaSic'
db 'iNfOrMaTiOn'
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov cx,5
s: mov al,[bx]
and al,11011111b
mov [bx],al
inc bx
loop s
mov cx,11
s1: mov al,[bx]
or al,00100000b
mov [bx],al
inc bx
loop s1
mov ax,4c00h
int 21h
code ends
end start
这是执行完后的结果,说明正确完成了要求
0x01 更多偏移地址表示方式
[bx+idata]
表示偏移地址由bx里的值+idata组成,利用这个我们可以进行多个等长数组同时处理了
例如将第一个字符串大写,第二个字符串小写
assume cs:code,ds:data
data segment
db 'BaSic'
db 'MinIX'
data ends
code segment
start: mov ax,data
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
code ends
end start
由上图结果可知代码无误,另外[bx+idata]在masm里还有一种写法 idata[bx] 例如 [bx]可以写成0[bx] [bx+5]可以写成5[bx]
si和di寄存器
si和di是8086cpu中和bx功能近似的寄存器,也用来表示偏移地址,但是不能拆分成两个8为寄存器来使用,以下指令实现相同功能
mov bx,0 mov ax,[bx]->mov si,0 mov ax,[si]->mov di,0 mov ax,[di]
mov bx,0 mov ax,[bx+123]->mov si,0 mov ax,[si+123]->mov di,0 mov ax,[di+123]
assume cs:code,ds:data
data segment
db 'welcome to masm!'
db '................'
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0
mov cx,16
s: mov al,[si]
mov [si+16],al
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start
注意 上述代码用的al作为临时储存的寄存器,所以是一个字节一个字节的复制,但是我们观察数据是16字节,所以我们也可以用ax两个字节一起赋值,这样就不是inc si 是 add si,2
[bx+si]和[bx+di]
有了两个变量作为偏移地址,那我们就可以实现二维数组的遍历 将bx作为行偏移量 di/si作为列偏移量,但是这样需要嵌套的循环 而我们的loop都以cx作为循环依据,如何实现嵌套循环呢?实现思路就是进入内循环前保存外循环cx的值,出时读取 同样的保存内循环的值
很简单 ax 00beh bx 1000h cx 0606h
[bx+si+idata]和[bx+di+idata]
ax 0006h cx 6a00h bx 6a22h
0x02 不同寻址方式的灵活运用-嵌套循环的实现
assume cs:code,ds:data
data segment
db '1. file '
db '2. edit '
db '3. search '
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,16
loop s
mov ax,4c00h
int 21h
code ends
end start
上述代码是正确的
assume cs:code,ds:data
data segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0;行初始值
mov cx,4;行循环变量初始值
h: mov dx,cx;行循环变量保存在dx里
mov cx,3;列循环变量初始值
mov si,0
l: mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop l
mov cx,dx;恢复行循环变量
add bx,16
loop h
mov ax,4c00h
int 21h
code ends
end start
上述代码运行正确,其对应的c语言代码如下
int translate(char* start){
int h=0,l=0;
int bx=0;
for(h=4;h>0;h--){
int si=0;
for(l=3;l>0;l--){
start[bx+si]&=11011111b;
si++;
}
bx+=16;
}
return 0;
}
8086中只有一个循环变量,我们要同时进行两个循环,因此每次开始内循环前,将cx保存起来,我们这里用的是dx保存,实际上应该用栈比较好,保存就push cx 回复就pop cx
assume cs:code,ds:data
data segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,16
mov bx,0;行初始值
mov cx,4;行循环变量初始值
h: push cx;行循环变量进栈
mov cx,3;列循环变量初始值
mov si,0
l: mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop l
pop cx;行循环变量出栈
add bx,16
loop h
mov ax,4c00h
int 21h
code ends
end start
assume cs:code,ds:data,ss:stack
data segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
mov cx,4
mov bx,0
h: push cx
mov si,0
mov cx,4
l: mov al,[bx+si+3]
and al,11011111b
mov [bx+si+3],al
inc si
loop l
pop cx
add bx,16
loop h
mov ax,4c00h
int 21h
code ends
end start
以上代码运行结果正确