2016-11-16 48 views
0

我已經拆卸由編譯器產生的代碼,我看到它已經產生的指令序列如下:爲什麼編譯器在除以2時產生右移31位?

mov  eax, edx 
shr  eax, 1Fh 
add  eax, edx 
sar  eax, 1 

這是什麼代碼的目的是什麼?


我知道

sar  eax, 1 

除以2,但到底是什麼

shr  eax, 1Fh 

嗎?這是否意味着EAX將是0或1,如果左邊的位是0或1?

這看起來很奇怪!有人可以解釋嗎?

回答

2

您的問題的快速回答是什麼shr eax, 1Fh它是用來隔離eax的最高位。如果將十六進制1Fh轉換爲十進制31,則可能會更容易理解。現在,你看到你正在將eax右移31位。由於eax是一個32位的值,因此將其右移31將會隔離最高位,使得eax將包含0或1,具體取決於原始值是位31(假設我們用0開始編碼位)。

這是隔離符號位的常用技巧。當一個值在二進制補碼機上解釋爲有符號整數時,最高位是符號位。如果值爲負值,則設置爲(== 1),否則設置爲(== 0)。當然,如果該值被解釋爲無符號整數,則最高位是用於存儲其值的另一位,因此最高位具有任意值。


去一行行通過拆解,下面的代碼做什麼:

mov  eax, edx 

顯然,輸入是EDX。此說明將EDX的值複製到EAX中。這允許後續代碼操縱EAX中的值而不會丟失原始值(在EDX中)。

shr  eax, 1Fh 

EAX右移31位,從而隔離最高位。假設輸入值是一個有符號整數,這將是符號位。如果原始值爲負,則EAX現在包含1,否則爲0。

add  eax, edx 

原始值(EDX)添加到我們的暫定值EAX。如果原始值爲負數,則會將1加1。否則,它會加0。

sar  eax, 1 

EAX右移1位。這裏的區別是這是一個算術右移,而SHR是一個邏輯右移。邏輯移位用0填充新暴露的位。算術移位將最高位(符號位)複製到新暴露的位。


全部放在一起,這是用於將一個符號整數值2,以確保負值被正確四捨五入標準成語。

如果將的無符號值除以2,則只需要一個簡單的位移。因此:

unsigned Foo(unsigned value) 
{ 
    return (value/2); 
} 

等同於:

shr eax, 1 

但將一個符號的值時,你必須處理的符號位。你可以用sar eax, 1來實現一個2的有符號整數除法,但這會導致結果值向負無窮大取整。請注意,這與指令的行爲不同,該指令始終向零調整。如果你想模擬round-to-zero行爲,你需要一些特殊的處理,這正是你的代碼所做的。

int Foo(int value) 
{ 
    return (value/2); 
} 

這是一個非常招:其實,GCC,鐺,MSVC的,大概每隔編譯器都會在編譯下面的函數生成正是這種代碼。 Michael Abrash在其彙編語言,,大約,1990.(Here is the relevant section在他的書的在線副本)中發表的10中討論過。在這之前,彙編語言專家當然是共同的知識。

相關問題