tannerwj
tannerwj

Reputation: 154

Best way to convert a Little Endian four byte long integer to Big Endian, or vice versa in x86 Assembly

So I figured out how to reverse the endianess of a four byte long int in C:

unsigned int swapWord (unsigned int n){
   return (n>>24) | ((n<<8) & 0x00FF0000) |((n>>8) & 0x0000FF00) | (n<<24);
}

Now I know I can just disassemble this, and I did, and it was decent code, but I'm sure there is a more efficient way to reverse the endianess. Any ideas?

Edit: Here's the disassembled code:

00000000004005a3 <swapWord>:
      4005a3:   55                      push   %rbp
      4005a4:   48 89 e5                mov    %rsp,%rbp
      4005a7:   89 7d fc                mov    %edi,-0x4(%rbp)
      4005aa:   8b 45 fc                mov    -0x4(%rbp),%eax
      4005ad:   c1 e8 18                shr    $0x18,%eax
      4005b0:   89 c2                   mov    %eax,%edx
      4005b2:   8b 45 fc                mov    -0x4(%rbp),%eax
      4005b5:   c1 e0 08                shl    $0x8,%eax
      4005b8:   25 00 00 ff 00          and    $0xff0000,%eax
      4005bd:   09 c2                   or     %eax,%edx
      4005bf:   8b 45 fc                mov    -0x4(%rbp),%eax
      4005c2:   c1 e8 08                shr    $0x8,%eax
      4005c5:   25 00 ff 00 00          and    $0xff00,%eax
      4005ca:   09 c2                   or     %eax,%edx
      4005cc:   8b 45 fc                mov    -0x4(%rbp),%eax
      4005cf:   c1 e0 18                shl    $0x18,%eax
      4005d2:   09 d0                   or     %edx,%eax
      4005d4:   5d                      pop    %rbp
      4005d5:   c3                      retq   
      4005d6:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
      4005dd:   00 00 00 

Upvotes: 2

Views: 3552

Answers (1)

Brendan
Brendan

Reputation: 37222

For 80486 and later, there's an instruction called bswap that swaps bytes in a dword.

For older 80386 CPUs I'd be tempted to use something like this:

                     ;eax = 0xAABBCCDD
    xchg ah,al       ;eax = 0xAABBDDCC
    rol eax,16       ;eax = 0xDDCCAABB
    xchg ah,al       ;eax = 0xDDCCBBAA

For even older CPUs (8086 to 80286) you have to use a pair of 16-bit registers (as there are no 32-bit registers), and it ends up like this:

                     ;dx:ax = 0xAABBCCDD
                     ;ax:dx = 0xCCDDAABB
    xchg ah,al       ;ax:dx = 0xDDCCAABB
    xchg dh,dl       ;ax:dx = 0xDDCCBBAA

Note: Instead of using xchg ah,al you could use either ror ax,8 or rol ax,8. I doubt it makes much difference which of these 3 instructions you use.

Upvotes: 5

Related Questions