21 Mar 2006 (updated 21 Mar 2006 at 10:51 UTC)
»
On byte swapping and endianess
I have seen various implementations of htonl(). Most of them look like ...
(x >>
24) | ((x & 0xff0000) >> 8) | (( x & 0xff00) << 8)
| (x << 24);
Let's restrict ourselves to the M$ VC++ 6 32 bit machine and see what
the compiler makes of that htonl() implementation..
F:\maya\misc>cl
Microsoft (R) 32-bit C/C++ Standard Compiler Version 12.00.8168 for
80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
F:\maya\misc>cat htonl.c
int htonl(int x)
{
return (x >> 24) | ((x & 0xff0000) >> 8) | (( x
& 0xff00) << 8) | (x << 24);
}
Now we ask the compiler to show us the (un-optimised) assembly for this
file
F:\maya\misc>cl /c /Fa htonl.c
F:\maya\misc>more htonl.asm
/** _snip_ **/
; File htonl.c
; Line 2
push ebp
mov
ebp, esp
; Line 3
mov eax, DWORD PTR _x$[ebp]
sar
eax,
24
; 00000018H
mov
ecx, DWORD PTR _x$[ebp]
and
ecx,
16711680
; 00ff0000H
sar
ecx, 8
or eax, ecx
mov
edx, DWORD PTR _x$[ebp]
and
edx,
65280
; 0000ff00H
shl
edx, 8
or eax, edx
mov
ecx, DWORD PTR _x$[ebp]
shl
ecx,
24
; 00000018H
or eax, ecx
; Line 4
pop
ebp
ret 0
_htonl ENDP
_TEXT ENDS
END
That seems like a lot of stuff for endianness conversion. Now let's see
if a little bit of inline assembly can't fix this ..
F:\maya\misc>cat htonl.c
int htonl(int j)
{
_asm
{
mov eax, j
bswap eax
}
}
And the assembly for this is ...
F:\maya\misc>more htonl.asm
/** snip **/
; File htonl.c
; Line 2
push ebp
mov
ebp, esp
push ebx
push esi
push edi
; Line 5
mov
eax, DWORD PTR _j$[ebp]
; Line 6
bswap eax
; Line 8
pop
edi
pop
esi
pop
ebx
pop
ebp
ret 0
_htonl ENDP
_TEXT ENDS
END
So, the assembly is neater and smaller. If you ignore all the pushes
and pop's need to make that inline assembly work, you will see that
the main brunt of the work is done by the *bswap* instruction which
takes 1 to 3 cycles for all the dirty work.