2017-07-27 77 views
3

我通過拆卸win32的C++程序讀,我看到不少:「AND AL,0xFF」的用途是什麼?

AND AL,0xFF 

這是完全沒有意義的,或者爲什麼會編譯器生成這些?

這是一個較長的例子:

movsx eax, byte ptr [ebx] 
shl  eax, 18h 
movsx edx, byte ptr [ebx+1] 
shl  edx, 10h 
add  eax, edx 
movsx ecx, byte ptr [ebx+2] 
shl  ecx, 8 
add  eax, ecx 
movsx edx, byte ptr [ebx+3] 
add  eax, edx 
xor  edx, edx 
call sub_43B55C 
mov  ecx, eax 
mov  edx, eax 
sar  ecx, 10h 
and  al, 0FFh  # <---- 
sar  edx, 8 
and  cl, 0FFh  # <---- 
mov  [esi], cl 
and  dl, 0FFh  # <---- 
mov  [esi+1], dl 
mov  [esi+2], al 
add  ebx, 4 
add  esi, 3 
inc  ebp 
cmp  ebp, 6 
jl  short loc_43B5E4 

標誌不能被這些操作之後檢查以致不能成爲目的。在AND之後,AL,CLDL中的值正被移至[ESI + n]

+2

不知道之前發生了什麼,很難說。假設EAX是一個指針,它需要在一個16字節的邊界上對齊。這將設置ZF爲真,因此指令的要點是設置標誌。或者,如果編譯器設置適當,可能會使用'test al,0xff'。 –

+0

感謝您的評論。標誌沒有被檢查。 ANDing似乎在將字節移到內存之前發生。我使用周圍的代碼更新了上下文。 – user35358

+3

似乎很奇怪。也許這條指令是用於填充或作爲鉤子的標記。 – fuz

回答

4

正如@fuz所建議的那樣,這只是優化程序不認識到foo & 0xff是在原始函數中最可能使用的上下文中沒有操作的錯誤。

我編譯下面的代碼片段與Borland C++ Builder中6設置項目的編譯設置,以「釋放」後:

unsigned char foobar(int foo) { return (foo >> 16) & 0xff; } 

這類似於操作中你頗有淵源提供的拆卸進行。我們有一個32位的值,我們想要移位一個給定的位數,然後把它變成一個字節值,基本上將原始值的16-23位作爲一個字節返回。輸入參數的類型爲int,以便生成sar指令而不是shr:在原始代碼中最有可能還使用了int

編制,並與objconv拆卸造成的obj(因爲我無法弄清楚如何實現從C++ Builder的IDE內彙編清單)後,我得到這個:

@foobar$qi PROC NEAR 
; COMDEF @foobar$qi 
     push ebp          ; 0000 _ 55 
     mov  ebp, esp        ; 0001 _ 8B. EC 
     mov  eax, dword ptr [ebp+8H]     ; 0003 _ 8B. 45, 08 
     sar  eax, 16         ; 0006 _ C1. F8, 10 
     and  al, 0FFFFFFFFH       ; 0009 _ 24, FF 
     pop  ebp          ; 000B _ 5D 
     ret            ; 000C _ C3 
@foobar$qi ENDP 

正如你所看到的,多餘的and仍然存在。反彙編中的32位立即數可以忽略不計,因爲指令的編碼清楚地表明實際碼流中的立即數是8位:無論如何8位寄存器沒有其他有效選項。

Microsoft Visual Studio C++ 6似乎有同樣的問題,但在整個32位寄存器上運行(因此由於32位立即產生更多3個字節),清除高位 - 這是不必要的,參觀瞭解函數的返回值被明確宣佈爲8位:

[email protected]@[email protected] PROC NEAR        ; foobar 
; 1 : unsigned char foobar(int foo) { return (foo >> 16) & 0xff; } 
    00000 55    push ebp 
    00001 8b ec   mov  ebp, esp 
    00003 8b 45 08   mov  eax, DWORD PTR _foo$[ebp] 
    00006 c1 f8 10   sar  eax, 16      ; 00000010H 
    00009 25 ff 00 00 00 and  eax, 255    ; 000000ffH 
    0000e 5d    pop  ebp 
    0000f c3    ret  0 
[email protected]@[email protected] ENDP         ; foobar 

同時,the oldest version of gcc available on godbolt正確編譯成什麼本質上只是一個轉變,但由於調用約定的清單之間的自然差異這一點。