1

I m playing with open source which contains the following code

uint32_t addr = htonl(* (uint32_t *)RTA_DATA(rth));
if (htonl(13) == 13) {
    // running on big endian system
} else {
    // running on little endian system
    addr = __builtin_bswap32(addr);
}

It looks like it check if the system is a big endian or little endian with if (htonl(13) == 13). is it correct? and could you please explain why the check this in this way? and why he use 13?

Also the addr = __builtin_bswap32(addr); cause a compilation problem "undefined reference". Are there a solution to fix that? it looks like that function does not exist any more in the new versions of the gcc libs. is it correct?

EDIT:

The toolchain I use is toolchain-i386_gcc-4.1.2_uClibc-0.9.30.1

for the options I used in the compilation:

  • for the c to object compilation options:

    -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -I. -I/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/usr/include -O2 -pipe -march=i486 -funit-at-a-time -fhonour-copts -D_GNU_SOURCE -MT

  • for the object to binary (linker)

    -O2 -pipe -march=i486 -funit-at-a-time -fhonour-copts -D_GNU_SOURCE -L/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/usr/lib -L/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/lib -L/opt/lampp/htdocs/backfire/staging_dir/toolchain-i386_gcc-4.1.2_uClibc-0.9.30.1/lib -Wl,-rpath-link=/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/usr/lib

MOHAMED
  • 41,599
  • 58
  • 163
  • 268
  • What compiler, and what compiler was the code actually written for? – Mats Petersson Feb 05 '13 at 17:56
  • it's toolchain-i386_gcc-4.1.2_uClibc-0.9.30.1 – MOHAMED Feb 05 '13 at 17:58
  • And what compiler options? – Mats Petersson Feb 05 '13 at 17:58
  • for the object to binary (linker) `-O2 -pipe -march=i486 -funit-at-a-time -fhonour-copts -D_GNU_SOURCE -L/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/usr/lib -L/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/lib -L/opt/lampp/htdocs/backfire/staging_dir/toolchain-i386_gcc-4.1.2_uClibc-0.9.30.1/lib -Wl,-rpath-link=/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/usr/lib` – MOHAMED Feb 05 '13 at 18:03
  • for the c to object compilation options: `-DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -I. -I/opt/lampp/htdocs/backfire/staging_dir/target-i386_uClibc-0.9.30.1/usr/include -O2 -pipe -march=i486 -funit-at-a-time -fhonour-copts -D_GNU_SOURCE -MT` – MOHAMED Feb 05 '13 at 18:06
  • Don't see anything directly wrong there. – Mats Petersson Feb 05 '13 at 18:09
  • NO. the options are generated automatically by the platform OpenWRT. – MOHAMED Feb 05 '13 at 18:11
  • Yes, just checking - there is a "-fno-builtin" or some such - and checking the obvious is always a good start... – Mats Petersson Feb 05 '13 at 18:14
  • I just tried adding `int x = __builtin_swap32(something);` into an existing program of mine, and it works fine. Of course, I have gcc 4.6.3, but I don't think that should make any huge difference, these have been part of gcc for quite a few years now. – Mats Petersson Feb 05 '13 at 18:16

1 Answers1

2

htonl converts a "host-order" number to network byte order. Host order is whatever endianness you have on the system running the code. Network byte order is big-endian. If host-to-network is big-to-big, that means no change -- which is what 13 -> 13 would verify. On the other hand, if host-to-network is small-to-big, that means you'll get swapping, so the least-significant byte 13 (least because changing it by 1 changes the overall number only by 1) would become most-significant-byte 13 (most because changing that byte by one changes the overall number by the largest amount), and 13 -> (13 << 24).

13 specifically is unimportant. You could use any number, so long as its little-endian representation wasn't the same as its big-endian representation. (0 would be bad, because 0 byte-swapped is still 0. Same for (65536 + 256) as well, because the 32-bit representation is 00 01 01 00 in both big-endian and little-endian.

Note that there are also mixed-endian systems where for the 32-bit number 0x12345678, you'd have bytes not in the order 12 34 56 78 (big-endian) or 78 56 34 12 (little-endian): 34 12 78 56 for one, I believe. These systems aren't common, but they do still exist, and the code here wouldn't handle them correctly.

http://gcc.gnu.org/onlinedocs/gcc-4.2.0/gcc/Other-Builtins.html and http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Other-Builtins.html suggest __builtin_bswap32 was added in gcc 4.3, so your gcc 4.1.2 toolchain wouldn't have it.

Jeff Walden
  • 7,008
  • 2
  • 38
  • 55