From: eLinux.org

GCC Tips

Contents

What’s Here, Why You Should Care

A collection of tips useful to those doing embedded development.
Accumulated over several years of doing project work, helping other
engineers, untangling projects for customers and feedback from several
CELF presentations related to this topic.

Tips

View Compilation Plan

  1. gcc -### <the rest of your command line goes here>

The GCC you run is a driver program for a bunch of other programs. With
this parameter, gcc will produce (but not actually execute) the commands
it would have used to accomplish the task you asked it to do. This way,
you can see the gory details of what’s going on behind the scenes. What
library is being used? What is -mcpu set to? It’s all there.

You can pipe this output to a file and execute that to compile a
program, making it easy to experiment with tweaks to the linker or
assembler.

  1. Reading specs from /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/specs
  2. Configured with: ../configure --prefix=/opt/timesys/toolchains/ppc7xx-linux --mandir=/opt/timesys/toolchains/ppc7xx-linux/share/man --infodir=/opt/timesys/toolchains/ppc7xx-linux/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++ --with-sysroot=/here/workdir/i386-x-ppc7xx/deleteme --disable-libgcj --build=i686-timesys-linux --host=i686-timesys-linux --target=powerpc-linux --program-prefix=ppc7xx-linux-
  3. Thread model: posix
  4. gcc version 3.4.1 20040714 (TimeSys 3.4.1-7)
  5. /opt/timesys/toolchains/ppc7xx-linux/libexec/gcc/powerpc-linux/3.4.1/cc1 -quiet -v -D__unix__ -D__gnu_linux__ -D__linux__ -Dunix -D__unix -Dlinux -D__linux -Asystem=linux -Asystem=unix -Asystem=posix -I/opt/timesys/toolchains/ppc7xx-linux/powerpc-linux/include/nptl file.c -quiet -dumpbase file.c -auxbase file -version -o /tmp/ccShiHn4.s
  6. ignoring nonexistent directory "/here/workdir/i386-x-ppc7xx/deleteme/usr/local/include"
  7. ignoring nonexistent directory "/here/workdir/i386-x-ppc7xx/deleteme/usr/include"
  8. #include "..." search starts here:
  9. #include <...> search starts here:
  10. /opt/timesys/toolchains/ppc7xx-linux/powerpc-linux/include/nptl
  11. /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/include
  12. /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/../../../../powerpc-linux/include
  13. End of search list.
  14. GNU C version 3.4.1 20040714 (TimeSys 3.4.1-7) (powerpc-linux)
  15. compiled by GNU C version 3.2.2 20030222 (Red Hat Linux 3.2.2-5).
  16. GGC heuristics: --param ggc-min-expand=47 --param ggc-min-heapsize=32138
  17. /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/../../../../powerpc-linux/bin/as -mppc -many -V -Qy -o /tmp/ccWeV3a3.o /tmp/ccShiHn4.s
  18. GNU assembler version 2.15.90.0.3 (powerpc-linux) using BFD version 2.15.90.0.3 20040415
  19. /opt/timesys/toolchains/ppc7xx-linux/libexec/gcc/powerpc-linux/3.4.1/collect2 --eh-frame-hdr -V -Qy -L/opt/timesys/toolchains/ppc7xx-linux/powerpc-linux/lib/nptl --rpath-link /opt/timesys/toolchains/ppc7xx-linux/powerpc-linux/lib/tls -m elf32ppclinux -dynamic-linker /lib/ld.so.1 -o file /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/../../../../powerpc-linux/lib/crt1.o /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/../../../../powerpc-linux/lib/crti.o /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/crtbegin.o -L/opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1 -L/opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/../../../../powerpc-linux/lib /tmp/ccWeV3a3.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/crtsavres.o /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/crtend.o /opt/timesys/toolchains/ppc7xx-linux/lib/gcc/powerpc-linux/3.4.1/../../../../powerpc-linux/lib/crtn.o
  20. GNU ld version 2.15.90.0.3 20040415
  21. Supported emulations:
  22. elf32ppclinux
  23. elf32ppc
  24. elf32ppcsim

Note: on my (Tim Bird’s) Ubuntu 12.04 system, using gcc 4.6.3, it shows
quite different output. Specifically, it is missing anything about the
include directories.

See default include search paths

You can get a report about the include search paths with the following
command:

  1. $ gcc -xc -E -v -
  2. Using built-in specs.
  3. COLLECT_GCC=gcc
  4. COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
  5. Target: x86_64-linux-gnu
  6. Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
  7. Thread model: posix
  8. gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
  9. COLLECT_GCC_OPTIONS='-E' '-v' '-mtune=generic' '-march=x86-64'
  10. /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -E -quiet -v -imultilib . -imultiarch x86_64-linux-gnu - -mtune=generic -march=x86-64 -fstack-protector
  11. ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
  12. ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../x86_64-linux-gnu/include"
  13. #include "..." search starts here:
  14. #include <...> search starts here:
  15. /usr/lib/gcc/x86_64-linux-gnu/4.6/include
  16. /usr/local/include
  17. /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
  18. /usr/include/x86_64-linux-gnu
  19. /usr/include
  20. End of search list.

Timing sub-commands

You can get a report for the amount of time taken for each sub-command
that gcc uses, using the ‘-time’ command.

Example:

  1. $ gcc -time -static hello.c -o hello
  2. # cc1 0.01 0.01
  3. # as 0.00 0.00
  4. # collect2 0.03 0.02
  5. $

This was on a fast machine, with a very small sample program. It shows
that the sub-programs ‘cc1’, ‘as’, and ‘collect2’ (the compiler, the
assembler, and the linker (collect2 is a front-end for ‘ld’),
respectively), took less than a few hundredths of a second each to run.

Pre-Process, Retain Comments

  1. gcc -C -E <file-name.c> -o file

Some engineers love to do coding in macros. The rest of us would like to
break their fingers. This command will run the file through the
pre-processor, expanding all macros, but retaining all comments. Stick a
comment like “LOOK HERE” and search for that so you reduce the amount of
time you spend looking for the offending code.

Pre-Process, Retain Defines/Macros

  1. gcc -dD -E <file-name.c> -o file

Just like the previous example, but perhaps you’re trying to trace the
macro define mess.

See what Files the Linker is Using

  1. gcc -Wl,-t <parameters>

Displays what files the linker opens in what order. When looking in
archive files, the archive file is displayed in para theses, followed by
the file in the archive. Very handy when working through a legacy
project that depends on files linking in a certain order that suddenly
breaks because of a small (probably viewed as not noteworthy) change in
a makefile somewhere.

  1. /usr/bin/ld: mode elf_i386
  2. /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/../../../crt1.o
  3. /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/../../../crti.o
  4. /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/crtbegin.o
  5. /tmp/cc37FxnS.o
  6. -lgcc_s (http://eLinux.org/usr/lib/gcc-lib/i386-redhat-linux/3.3.3/libgcc_s.so)
  7. /lib/libc.so.6
  8. (http://eLinux.org/usr/lib/libc_nonshared.a)elf-init.oS
  9. -lgcc_s (http://eLinux.org/usr/lib/gcc-lib/i386-redhat-linux/3.3.3/libgcc_s.so)
  10. /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/crtend.o
  11. /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/../../../crtn.o

Print Pre-defined Macros

  1. gcc -E -dM - < /dev/null | cut -c 9- | sort

Very handy when porting code. Lets you know if your target processor has
some missing defines or if something is different (like
__INT_MAX__) that can have interesting effects on your project.
Diff the output from the old to the new compiler so you can easily see
the differences, makes it easy to spot problems before getting started.

Sample output, from a compiler targeting an ARM processor.

  1. __APCS_32__ 1
  2. __arm__ 1
  3. __ARM_ARCH_4T__ 1
  4. __ARMEL__ 1
  5. __CHAR_BIT__ 8
  6. __CHAR_UNSIGNED__ 1
  7. __DBL_DENORM_MIN__ 4.9406564584124654e-324
  8. __DBL_DIG__ 15
  9. __DBL_EPSILON__ 2.2204460492503131e-16
  10. __DBL_HAS_DENORM__ 1
  11. __DBL_HAS_INFINITY__ 1
  12. __DBL_HAS_QUIET_NAN__ 1
  13. __DBL_MANT_DIG__ 53
  14. __DBL_MAX_10_EXP__ 308
  15. __DBL_MAX__ 1.7976931348623157e+308
  16. __DBL_MAX_EXP__ 1024

Mixed Assembler and Source Output

  1. gcc -g somefile.c -o somefile
  2. objdump -S somefile

Prints out each line in the program and the corresponding assembly code.
Very handy when you’re trying to see that the processor is generating
the correct code, with the instructions you’re expecting. You can also
see the effects of optimization, but would recommend doing this for a
small amount of code because when the optimization level is high,
there’s a much lower relationship between line of code and generated
assembler.

Here’s an example of what objdump produces for a few lines of code:

  1. gpvSharedMemory = shmat(hSharedMemory, NULL, 0);
  2. 10000958: 80 7f 00 10 lwz r3,16(r31)
  3. 1000095c: 38 80 00 00 li r4,0
  4. 10000960: 38 a0 00 00 li r5,0
  5. 10000964: 48 01 09 31 bl 10011294 <shmat@plt>
  6. 10000968: 7c 60 1b 78 mr r0,r3
  7. 1000096c: 3d 20 10 01 lis r9,4097
  8. 10000970: 90 09 11 d0 stw r0,4560(r9)
  9. if (errno != 0) {
  10. 10000974: 48 01 08 d1 bl 10011244 <__errno_location@plt>
  11. 10000978: 7c 60 1b 78 mr r0,r3
  12. 1000097c: 7c 09 03 78 mr r9,r0
  13. 10000980: 80 09 00 00 lwz r0,0(r9)
  14. 10000984: 2f 80 00 00 cmpwi cr7,r0,0
  15. 10000988: 41 9e 00 50 beq- cr7,100009d8 <main+0x10c>

Specify Language

  1. gcc -x c a-c-source-file.with-a-non-standard-extension -o test.out

Great for legacy projects where where the file extensions don’t match
with GCC’s expectations, while less of a problem since many projects got
their start with GCC, this still is an issue with long-running projects
that years back, used some other compiler. This stays in effect for the
following file on the command line.

List Include File Dependencies

There’s a whole family of things around -M. These produce a rule that
could be used in a make file, with the included files as dependencies.

  1. gcc -M <file name>

This shows you all includes, even those on the system path. Useful if
you’re doing porting work or validating if your compiler is working as
expected and getting the files from the right place. You’ll see
something like this for a basic hello world program

  1. hello.o: hello.c /usr/include/stdio.h /usr/include/features.h \
  2. /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
  3. /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \
  4. /usr/include/bits/types.h /usr/include/bits/wordsize.h \
  5. /usr/include/bits/typesizes.h /usr/include/libio.h \
  6. /usr/include/_G_config.h /usr/include/wchar.h /usr/include/bits/wchar.h \
  7. /usr/include/gconv.h \
  8. /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdarg.h \
  9. /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
  10. gcc -MM <file name>

Like -M, but no system files. Great to see if your project is configured
and working as expected.

  1. gcc -M -MG <file name>

The prior -M and -MM commands will stop if header files can be located.
The parameter -MG will just produce the dependency list with the missing
file. Engineers that have projects that generate header files as part of
the build find -MM very handy.

  1. gcc -M -MT '<target>' <file name>

By default, the target will be the \.o This command will
make the default the value of \.

If the command was

  1. gcc -M -MT '$(target)' hello.c

You would see

  1. $(target): hello.c

Symbol Trace

  1. gcc -Wl,-y,printf hello.c

This is very handy when you want to understand where the linker is
finding a definition of a symbol. Some projects have name collisions or
link order dependencies. This lets you see precisely what the linker is
doing.

Given a hello world program, you would see output like

  1. /tmp/ccwZx5UV.o: reference to printf
  2. /lib/libc.so.6: definition of printf

The reference is in a temporary file created during the compilation
process. If you were linking several object files together explicitly,
you would see the name of the object file where printf was referenced.

Saving temporary files

  1. gcc -save-temps hello.c

The compilers temporary files are saved. This is often invaluable
dealing with complicated makefiles to peek at the preprocessed output
without having to figure out how to do a -E option by hand.

Categories: