assembly - What's the purpose of "AND AL,0xFF"? -
i'm reading through disassembled win32 c++ program , see quite few:
and al,0xff
is pointless or why compiler generate these?
here longer example:
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 , al, 0ffh # <---- sar edx, 8 , cl, 0ffh # <---- mov [esi], cl , 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
the flags aren't being checked after these operations can't purpose. after and
, values in al
, cl
, , dl
being moved [esi + n]
.
as @fuz suggested, fault of optimizer not recognizing foo & 0xff
being no-op in context in used in original function.
i compiled following code snippet borland c++ builder 6 after setting project's compilation settings "release" :
unsigned char foobar(int foo) { return (foo >> 16) & 0xff; }
this resembles operations carried out in disassembly provided quite closely. have 32-bit value want shift given number of bits , turn byte value, returning bits 16-23 of original value 1 byte. input parameter of type int
in order generate sar
instruction instead of shr
: int
used in original code well.
after compiling , disassembling resulting .obj objconv (as couldn't figure out how enable assembly listings within c++ builder's ide), got :
@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 , al, 0ffffffffh ; 0009 _ 24, ff pop ebp ; 000b _ 5d ret ; 000c _ c3 @foobar$qi endp
as can see, redundant and
still there. 32-bit immediate in disassembly can disregarded, since instruction's encoding shows immediate in actual code stream 8-bit : there no other valid options 8-bit register anyway.
microsoft visual studio c++ 6 seems guilty of same thing, operates on whole 32-bit register (thus generating 3 bytes more due 32-bit immediate), clearing upper bits - needless, seeing how return value of function explicitly declared 8-bit :
?foobar@@yaeh@z 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 , eax, 255 ; 000000ffh 0000e 5d pop ebp 0000f c3 ret 0 ?foobar@@yaeh@z endp ; foobar
meanwhile, the oldest version of gcc available on godbolt correctly compiles what's shift, except natural differences between listings due calling conventions.
Comments
Post a Comment