汇编语言第11章
检测点11.1
写出下面每条指令执行后,ZF,PF,SF等标志位的值。
sub al,al ZF= 1 ,PF=1,SF=0
mov al,1 ZF=0,PF=0,SF=0
push ax ZF=0,PF=0,SF=0
pop bx ZF=0,PF=0,SF=0
add al,bl ZF=0,PF=0,SF=0
//al=1,bl=1执行后,al=2
add al,10 ZF=0,PF=1,SF=0
mul al ZF=0,PF=1,SF=1
//执行后,al=alal=1212=144
检测点11.2
写出下面每条指令执行后,ZF,PF,SF,CF,OF等标志位的值。
指令 | CF | OF | SF | ZF | PF |
---|---|---|---|---|---|
sub al,al | 0 | 0 | 0 | 1 | 1 |
mov al,10h | 0 | 0 | 0 | 0 | 0 |
add al,90h | 0 | 0 | 0 | 0 | 1 |
mov al,80h | 0 | 0 | 0 | 0 | 0 |
add al,80h | 1 | 1 | 1 | 0 | 1 |
mov al,0FCh | 0 | 0 | 1 | 0 | 1 |
add al,7Dh | 1 | 1 | 0 | 0 | 0 |
mov al,7Dh | 0 | 0 | 0 | 0 | 1 |
add al,0Bh | 0 | 1 | 1 | 0 | 1 |
检测点11.3
(1)补全程序。
jb s0
ja s0
:::::
进入循环后,比较32和内存中的值,如果内存中的值小于32,则比较下一个内存单元;如果内存中的值不小于32,比较128和内存中的值,如果内存中的值大于128,则继续比较下一个内存单元;如果两个条件都满足,使dx加一;直至全部比较完成。
:::::
(2)补全程序。
jna s0
jnb s0
:::::
进入循环后,比较32和内存中的值,如果内存中的值不大于32,则比较下一个内存单元;如果内存中的值大于32,比较128和内存中的值,如果内存中的值不小于128,则继续比较下一个内存单元;如果两个条件都满足,使dx加一;直至全部比较完成。
:::::
"""
这两个小题主要是让我们掌握“简接比较两个数的关系,来让程序更加精简”这种思想,以及联系我们对这几个条件转移指令和cmp的联合应用关系。
"""
检测点11.4
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12,13,14,15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
CF | PF | AF | ZF | SF | TF | IF | DF | OF |
下面程序执行后,(ax)=?
mov ax,0
push ax
popf ;弹出栈顶数据0到flag
mov ax,0fff0h
add ax,0010h ;这步执行后,发生溢出;cf=0,pf=1,zf=1,sf=0,df=0,of=1
pushf ;将flag入栈
pop ax ;弹出flag的值到ax(1010 0010 0001 0000)
and al,11000101b
;ax=1010 0010 0000 0000
and ah,00001000b
;ax=0000 0000 0000 0000
::::::
所以执行后,ax的值是0
::::::
实验11 编写子程序
编写一个子程序,将包含任意字符,以0字符结尾的字符串中的小写字母转变成大写字母。
:::
考虑用比较指令;比较字符的ascii码值是否在字符'a'的ascii码值与'z'的ascii码值之间。
以下,
:::
assume cs:code
data segment
db "Beginner's All-purpose Symbolic Instrution Code.",0
data ends
code segment
begin:
mov ax,data
mov si,0 ;使ds:si指向data段
call letterc
mov ax,4c00h
int 21h
"""
子程序描述:
名称:letterc
功能:将以0为结尾的字符串中的小写字母转变成大写字母
参数:ds:si指向字符串首地址。
"""
letterc:
push ax
push bx
push cx
push si
push ds
mov al,61h ;'a'的ascii码值为61h
mov bl,7bh ;'b'的ascii码值为7bh
cmpp:
mov cl,ds:[si]
mov ch,0
jcxz back ;判断是否遇到了结束字符
cmp cl,al
jb incp ;如果cl小于al就跳转到incp
cmp cl,bl ;cl不小于al了,如果cl大于bl就跳转到incp
ja incp
and cl,11011111b ;cl不小于al了,cl又不大于bl了,那就是我们要转变的字符了。
mov ds:[si],cl ;将转变后的字符送回原处
incp:
inc si ;判断下一个字符
jmp short cmpp ;跳转到开始判断位置。
back: ;结束
pop ds
pop si
pop dx
pop cx
pop bx
pop ax
ret
code ends
end begin
这个程序比较简单,哈哈,10分钟·就被我搞定了,成就感满满,不像之前那些个,??。
课程知识点概括:
CPU内部的寄存器中,有一种特殊的寄存器(不同处理机,结果可能不通。)——标志寄存器(flag)
都有3种作用:
(1)用来存储相关指令的某些执行结果;
(2)用来为CPU执行相关指令提供行为依据;
(3)用来控制CPU的相关工作方式;
X86CPU的标志寄存器有16位,其中存储的信息叫做PSW(程序状态字)。
首先,flag按位起作用,每一位都有专门的含义,记录特定的信息。示意图:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12,13,14,15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
CF | PF | AF | ZF | SF | TF | IF | DF | OF |
其中,1,3,5,12,13,14,15位没有作用。不具任何含义。
1。ZF标志
第6位,ZF标志位是零标志位。记录相关指令执行后,其结果是否为0。
如果为0,ZF=1;
如果不为0,ZF=0;
2。PF标志
第2位,PF标志位是奇偶标志位。记录相关指令执行后,其结果中所有bit位中1的个数。
如果1的个数为偶数,PF=1;(0也是0数)
如果1的个数为奇数,PF=0;
3。SF标志
第7位,SF标志位是符号标志位。记录相关指令执行后,其结果的正负。
如果为负,SF=1;
如果为正,SF=0;
SF的指示,在我们做无符号运算时没有影响,虽然它的值会改变。做有符号运算时,记录结果的正负。
4。CF标志
第0位,CF标志位是进位标志位。在进行无符号数运算时,记录最高有效位是否向更高位进位或者是借位。
当发生进位或是借位时,CF=1;
反之为0;
5。OF标志
第11位,OF标志位是溢出标志位。记录有符号数运算的结果是否发生了溢出。
如果发生了溢出,OF=1;
反之,为0;
要注意OF和CF的区别。
6。adc指令
带进位加法指令,利用CF位上的进位值。
指令格式:adc 操作对象1,操作对象2
功能:操作对象1=操作对象2+CF
利用adc指令可以实现对任意大的数据进行加法运算。
原理: 加法可以分两步来进行:1)低位相加;2)高位相加再加上低位相加产生的进位值。
比如:add ax,bx可等价于:
add al,bl
adc ah,bh
7。sbb指令
带借位减法指令,利用了CF位上记录的借位值。
指令格式:sbb 操作对象1,操作对象2
功能:操作对象1=操作对象1-操作对象2-CF
它的设计思想和adc一致。
8。cmp指令
cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。其他相关指令通过识别被cmp影响的标志寄存位来得知比较结果。
比如:cmp ax,ax
执行后:zf=1,pf=1,sf=0,cf=0,of=0
9。检测比较结果的条件转移指令
常用的根据无符号数的比较结果进行转移的条件转移指令。
指令 | 含义 | 记法 | 检测的相关标志位 |
---|---|---|---|
je | 等于则转移 | jump equal | zf=1 |
jne | 不等于则转移 | jump not equal | zf=0 |
jb | 小于则转移 | jump below | cf=1 |
jnb | 不小于则转移 | jump not below | cf=0 |
ja | 大于则转移 | jump above | cf=0且zf=0 |
jna | 不大于则转移 | jump not above | cf=1或zf=0 |
通常这些指令和cmp指令配合来使用进而实现这些转移指令的逻辑含义。
它们的联合使用看起来像高级语言中的 if 语句
在进行判断的时候,要多利用间接比较两个数的关系,来使我们的程序更加的简洁。
10。DF标志和串传送指令
第10位,DF标志位是方向标志位。在串处理指令中,控制每次操作后si,di的增减。
df=0,每次操作后si,di递增;
df=1,每次操作后si,di递减;
串传送指令:movsb
格式:movsb
功能:执行movsb指令相当于进行下面的操作:
mov es:[di],byte ptr ds:[si]
如果df=0:
inc si
inc di
如果df=1:
dec si
dec di
即movsb的功能是将ds:si指向的内存单元中的字节送入es:di,然后根据df位的值,来将si和di递增或者递减。
也可以传送一个字:movsw
一般来说:rep和movsb来进行配合使用。
格式:rep movsb
功能就是:
s:movsb
loop s
rep movsb可以循环实现(cx)个字符的传送。
rep movsw也可以。
cld指令和std指令:
分别将标志寄存器df位置0和置1;
在进行串传送指令进行数据的传送的时候,需要提供一些必要的信息:
1)传送的原始位置:ds:si;
2)传送的目的位置:es:di;
3)传送的长度:cx;
4)传送的方向:df
11。pushf和popf
pushf:将flag的值压栈;
popf:弹出栈顶数据到flag;
12。flag在debug中的显示
已知标志位的表示:
标志 | 值为1的标记 | 值为0的标记 |
---|---|---|
of | OV | NV |
df | DN | UP |
sf | NG | PL |
zf | ZR | NZ |
pf | PE | PO |
cf | CY | NC |