組合語言與 CPU
旗標/狀態暫存器
當你把兩個數相減時,你往往跟答案一樣在意那些附帶事實:結果是零嗎?變成負的了嗎?數值有沒有環繞超過它能容納的最大值?旗標暫存器正是 CPU 記錄這些附帶事實的地方。它是一個特殊暫存器,其中各個位元——也就是旗標——各自回報最近一次算術或比較的某件事。
有幾個旗標時時刻刻都重要。零旗標在上一次結果剛好為零時被設定。符號旗標複製結果的符號位元(結果為負時設定,依二補數來看)。進位旗標捕捉無號溢位——從最高位元進位或借位出去。溢位旗標捕捉有號溢位。關鍵在於:程式要問「a 等於 b 嗎」這類問題的方法,是用 cmp 指令算 a - b,這會設定這些旗標但丟棄結果,接著執行一個只看旗標的條件分支。je(相等就跳)在零旗標被設定時分支;jl、jg、jne 等各自測試某種旗標組合。
這套兩步舞——先設旗標、再依旗標分支——正是每個 if、while、for 的條件編譯後的樣子。它也說明了為什麼有號與無號比較使用不同的分支指令:它們查詢不同的旗標(有號用 jl/jg,依符號與溢位旗標;無號用 jb/ja,依進位旗標)。在手寫或閱讀組合語言時把這個配對弄錯,是經典的錯誤來源。
cmp eax, ebx 僅為了設定旗標而計算 eax - ebx;緊接著的 je target 恰在 eax == ebx(零旗標被設定)時分支過去。
比較會設定旗標並丟棄結果;條件分支只讀旗標。
旗標只反映最近一次會設定旗標的指令;中間插進一條無關卻會更動旗標的指令就會改變它們,所以 cmp 必須緊接在依賴它的分支之前。並非每條指令都更新旗標——例如單純的 mov 就不動它們。
又稱
另見