10.21汇编
今天看了两章,下午由于一些事耽搁了,本来其实还可以看更多,但总体还是满意的
第十一章是讲标志寄存器,说实话这个感觉主要靠记,而我还真记不下来
标志寄存器被称为flag,其中共有9个标志,存在0,2,4,6,7,8,9,10,11位中,别的位无意义。
ZF
零标志位,形如and ax,0
,sub ax,ax
这样的产生运算了的指令之后会根据运算的结果改变值,当结果位零时zf置1,反之置0。传送指令大多不对zf产生影响
PF
奇偶标志位,仍是产生运算时改变,若一的个数位偶数pf置1,反之置0。
SF
符号标志位,检测相关指令执行后结果是否为负,若为负sf置1,反之置0。
CF
进位标志位,若出现进位或借位则置1,常配合adc和sbb(带位运算)使用
比如若要进行32位运算,就可以
add ax,cx
adc bx,dx
;ax,cx为低位,bx,dx为高位
;sbb也类似
所以可以看出,cf主要涉及无符号数运算
OF
针对有符号数的溢出标志位
cmp指令
cmp 操作对象1,操作对象2
进行操作对象2-操作对象1的运算,但不保留结果,目的是影响标志寄存器flag。配合条件转移语句即可实现if的效果
指令 | 含义 | 检测的标志位 |
je | 等于则转移 | zf=1 |
jne | 不等于则转移 | zf=0 |
jb | 低于则转移 | cf=1 |
jnb | 不低于则转移 | cf=0 |
ja | 高于则转移 | cf=0且zf=0 |
jna | 不高于则转移 | cf=1或zf=1 |
e=equal,n=not,b=below,a=above,很好记
DF和串传送指令
这个就厉害了,df是方向标志位,在串处理指令中控制si,di的增减
df=0 si++,di++
df=1 si--,di--
cld将df置0,std将df置1
而movsb则可以做到
mov es:[di],byte ptr ds:[si];这个指令当然是不对的,内存不能直接传内存,只是表达效果
inc di
inc si
;假设df=0
的效果
movsw是以字为单位移动,也差不多。
一般来讲,为了控制移动的长度,会加上rep,如rep movsb
,当cx==0是结束转移,类似与loop
pushf和popf
将标志寄存器压栈、出栈以直接访问标志寄存器。
实验11
;convert every and only lower-case to capital letter
assume ds:data,ss:stack,cs:code
data segment
db "auSDFGofh gQWERaiSDoGsu ASdSDhf1y45gSD192459 te0g13894g!!!",0
data ends
stack segment
dd 4 dup(0)
stack ends
code segment
main:
;sreg init
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,16
call letterc
mov ax,4c00h
int 21h
letterc:
push ax
push bx
push cx
mov bx,0
mov ch,0
mov cl,ds:[bx]
s_letterc:
jcxz end_of_string_letterc
mov al,ds:[bx]
mov cl,al
cmp al,97
jb not_lowercase_letterc
cmp al,122
ja not_lowercase_letterc
and al,11011111b
mov ds:[bx],al
not_lowercase_letterc:
inc bx
jmp short s_letterc
end_of_string_letterc:
pop cx
pop bx
pop ax
ret
code ends
end main
一个比较简单的实验
内中断
内中断没有我想象中的难,cpu实现内中断的方法是通过中断向量表记录个中断处理程序的段地址和偏移地址。中断向量表的段地址就是零,偏移地址从0000到03FF,总共可以存储256个中断向量。每个向量占两个字,高地址字存段地址,低地址字存偏移地址。cpu根据中断码到向量表中查询目标地址,以执行中断程序。
过程为:
取得中断码N
pushf
TF=0,IF=0
push CS
push IP
(IP)=(N*4),(CS)=(N*4+2)
中断处理程序就可以通过
保存寄存器
处理
恢复寄存器
iret
iret类似与
pop IP
pop CS
popf
由此就实现了中断后返回
浅谈TF
单步中断是如何做到的?如果TF为1,cpu就进行单步中断(中断码为1)。如果执行中断程序之前不对TF置零,显然就麻烦了——永远都会处于单步中断的过程中。所以中断前要对TF置零。由此,其实debug的调试原理就很好理解了。提供TF标志位也就是为了提供单步调试功能
实验12
;display 'divide error!' in the middle of the screen when the div overflow error occured
assume cs:code
code segment
main:
;---------------------------------setup err0---------------------------------
mov ax,0
mov es,ax
mov ax,cs
mov ds,ax
mov cx,offset end_of_err0-err0
mov si,offset err0
mov di,200h
cld
rep movsb
;set err vector
mov ax,0
mov es,ax
mov es:[0*4+0],word ptr 200h
mov es:[0*4+2],word ptr 0h
;---------------------------------setup err0---------------------------------
;trigger the err0
mov ax,0fffh
mov cx,1
div cx
mov ax,4c00h
int 21h
err0:
jmp short err0_start
db 'divide error!'
err0_start:
;------------------------------clear the screen------------------------------
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
s_clear:
mov word ptr es:[bx],0
add bx,2
loop s_clear
;------------------------------clear the screen------------------------------
;--------------------------dispaly error information-------------------------
mov ax,0
mov ds,ax
mov ax,0202h
mov si,ax
mov ax,0b800h
mov es,ax
mov di,160*12+80-12
mov cx,13
mov ah,00100100b
s0_err0:
mov al,ds:[si]
mov es:[di].0,al
mov es:[di].1,ah
inc si
add di,2
loop s0_err0
;--------------------------dispaly error information-------------------------
;wat:jmp short wat
mov ax,4c00h
int 21h
end_of_err0:nop
code ends
end main
仍然算比较简单