[英]Arithmetic identities and EFLAGS
因為 −x = not(x)+1 意味着 ab = a+not(b)+1,所以
sub rax, rcx
相當於
mov temp, rcx
not temp
add rax, temp
add rax, 1
某些寄存器在哪里 temp 被認為是易失性的?
換句話說,后者是否以完全相同的方式影響 EFLAGS? 如果不是,怎么能被迫?
不,它們不相等。 例如,如果rax = 1
和rcx = 3
,則sub rax, rcx
將設置進位標志,因為您正在從較小的數字中減去較大的數字。 但是在您的第二個指令序列中,在add rax, temp
之后, rax
將包含-3
(即0xfffffffffffffffd
),並且將1
添加到-3
不會導致進位。 所以在你的第二個指令序列之后,進位標志將被清除。
我不知道有任何簡單的方法可以精確地模擬sub
的行為,包括它對標志的影響(除了使用cmp
,但那是作弊,因為它實際上只是sub
在引擎蓋下)。 原則上,您可以編寫一長串指令,手動執行sub
內部執行的所有相同測試(參考指令集手冊中的精確描述),並在末尾使用sahf
或popf
之類的設置標志。
這將是很多工作,特別是如果您不打算使用cmp
,並且我不會通過它 go 來回答這個問題。 尤其是因為我也想不出任何理由需要這樣做,除了作為一項相當無意義的練習。
是的,在 RAX 中得到相同的 integer 結果。
換句話說,后者是否以完全相同的方式影響 EFLAGS?
當然不是。 ZF、SF 和 PF 僅取決於 integer 結果,但CF 和 OF 1取決於您如何到達那里。 x86 的 CF 進位標志是從減法中借用 output。 (與某些 ISA 不同,例如 ARM,如果沒有借位,減法會設置進位標志。)
您可以在腦海中檢查一個簡單的反例:
0 - 1
, sub
集 CF=1。 但是您的方式清除了CF。
mov temp, rcx # no effect on FLAGS
not temp # no effect on FLAGS, unlike most other x86 ALU instructions
add rax, ~1 = 0xFF..FE # 0 + anything clears CF
add rax, 1 # 0xFE + 1 = 0xFF..FF = -1. clears CF
(有趣的事實: not
不會影響 FLAGS,不像大多數其他 ALU 指令,包括neg
。 neg
設置標志與sub
從0
相同。x86 歷史的一個奇怪怪癖。https://www.felix#cloutier.com/x86/not標志影響)
腳注 1:AF 也是如此,它是低字節中從低半字節到高半字節的半進位標志(輔助)。 您不能直接對其進行分支,並且 x86-64 刪除了讀取它的像aaa
這樣的 BCD 指令,但它仍然存在於 RFLAGS 中,您可以使用pushf
/ pop rax
讀取它。
如果不是,怎么能被迫?
使用不同的指令。 在 EFLAGS 上獲得所需效果的最簡單和最有效的方法是將其優化回sub rax, rcx
。 這就是為什么 x86 有sub
和sbb
指令的原因。 如果那是您想要的,請使用它。
如果你想要一個替代方案,你肯定需要避免像add rax,1
作為最后一步。 僅當最終結果為零時才會設置 CF,從 ULONG_MAX = -1 開始。
在大多數情況下,將x -= y
作為x += -y
適用於 OF。 (但不是最負數y=LONG_MIN
( 1UL<<63
),其中neg rcx
會溢出)。
但是 CF 告訴你 64 + 64 位加法或減法的 65 位完整結果。 64 位否定是不夠的: x += -y
並不總是將 CF 設置為與x -= y
的相反。
可能涉及neg
/ sbb
的東西可能有用嗎? 但是不,這將否定的執行視為 -0 / -1,而不是-(1<<64)
。
# Broken attempt that fails for CF when rcx=0 at least, probably many more cases.
# Also fails for OF for rcx=0x8000000000000000 = LONG_MIN
mov temp, rcx # no effect on FLAGS
neg temp # or NOT + INC if you insist on avoiding sub-like operations
add rax, temp # x += -y
cmc # complement carry. CF = !CF
請注意,我們在一個步驟中組合了 x 和 y。 您在較早的 CF 結果的末尾add rax, 1
,使 CF 成為您想要的結果的可能性甚至更低。
有符號溢出 (OF) 有一個極端情況。 大多數輸入都是相同的,其中帶符號的算術運算對於x -= y
或x += -y
是相同的。 但是如果-y
溢出仍然是負數([最負的 2 的補數][1] 沒有倒數),它是加一個負數而不是減去一個負數。
例如-LONG_MIN == LONG_MIN
因為有符號溢出。 (C 表示法;有符號溢出是 ISO C 中的 UB,但在 asm 中它會換行)。
CF 嘗試的反例:
-1 - 0
不借,所以 CF=0。 -1 + -0
= -1 + 0
也不進位,然后 CMC 會將 CF 翻轉為 1
但是-1
( 0xff...ff
) 加上任何其他數字會執行,而-1
減去任何數字不會。
所以要准確模擬sub
的借用output並不容易,而且可能不是很有趣。
請注意,硬件 ALU 經常使用二進制 [加法器-減法器][2] 之類的東西,它以進位/借位感知方式將A
或~A
多路復用作為全加器的輸入,以正確實現A + B
或A - B
借用 output 做減法。
[1]: https://en.wikipedia.org/wiki/Two%27s_complement#:~:text=The%20two's%20complement%20of%20the%20most%20negative%20number%20representable%20(例如,%C2% A7%20Most%20negative%20number%20below. [2]: https://en.wikipedia.org/wiki/Adder%E2%80%93subtractor
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.