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
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.
Related
Sample Code
#include "stdio.h"
#include <stdint.h>
int main()
{
double d1 = 210.01;
uint32_t m = 1000;
uint32_t v1 = (uint32_t) (d1 * m);
printf("%d",v1);
return 0;
}
Output
1. When compiling with -m32 option (i.e gcc -g3 -m32 test.c)
/test 174 # ./a.out
210009
2. When compiling with -m64 option (i.e gcc -g3 -m64 test.c)
test 176 # ./a.out
210010
Why do I get a difference?
My understanding "was", m would be promoted to double and multiplication would be cast downward to unit32_t. Moreover, since we are using stdint type integer, we would be further removing ambiguity related to architecture etc etc.
I know something is fishy here, but not able to pin it down.
Update:
Just to clarify (for one of the comment), the above behavior is seen for both gcc and g++.
I can confirm the results on my gcc (Ubuntu 5.2.1-22ubuntu2). What seems to happen is that the 32-bit unoptimized code uses 387 FPU with FMUL opcode, whereas 64-bit uses the SSE MULS opcode. (just execute gcc -S test.c with different parameters and see the assembler output). And as is well known, the 387 FPU that executes the FMUL has more than 64 bits of precision (80!) so it seems that it rounds differently here. The reason of course is that that the exact value of 64-bit IEEE double 210.01 is not that, but
210.009999999999990905052982270717620849609375
and when you multiply by 1000, you're not actually just shifting the decimal point - after all there is no decimal point but binary point in the floating point value; so the value must be rounded. And on 64-bit doubles it is rounded up. On 80-bit 387 FPU registers, the calculation is more precise, and it ends up being rounded down.
After reading about this a bit more, I believe the result generated by gcc on 32-bit arch is not standard conforming. Thus if you force the standard to C99 or C11 with -std=c99, -std=c11, you will get the correct result
% gcc -m32 -std=c11 test.c; ./a.out
210010
If you do not want to force C99 or C11 standard, you could also use the -fexcess-precision=standard switch.
However fun does not stop here.
% gcc -m32 test.c; ./a.out
210009
% gcc -m32 -O3 test.c; ./a.out
210010
So you get the "correct" result if you compile with -O3; this is of course because the 64-bit compiler uses the 64-bit SSE math to constant-fold the calculation.
To confirm that extra precision affects it, you can use a long double:
#include "stdio.h"
#include <stdint.h>
int main()
{
long double d1 = 210.01; // double constant to long double!
uint32_t m = 1000;
uint32_t v1 = (uint32_t) (d1 * m);
printf("%d",v1);
return 0;
}
Now even -m64 rounds it to 210009.
% gcc -m64 test.c; ./a.out
210009
I wrote a bash script to determine the size of gcc's datatypes (e.g. ./sizeof int double outputs the respective sizes of int and double) by wrapping each of its arguments in the following P() macro and then compiling and running the code.
#define P(x) printf("sizeof(" #x ") = %u\n", (unsigned int)sizeof(x))
The problem is that this is relative slow (it takes a whole second!), especially the linking step (since compiling with -c or -S takes virtually no time, and so does running the outputted binary). One second is not really that slow by itself, but if I were to use this script in other scripts, it would add up.
Is there a faster, less roundabout way to find out what sizes gcc uses for datatypes?
You can achieve the functionality for standard types using the GCC's preprocessor only. For standard types there are predefined macros:
__SIZEOF_INT__
__SIZEOF_LONG__
__SIZEOF_LONG_LONG__
__SIZEOF_SHORT__
__SIZEOF_POINTER__
__SIZEOF_FLOAT__
__SIZEOF_DOUBLE__
__SIZEOF_LONG_DOUBLE__
__SIZEOF_SIZE_T__
__SIZEOF_WCHAR_T__
__SIZEOF_WINT_T__
__SIZEOF_PTRDIFF_T__
So, by using code like the following:
#define TYPE_TO_CHECK __SIZEOF_INT__
#define VAL_TO_STRING(x) #x
#define V_TO_S(x) VAL_TO_STRING(x)
#pragma message V_TO_S(TYPE_TO_CHECK)
#error "terminate"
you will be able to get the value of __SIZEOF_INT__ from the preprocessor itself without even starting the compilation. In your script you can define the TYPE_TO_CHECK (with -D) to whatever you need and pass it to gcc. Of course you will get some junk output, but I believe you can deal with that.
You can use the 'negative array size' trick that autoconf (see: AC_COMPUTE_INT) uses. That way, you don't need to link or execute code. Therefore, it also works when cross compiling. e.g.,
int n[1 - 2 * !(sizeof(double) == 8)];
fails to compile if: sizeof(double) != 8
The downside is, you might have to pass -DCHECK_SIZE=8 or something similar in the command line, since it might take more than one pass to detect an unusual value. So, I'm not sure if this will be any faster in general - but you might be able to take advantage of it.
Edit: If you are using gcc exclusively, I think #wintermute's comment is probably the best solution.
Here are three possible solutions.
The first one will work with any type whose size is less than 256. On my system, it takes about 0.04s (since it doesn't need headers or libraries other than the basic runtime). One downside is that it will only do one at a time, because of the small size of the output channel. Another problem is that it doesn't compensate for slow linking on some systems (notably MinGW):
howbig() {
gcc -x c - <<<'int main() { return sizeof ('$*'); }' && ./a.out
echo $?
}
$ time howbig "struct { char c; union { double d; int i[3];};}"
24
real 0m0.041s
user 0m0.031s
sys 0m0.014s
$ time howbig unsigned long long
8
real 0m0.044s
user 0m0.035s
sys 0m0.009s
If you wanted to be able to do larger types, you could get the size one byte at a time, at the cost of a couple more centiseconds:
howbig2 ()
{
gcc -x c - <<< 'int main(int c,char**v) {
return sizeof ('$*')>>(8*(**++v&3)); }' &&
echo $((0x$(printf %02x $(./a.out 3;echo $?) $(./a.out 2;echo $?) \
$(./a.out 1;echo $?) $(./a.out 0;echo $?)) ))
}
$ time howbig2 struct '{double d; long long u[12];}([973])'
101192
real 0m0.054s
user 0m0.036s
sys 0m0.019s
If you are compiling for x86, the following will probably work, although I'm not in a position to test it thoroughly on a wide variety of architectures and platforms. It avoids the link step (notoriously slow on MinGW, for example), by analyzing the compiled assembly output. (It would probably be slightly more robust to analyze the compiled object binary, but I fear that binutils on MinGW are also slow.) Even on Ubuntu, it is significantly faster:
howbig3 () {
gcc -S -o - -x c - <<< 'int hb(void) { return sizeof ('$*'); }' |
awk '$1~/movl/&&$3=="%eax"{print substr($2,2,length($2)-2)}'
}
$ time howbig3 struct '{double d; long long u[12];}([973])'
101192
real 0m0.020s
user 0m0.017s
sys 0m0.004s
Using nm with no code
Just make your thing a global variable. nm can report its size.
// getsize.c
struct foo {
char str[3];
short s; // expect padding galore...
int i;
} my_struct;
Compile but don't link, then use nm:
$ gcc -c getsize.c
$ nm getsize.o --format=posix
my_struct C 000000000000000c 000000000000000c
Note that the last column is the size (in hex), here is how we can get it:
$ nm test.o -P | cut -d ' ' -f 4
000000000000000c
# or in decimal
$ printf %d 0x`nm test.o -P | cut -d ' ' -f 4`
12
Using objdump with no code
If nm doesn't work for some reason, you can store the size itself in a global variable.
Start with this C file:
// getsize.c
struct foo { char str[3]; short s; int i; };
unsigned long my_sizeof = sizeof(struct foo);
Now we have to find the value of this variable from the object file.
$ gcc -c sizeof.c
$ objdump -Sj .data sizeof.o
test.o: file format elf64-x86-64
Disassembly of section .data:
0000000000000000 <my_sizeof>:
0: 0c 00 00 00 00 00 00 00 ........
Darn, little endian! You could write a script to parse this, but the following solution (assuming GCC extensions) will force it to always be big endian:
// getsize.c
struct foo { char str[3]; short s; int i; };
struct __attribute__ ((scalar_storage_order("big-endian"))) {
unsigned long v;
} my_sizeof = { sizeof(struct foo) };
This yields:
0000000000000000 <my_sizeof>:
0: 00 00 00 00 00 00 00 0c ........
Watch out! You can't just strip out all non-hex characters because sometimes the "...." stuff on the right will be valid ASCII. But the first one should always be a .. The following command keeps things between the : and the first ..
$ gcc -c sizeof.c
$ objdump -Sj .data sizeof.o |
sed '$!d # keep last line only
s/\s//g # remove tabs and spaces
s/.*:\([^.]*\)\..*/\1/' # only keep between : and .'
000000000000000c
If you happen to be in an IDE like VS2019, you can just type char foo[sizeof(MyType)] anywhere in the code, hover over foo and get the answer :)
I have the following tagged union in my code: https://github.com/EarlGray/SECD/blob/f2e364f84d194aea5cef9257630bf931e9f88cab/secd.h#L217
When I compile it on 64 bit Linux or OS X using gcc or clang, size of cell_t is always 32 bytes (4 * sizeof(long), as expected).
When I compile it on Linux (Ubuntu 14.04, gcc 4.8) using -m32 switch, the size is 16 bytes (as expected).
When I compile the same code on OS X (10.9.5) using either gcc (4.8) or clang (Apple 6.0) with -m32, the size is 20 bytes. I tried to debug the program and to see if there are any union cases that might use the fifth word, haven't found any. It does not depend on levels of optimization and debug information presence.
Any ideas why sizeof(cell_t) is 20 bytes?
On OS X:
sizeof(off_t) == 8
On Linux:
sizeof(off_t) == 4
You use that type in string_t. There may be other occasions of this, but that was the first that I came across.
I am working in a dev environment where we produce both 32 and 64 bit
executables. I have one application that is failing to build in 64 bit mode.
It uses inotify and includes glib.h to get the definitions for that.
I decided to see if a minimal program can cause the problem to happen and here it is.
The source for the test, glibtest.c:
#include <stdio.h>
#include <glib.h>
int
main (int argc, char ** argv)
{
printf( "hello, I am glib test.\n\n");
}
Building in 32 bit mode...
[svn/glibtest] : gcc glibtest.c -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -m32
[svn/glibtest] : a.out
hello, I am glib test.
[svn/glibtest] :
Things compile in 32 bit mode and a.out prints what one expects.
Now if one compiles in 64 bit mode the error occurs.
[svn/glibtest] : gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include glibtest.c
In file included from /usr/include/glib-2.0/glib/gasyncqueue.h:34,
from /usr/include/glib-2.0/glib.h:34,
from glibtest.c:7:
/usr/include/glib-2.0/glib/gthread.h: In function ‘g_once_init_enter’:
/usr/include/glib-2.0/glib/gthread.h:347: error: size of array ‘type name’ is negative
[svn/glibtest] :
In 64 bit mode the error points into gthread.h here...
#if defined (G_CAN_INLINE) || defined (__G_THREAD_C__)
G_INLINE_FUNC gboolean
g_once_init_enter (volatile gsize *value_location)
{
error>>> if G_LIKELY ((gpointer) g_atomic_pointer_get (value_location) != NULL)
return FALSE;
else
return g_once_init_enter_impl (value_location);
}
#endif /* G_CAN_INLINE || __G_THREAD_C__ */
Am I missing a needed header? Has anyone seen this before and found the solution? (yes, there is a similar post from a year ago that no one has answered.)
Centos 6.5, 'Linux tushar 2.6.32-431.17.1.el6.x86_64 #1 SMP Wed May 7 23:32:49 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux'
glib package is 1:1.2.10-33.el6
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
Thanks.
/usr/lib/glib-2.0/include is, generally, platform-specific. It probably contains 32 bit-specific definitions. e.g., I have the following in /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:
#define GLIB_SIZEOF_SIZE_T 8
That would probably be 4 in your version, since it seems to be the 32-bit one.
Check if you have correct glibconfig.h file in includes with proper settings for your build target (64-bit). For different targets (32 and 64 bit) you must have different glibconfig.h
A modern system:
% pacman -Q glibc gcc
glibc 2.16.0-4
gcc 4.7.1-6
% uname -sr
Linux 3.5.4-1-ARCH
A trivial program:
% < wtf.c
void main(){}
Let's do static and dynamic builds:
% gcc -o wtfs wtf.c -static
% gcc -o wtfd wtf.c
Everything looks fine:
% file wtf?
wtfd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x4b421af13d6b3ccb6213b8580e4a7b072b6c7c3e, not stripped
wtfs: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=0x1f2a9beebc0025026b89a06525eec5623315c267, not stripped
Could anybody explain this to me?
% for n in $(seq 1 10); do ./wtfd; echo $?; done | xargs
0 0 0 0 0 0 0 0 0 0
% for n in $(seq 1 10); do ./wtfs; echo $?; done | xargs
128 240 48 128 128 32 64 224 160 48
Sure, one can use int main(). And -Wmain will issue a warning (return type of ‘main’ is not ‘int’).
I'd just like to understand what is going on there.
That's EXACTLY the point.
There is no "void main()". There is ALWAYS a result value, and if you don't return one and don't do anything in your program, the return value is what happens to be in the appropiate register at program start (or specifically, whatever happens to be there when main is called from the startup code). Which can certainly depend on what the program is doing before main, such as dealing with shared libs.
EDIT: to get an idea how this can happen, try this:
int foo(void)
{
return 55;
}
void main(void)
{
foo();
}
There is no guarantee, of course, but there's a good chance that this program will have an exit code of 55, simply because that's the last value returned by some function. Just imagine that call happened before main.
To further illustrate what Christian is saying. Even though you declared void main() your process will return whatever value was previous in eax (since you are on linux x86 arch).
void main() {
asm("movl $55, %eax");
}
So now it always returns 55 b/c the above code explicitly initializes eax.
$ cc rval.c
$ ./a.out
$ echo $?
55
Again this example will only work on the current major OSs since I am assuming the calling convention. There is no reason an OS could not have a different calling convention and the return value could be somewhere else (RAM, register, whatever).