2010-10-13 248 views
13

在x86程序集中,當對有符號整數執行addsub操作時溢出標誌置位,並且對無符號整數的操作溢出時置位進位標誌。x86程序集:INC和DEC指令和溢出標誌

但是,當涉及到incdec指令時,情況似乎有所不同。根據這個websiteinc指令根本不影響進位標誌。

但是我找不到有關如何影響溢出標誌的任何信息,例如incdec

是否incdec當發生整數溢出時設置溢出標誌?這種行爲對於有符號整數和無符號整數都是一樣的嗎?

============================= 編輯 ============== ===============

好的,所以基本上這裏的一致意見是,INC和DEC應該像設置標誌一樣表現ADD和SUB,除了進位標誌。這也是它在英特爾手冊中所說的。

問題是我實際上無法在實踐中重現這種行爲,當涉及到無符號整數。

考慮下面的彙編代碼(使用GCC內聯彙編,以方便打印出結果。)

int8_t ovf = 0; 

__asm__ 
(
    "movb $-128, %%bh;" 
    "decb %%bh;" 
    "seto %b0;" 
    : "=g"(ovf) 
    : 
    : "%bh" 
); 

printf("Overflow flag: %d\n", ovf); 

在這裏,我們遞減-128帶符號的8位值。由於-128是最小的可能值,溢出是不可避免的。正如預期的那樣,這種打印出:Overflow flag: 1

但是,當我們做與無符號值相同,該行爲並不如我所料:

int8_t ovf = 0; 

__asm__ 
(
    "movb $255, %%bh;" 
    "incb %%bh;" 
    "seto %b0;" 
    : "=g"(ovf) 
    : 
    : "%bh" 
); 

printf("Overflow flag: %d\n", ovf); 

我在這裏增加一個無符號的8位值255。由於255是最大的可能值,溢出是不可避免的。但是,這會打印出:Overflow flag: 0

咦?爲什麼沒有在這種情況下設置溢出標誌?

回答

15

當操作會導致符號更改時,會設置溢出標誌。你的代碼非常接近。我能夠設置標誌與以下(VC++)代碼:

char ovf = 0; 

_asm { 
    mov bh, 127 
    inc bh 
    seto ovf 
} 
cout << "ovf: " << int(ovf) << endl; 

當BH遞增的MSB從0變化到1,使所述的被設置。

這還設置組成:記住

char ovf = 0; 

_asm { 
    mov bh, 128 
    dec bh 
    seto ovf 
} 
cout << "ovf: " << int(ovf) << endl; 

記住,處理器不會簽署和無符號數區分。當你使用2的補碼算術時,你可以有一組處理兩者的指令。如果你想測試無符號溢出,你需要使用進位標誌。由於INC/DEC不影響進位標誌,因此您需要在該情況下使用ADD/SUB。

2

除了進位標誌inc設置標誌的方式與add操作數1相同。

inc不影響進位標誌的事實非常重要。

http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-2.html#HEADING2-117

+0

除了'add'還設置溢出標誌,如果發生整數溢出,但據我所見,'inc'不會這樣做。查看我編輯的問題以瞭解彙編代碼。 – Channel72 2010-10-13 16:34:43

+3

@ Channel72你明白標記不正確。 CF表示執行MSB(最高有效字節),如'1111 1111 + 1 = 1 | 0000 0000' CF在這裏。 CF表示無效(溢出)無符號操作。 (因爲它是256,不適合'字節')。但它是非常有效的有符號操作(-1 + 1 = 0)。 OF是當進位到MSB時,如'0111 1111 + 1 = 1000 0000'這意味着有效的無符號和無效的有符號運算(127 + 8 = -128 oops,這是在簽名的情況下溢出,因爲範圍是-128; 127 ) – Andrey 2010-10-13 17:22:10

3

嘗試改變你的測試傳遞的數字,而不是硬代碼它,然後有一個循環,嘗試所有256號碼找到一個,如果有任何影響國旗。或者讓asm執行循環並在它碰到標誌時退出,或者當它繞回它開始的數字時(從0x00,0x7f,0x80或0xFF以外的地方開始)。

編輯當它從0x7F的去爲0x80

 
.globl inc 
inc: 
    mov $33, %eax 

top: 
    inc %al 
    jo done 
    jmp top 

done: 
    ret 

.globl dec 
dec: 
    mov $33, %eax 

topx: 
    dec %al 
    jo donex 
    jmp topx 

donex: 
    ret 

公司溢出。 dec從0x80到0x7F溢出,我懷疑問題在於你使用內聯彙編程序的方式。

+0

有符號和無符號整數通常是編程語言的體現,並不反映在硬件中。沒有簽署公司和無簽名公司,它只是一種類型,通用。這就是爲什麼OF存在這個指令。有些處理器通常不太好,不提供檢測無符號和有符號結果的方法。我很驚訝地發現這個功能。 – 2010-10-13 17:41:11

+0

好吧,有'mul'與'imul'和'div'與'idiv'與x86指令集 – Channel72 2010-10-13 18:04:50

+0

很好......通常加減法,inc,dec等等都不是基於符號的,因爲它沒有任何意義。 – 2010-10-13 20:31:21

0

處理器所做的是爲這些指令的結果(add,adc,dec,inc,sbb,sub)設置適當的標誌,用於有符號和無符號的情況,即每個操作的兩個不同的標誌結果。另一種方法是有兩組指令,其中一組設置帶符號相關標誌,另一組指令與無符號相關。如果發佈的編譯器在操作中使用無符號變量,它將測試進位和零(jc,jnc,jb,jbe等),如果簽名它測試溢出,符號和零(jo,jno,jg,jng,jl,jle等)。

0

CPU/ALU只能處理無符號的二進制數,然後使用OF,CF,AF,SF,ZF等來決定是否將其用作有符號數(OF) ,無符號數字(CF)或BCD編號(AF)。



關於您的問題,記得要考慮二進制數字本身,作爲無符號。

此外,溢出和OF需要3個數字:輸入數字,算術中使用的第二個數字和結果數字。

僅當第一個和第二個數字對於符號位(最高有效位)具有相同值且結果具有不同符號時,纔會激活溢出。 作中,加入2個負數產生了正數,或增加2張正數導致了負數:

if((Sign_Num1==Sign_Num2) && (Sign_Result!=Sign_Num1)) OF=1; 
else OF=0; 


對於你的第一個問題,你正在使用-128爲第一個號碼。第二個數字隱含地是由DEC指令使用的-1。所以我們真的有二進制數字0x800xFF。他們都將符號位設置爲1.結果爲0x7F,這是一個符號位設置爲0的數字。我們得到了2個具有相同符號的初始數字,並得到了不同符號的結果,因此我們指出了溢出。 -128-1導致127,因此溢出標誌被設置爲指示錯誤的簽名結果。





關於第二個問題,你正在使用255作爲第一個數字。第二個數字隱含地是INC指令使用的1。所以我們真的有二進制數字0xFF0x01。它們都有一個不同的符號位,所以不可能發生溢出(當基本上添加兩個相同符號的數字時,它只能溢出,但它不可能溢出2個不同符號的數字,因爲它們將永遠不會超出可能的簽名值)。 結果是0x00,它不會設置溢出標誌,因爲255+1,或者更確切地說,-1+1給出0,這對於有符號算術顯然是正確的。

請記住,要設置溢出標誌,要添加/減去的2個數字需要具有相同值的符號位,然後結果必須具有符號位,其值不同於它們。