簡體   English   中英

算術恆等式和 EFLAGS

[英]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 = 1rcx = 3 ,則sub rax, rcx將設置進位標志,因為您正在從較小的數字中減去較大的數字。 但是在您的第二個指令序列中,在add rax, temp之后, rax將包含-3 (即0xfffffffffffffffd ),並且將1添加到-3不會導致進位。 所以在你的第二個指令序列之后,進位標志將被清除。

我不知道有任何簡單的方法可以精確地模擬sub的行為,包括它對標志的影響(除了使用cmp ,但那是作弊,因為它實際上只是sub在引擎蓋下)。 原則上,您可以編寫一長串指令,手動執行sub內部執行的所有相同測試(參考指令集手冊中的精確描述),並在末尾使用sahfpopf之類的設置標志。

這將是很多工作,特別是如果您不打算使用cmp ,並且我不會通過它 go 來回答這個問題。 尤其是因為我也想不出任何理由需要這樣做,除了作為一項相當無意義的練習。

是的,在 RAX 中得到相同的 integer 結果。

換句話說,后者是否以完全相同的方式影響 EFLAGS?

當然不是。 ZF、SF 和 PF 僅取決於 integer 結果,但CF 和 OF 1取決於您如何到達那里 x86 的 CF 進位標志是從減法中借用 output。 (與某些 ISA 不同,例如 ARM,如果沒有借位,減法會設置進位標志。)

您可以在腦海中檢查一個簡單的反例:
0 - 1sub集 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 指令,包括negneg設置標志與sub0相同。x86 歷史的一個奇怪怪癖。https://www.felix#cloutier.com/x86/not標志影響

腳注 1:AF 也是如此,它是低字節中從低半字節到高半字節的半進位標志(輔助)。 您不能直接對其進行分支,並且 x86-64 刪除了讀取它的像aaa這樣的 BCD 指令,但它仍然存在於 RFLAGS 中,您可以使用pushf / pop rax讀取它。

如果不是,怎么能被迫?

使用不同的指令。 在 EFLAGS 上獲得所需效果的最簡單和最有效的方法是將其優化回sub rax, rcx 這就是為什么 x86 有subsbb指令的原因。 如果那是您想要的,請使用它。


如果你想要一個替代方案,你肯定需要避免像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 -= yx += -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 + BA - 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM