標志寄存器
這就是計算機中的標志寄存器船老,說到標志我們就應(yīng)該想到flag琉苇,bool類型匕垫。而一個bool類型用1bit就可以表示了,所以我們談?wù)撨@個32位的標志寄存器除破,更多的時候是討論其中的某一位牧氮。
比如0位,2位瑰枫,4位踱葛,都是cpu中設(shè)定好的用途,就跟通用寄存器一樣光坝,有自己的名字尸诽。比如C位,P位盯另,O位性含。
進位標志位CF(carry flag)
如果運算結(jié)果的最高位產(chǎn)生了一個進位或借位,那么鸳惯,其值為1商蕴,否則其值為0。
三個實驗:
mov al,0xff
add al,2 // c位變成1
mov al,0xfe // mov不是運算所以C位不變
// C位手動清零
add al,2 // c位又變成1
// C位手動清零
mov ax,0xff
add ax,2 // c位已經(jīng)是0
// =========================重點
// 標志寄存器在學習過程中芝发,我們一定要明白數(shù)據(jù)的寬度
//【mov ax绪商,0xff 】中,數(shù)據(jù)的寬度是16位辅鲸,add之后格郁,確實是進位了,但不是最高位的進位
補充:什么是運算?
mov不算是運算例书,其他的加減乘除異或等都是運算
奇偶標志位:PF(Parity Flag)
PF 反應(yīng)運算結(jié)果中“1”的個數(shù)的奇偶性锣尉,如果1的個數(shù)是偶數(shù),則P位是1雾叭,如果1的個數(shù)是奇數(shù)悟耘,則P位是0
實驗
MOV AL,3 // 00001011 p位:0
add al,2 // 00001010 P位:1
輔助進位標志AF(Auxiliary Carry Flag)
在發(fā)生下列情況時,輔助進位標志AF的值被置為1织狐,否則其值為0:
(1)、在字節(jié)操作時筏勒,發(fā)生低字節(jié)向高字節(jié)進位或借位時移迫;
(2)、在字節(jié)操作時管行,發(fā)生低4位向高4位進位或借位時厨埋。
大白話說下,就是運算時捐顷,把位劃分成兩半荡陷,低位的一半的第一位如果向高位進位(加)或者借位(減)時,A位就是1
如下圖迅涮,就看突出的那一位
32位運算: _ _ _ _ - _ _ _
16位運算: _ _ - _
8位運算: _ -
實驗:
// 第一組
MOV EAX,0x55EEFFFF
ADD EAX,2 // A位變1
// 第二組
MOV AX,5EFE
add ax,2 // A位又變1
// 第三組
MOV AL,4E
add al,2 // A位又變1
零標志ZF(Zero Flag)
零標志ZF用來反映運算結(jié)果是否為0
如果運算結(jié)果為0废赞,則其值為1,否則其值為0叮姑。在判斷運算結(jié)果是否為0時唉地,可使用此標志位。
實驗
XOR EAX,EAX // Z位:1
// 這句話的作用有兩個
// 1.將EAX的值變?yōu)?
// 2.將標志位Z位置為1传透。如果[mov eax,0] 的話就沒有第二個作用了,mov就不是運算
符號標志SF(Sign Flag)
符號標志SF用來反映運算結(jié)果的符號位耘沼,它與運算結(jié)果的最高位相同。
特別注意:這里的最高位說的是二進制的最高位朱盐,所以只能是0或1
MOV AL,7F
ADD AL,2 // 1
溢出標志OF(Overflow Flag)
溢出標志OF用于反映有符號數(shù)加減運算所得結(jié)果是否溢出群嗤。
如果運算結(jié)果超過當前運算位數(shù)所能表示的范圍,則稱為溢出兵琳,OF的值被置為1狂秘,否則,OF的值被清為0闰围。
最高位進位(CF)和溢出(OF)的區(qū)別赃绊?
這里主要涉及到了無符號整數(shù)和有符號整數(shù)。計算機在存儲的時候羡榴,并不知道自己存儲的是有符號整數(shù)還是無符號整數(shù)碧查。只有使用的人才知道,就是程序員嘍。
C位是做無符號運算時該關(guān)注的
O位是做有符號運算時該關(guān)注的
想知道現(xiàn)在計算的結(jié)果有沒有溢出忠售,是看CF位還是OF位传惠?
我要看那個取決于我做的是有符號還是無符號運算。
如果你知道自己做的是無符號運算稻扬,你只用看C位卦方,不用管O位
如果你知道自己的做的是有符號運算,只要看O位泰佳,不用管C位
好好看這個圖就什么都明白了
正數(shù)+負數(shù)盼砍,一定在圈內(nèi),永遠不會溢出
正數(shù)+正數(shù)逝她,如果結(jié)果為負數(shù)(超過7F內(nèi))浇坐,一定溢出。因為越界了黔宛,兩個正數(shù)相加不應(yīng)該是負數(shù)近刘。
說結(jié)果之前,一定要指定到底是無符號運算還是有符號預算臀晃。
自己這個分析判斷是錯誤的觉渴,其實只要是圈上的點可以表示的,都沒有溢出徽惋,圈上的店不能表示的案淋,就是溢出了。
只是有符號的話寂曹,只有右邊區(qū)域表示正數(shù)哎迄,左邊區(qū)域表示負數(shù)
無符號的話,整個區(qū)域都可以表示
和標志寄存器相關(guān)的指令
ADC指令:帶進位加法
百度百科:
ADC 帶進位的加法指令 ADC Reg/Mem, Reg/Mem/Imm 功能隆圆,將目的操作數(shù)和源操作數(shù)相加再加低位進位漱挚,結(jié)果送入目的的地址 dst+src+cf->dst, 受影響的標志位:AF渺氧、CF旨涝、OF、PF侣背、SF和ZF白华,該指令的功能是把源操作數(shù)和進位標志位CF的值(0/1)一起加到目的操作數(shù)中。
實驗
MOV AL,1
MOV CL,2
ADC AL,CL //按照我們正常的ADD指令贩耐,此時AL中應(yīng)該是3
// 但是ADC指令是帶進位的加法,它會把c位中的值也給加上弧腥。
// 如果此時cf中的值是1,那結(jié)果:AL中的值是4潮太,cf的值:0
注意事項:1.兩邊
SBB指令:帶借位減法
百度百科的解釋很明確
SBB:帶借位減法管搪, 格式:SBB DST,SRC, 執(zhí)行的操作:(DST)←(DST)-(SRC)-CF,其中CF為進位的值虾攻。 SBB Compents :他們組成了Application .他們以何種方式組合是由SLEE來確定的。
實驗
MOV AL,3
MOV CL,1
SBB AL,CL
// 分兩種情況:
// 1. 如果cf是0更鲁,那么結(jié)果和我們預想的一樣霎箍,2
// 2. 如果cf是1,那么結(jié)果還會減1澡为,結(jié)果al變?yōu)?了
XCHG指令:交換數(shù)據(jù)
百度百科
交換指令XCHG是兩個寄存器漂坏,寄存器和內(nèi)存變量之間內(nèi)容的交換指令,兩個操作數(shù)的數(shù)據(jù)類型要相同媒至,可以是一個字節(jié)顶别,也可以是一個字,也可以是雙字
說明什么塘慕?
我們交換的是兩個容器炒嘲,不能是立即數(shù)
而且交換的兩個容器不能都是內(nèi)存
// 實驗:
MOV AL,1
MOV CL,3
XCHG AL,CL // AL變成3贬养,CL變成了1
XCHG DWORD PTR DS:[0X0019FF74],EAX
MOVS指令:移動數(shù)據(jù)
看了一下通用寄存器中EDI和ESI的分工:
再回顧一下通用寄存器的劃分:
https://xuxiaofeng.gitlab.io/2018/12/12/study-%E7%BC%96%E7%A8%8B%E8%BE%BE%E4%BA%BA-%E6%BB%B4%E6%B0%B4%E9%80%86%E5%90%913%E6%9C%9F%E5%AD%A6%E4%B9%A0-2018-12-12-%E8%BF%9B%E4%B8%80%E6%AD%A5%E5%AD%A6%E4%B9%A0%E5%AF%84%E5%AD%98%E5%99%A8/
現(xiàn)在我們來解釋MOVS指令
movs指令是用來復制一個數(shù)據(jù)項(字節(jié),字或雙字)從源字符串到目標字符串需纳。原字符串又ESI/SI/DH 指出骗随,目標字符串又EDI/DI/BH指出蛤织。(具體又那個指出,我們需要看使用時定義的單位)
這里還有一段解釋:
MOVS指令可以把由(SI)指向的數(shù)據(jù)段中的一個字(或字節(jié))傳送到由(DI)指向的附加段中的一個字(或字節(jié))中去鸿染,同時根據(jù)方向標志(df標志寄存器)及數(shù)據(jù)格式(字 或字節(jié))對SI和DI進行修改
在執(zhí)行該指令前指蚜,應(yīng)該先做好以下 準備工作:
1) 把存放于數(shù)據(jù)段中的源串首地址(如反向傳送則應(yīng)是末地址)放入SI寄存器中;
2) 把將要存放數(shù)據(jù)串的附加段中的目的串首地址(或反向傳送時的末地址)放入DI寄存器中涨椒;
3) 建立方向標志摊鸡。
實驗
首先說明一下,我們之前碰到內(nèi)存的時候蚕冬,我們總是這樣表示DS:[],沒錯免猾。但是碰到EDI表示內(nèi)存地址單元時,我們應(yīng)該這樣ES:[],所以往下囤热,我們會經(jīng)沉蕴幔看到這樣的字符:ES:[EDI] (這里涉及到段、頁的概念)
1.直接輸入movs旁蔼,點擊確定锨苏,編輯器就會自動給我們生成下面的額語句
充分說明了這個指令是針對EDI和ESI的
MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
mov edi,0019ff88
mov esi,0019ff80
MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
結(jié)果
edi:0019ff8c
esi:0019ff84
并且剛才edi對應(yīng)內(nèi)存編號中的值和dsi對應(yīng)內(nèi)存編號中的值確實做了交換
我們發(fā)現(xiàn)EDI和ESI中的值都+4 了。這是有D位(df標志寄存器決定的)
所以這個MOVS
指令有兩個主要影響棺聊,一是真的交換了寄存器對應(yīng)內(nèi)存地址單元中的值伞租,二是根據(jù)DF標志寄存器中的值,讓ESI和EDI都進行一些位移限佩。
STOS指令:講Al/AX/EAX的值存儲到[EDI]指定的內(nèi)存單元
到底是復制AL還是AX還是EAX葵诈,是又我們指定的內(nèi)存寬度決定的
。復制完畢后,EDI的變化方向是由我們的D位(df標志寄存器)決定的驯击。
// 實驗
mov eax,12345678
mov edi,0019ff88
直接數(shù)據(jù)stos烁兰,確定酒水彈出下面的值
STOS DWORD PTR ES:[EDI]
運行結(jié)果(D位此時是0)
DEI:0019FF8C
內(nèi)存單元0019FF88中的值:12345678
REP指令:按計數(shù)寄存器 (ECX) 中指定的次數(shù)重復執(zhí)行字符串指令
這里有一個把movs和rep指令糅合在一起的解釋
MOVS指令可以把由(SI)指向的數(shù)據(jù)段中的一個字(或字節(jié))傳送到由(DI)指向的附加段中的一個字(或字節(jié))中去,同時根據(jù)方向標志及數(shù)據(jù)格式(字 或字節(jié))對SI和DI進行修改徊都。當該指令與前綴REP聯(lián)用時沪斟,則可將數(shù)據(jù)段中的整串數(shù)據(jù)傳送到附加段中去。這里源串必須在數(shù)據(jù)段中暇矫,目的串必須在附加段 中主之,但源串允許使用段跨越前綴來修改。在與REP聯(lián)用時還必須先把數(shù)據(jù)串的長度送到CX寄存器中李根,以便控制指令結(jié)束槽奕。因此在執(zhí)行該指令前,應(yīng)該先做好以下 準備工作:
1) 把存放于數(shù)據(jù)段中的源串首地址(如反向傳送則應(yīng)是末地址)放入SI寄存器中房轿;
2) 把將要存放數(shù)據(jù)串的附加段中的目的串首地址(或反向傳送時的末地址)放入DI寄存器中粤攒;
3) 把數(shù)據(jù)串長度放入CX寄存器;
4) 建立方向標志囱持。
在完成這些準備工作后就可使用串指令傳送信息了
MOV ECX,10
REP MOVSD
REP STOSD