The Compiler Detective - What Compiler and Options Were Used to Build This Application?
By Tim Cook on Jan 23, 2007
Performance engineers often look at improving application performance by getting the compiler to produce more efficient binaries from the same source. This is done by changing what compiler options are used. In this modern era of Open Source Software, you can often get your hands on a number of binary distributions of an application, but if you really want to roll your sleeves up, the source is there, just waiting to be compiled with the latest compiler and optimisations.
Now, it might be useful to have as a reference the compiler version and flags that were originally used on the binary distribution you tried out, or you just might be interested to know. Read on for details on the forensic tools.
What architecture was the executable compiled for?
Solaris supports 64 and 32-bit programming models on SPARC and x86. You may need to know which one an application is using - it's easy enough to find out.
$ file \*.o xxx.o: ELF 64-bit LSB relocatable AMD64 Version 1 yyy.o: ELF 32-bit LSB relocatable 80386 Version 1 [SSE2]
Note: yyy.o was built using "-native", informing the compiler that it can use the SSE2 instruction set extensions supported by the CPUs on the build system.
Some more examples, including a binary built on a SunOS 4.x system:
$ file gobble.\* gobble.sunos4: Sun demand paged SPARC executable dynamically linked gobble.sparcv9: ELF 64-bit MSB executable SPARCV9 Version 1, dynamically linked, not stripped gobble.i386: ELF 32-bit LSB executable 80386 Version 1 [FPU], dynamically linked, not stripped gobble.amd64: ELF 64-bit LSB executable AMD64 Version 1 [SSE FXSR FPU], dynamically linked, not stripped
Can I detect what version of whose compiler was used to build a binary, and on what version of Solaris?
The command to use is:
$ /usr/ccs/bin/mcs -p executable | object
Here are some examples. The "ld:" entries should indicate what release of Solaris the executable was built on, which is a good indicator of the oldest version of Solaris it will run on.
- Sun Studio 11, on Solaris 10:
acomp: Sun C 5.8 2005/10/13 iropt: Sun Compiler Common 11 2005/10/13 as: Sun Compiler Common 11 2005/10/13 ld: Software Generation Utilities - Solaris Link Editors: 5.10-1.477
- An old version of GCC (this was built in 1994, looks like Solaris 2.3):
@(#)SunOS 5.3 Generic September 1993 GCC: (GNU) 2.5.8 as: SC3.0 early access 01 Sep 1993 ld: (SGU) SunOS/ELF (LK-1.3)
- Sun C 5.0, Solaris???
@(#)stdio.h 1.78 99/12/08 SMI acomp: WorkShop Compilers 5.0 98/12/15 C 5.0 ld: Software Generation Utilities - Solaris-ELF (4.0)
- GCC 2.8.1, Solaris 7:
@(#)SunOS 5.7 Generic October 1998 as: WorkShop Compilers 5.0 Alpha 03/27/98 Build GCC: (GNU) 2.8.1 ld: Software Generation Utilities - Solaris/ELF (3.0)
- GCC 3.4.3 (object). The GCC compiler was built on/for "sol210" [sic]
GCC: (GNU) 3.4.3 (csl-sol210-3_4-branch+sol_rpath)
There is a non-linear relationship between versions of the compiler ("Sun C") and the development suite ("Sun Studio", "Forte Developer", "Sun WorkShop", etc.). You can figure it out using Sun Studio Support Matrix.
Can I figure out what compiler flags were used?
It depends on what compiler was used, and whether you have objects.
- For Sun Studio 11, use "dwarfdump -i", and look for "DW_AT_SUN_command_line" in the output.
- For Sun Studio 10 and earlier, use "dumpstabs -s", and look for "CMDLINE" in the output.
- For GCC, you can only figure out what version of GCC was used (see above).
"dwarfdump" and "dumpstabs" are available with the Sun Studio suite.
$ dwarfdump -i gobble.sparcv9 ... DW_AT_name gobble.c DW_AT_language DW_LANG_C99 DW_AT_comp_dir /home/tc35445/tools/c/gobble DW_AT_SUN_command_line /usr/dist/share/sunstudio_sparc, v11.0/SUNWspro/prod/bin/cc -xO3 -xarch=v9 -c gobble.c DW_AT_SUN_compile_options Xa;O;R=Sun C 5.8 2005/10/13; backend;raw;cd; $ dumpstabs -s test 5: .stabs "Xa ; g ; V=3.1 ; R=Sun WorkShop 6 2000/04/07 C 5.1 ; G=$XAB0qnBB6 6: .stabs "/net/vic/export/home/timc/tools/c/interposition; /opt/Forte6/SUNWspro/bin/../WS6/bin/cc -g -c test.c -W0,-xp\\$XAB0qnBB6hh5S_R.",N_CMDLINE,0x0,0x0,0x0 $ dumpstabs -s getwd 1: .stabs "Xa ; V=3.1 ; R=WorkShop Compilers 4.2 30 Oct 1996 C 4.2", N_OPT,0x0,0x0,0x0 2: .stabs "/home/staff/timc/tools/c/getwd; /opt/SUNWspro/bin/../SC4.2/bin/cc -c getwd.c -W0,-xp",N_CMDLINE,0x0,0x0,0x0
Can I figure out where the binary will look for shared objects?If an RPATH has been specified, dumpstabs can find it:
$ dumpstabs mysqladmin | grep RPATH 13: Tag = 15 (RPATH) /usr/sfw/lib/mysql:/usr/sfw/lib
Can I figure out what shared objects the binary needs?
Yes, just use "ldd":
$ ldd mysqladmin libmysqlclient.so.12 => /usr/sfw/lib/libmysqlclient.so.12 libz.so.1 => /usr/lib/libz.so.1 librt.so.1 => /usr/lib/librt.so.1 libcrypt_i.so.1 => /usr/lib/libcrypt_i.so.1 libgen.so.1 => /usr/lib/libgen.so.1 libsocket.so.1 => /usr/lib/libsocket.so.1 libnsl.so.1 => /usr/lib/libnsl.so.1 libm.so.2 => /usr/lib/libm.so.2 libthread.so.1 => /usr/lib/libthread.so.1 libc.so.1 => /usr/lib/libc.so.1 libaio.so.1 => /usr/lib/libaio.so.1 libmd5.so.1 => /usr/lib/libmd5.so.1 libmp.so.2 => /usr/lib/libmp.so.2 libscf.so.1 => /usr/lib/libscf.so.1 libdoor.so.1 => /usr/lib/libdoor.so.1 libuutil.so.1 => /usr/lib/libuutil.so.1 /platform/SUNW,Sun-Fire-15000/lib/libc_psr.so.1 /platform/SUNW,Sun-Fire-15000/lib/libmd5_psr.so.1