gcc 6.3 including too many debug symbols, especially extern global declarations

1

This question may have been asked, but I've got a toy program that exemplifies the issue fairly well.

Synopsis

When compiling with gcc -g using gcc 4.9, the debug symbols included, especially for externally declared global variables, is at an expected and familiar amount. When switching to gcc 6.3, the amount of debug symbols included seems excessive and superfluous. Attempts at using flags such as:

  • -feliminate-unused-debug-symbols
  • -feliminate-unused-debug-types
  • -femit-struct-debug-baseonly

have yielded no difference. This creates a problem when working with a very large codebase that yields large library archives that end up being several orders of magnitude larger (file size) with the newer compiler vs. the older one.

Sample Program

a.c:

#include <stdlib.h>
#include <stdio.h>
#include "big.h"

int main (void) {
    printf("%s\n", big_time);
    return 0;
}

b.c:

#include "big.h"

char* big_time = "BIG_TIME";
char* big_mama = "BIG_MAMA";

c.c:

#include "big.h"

char* big_stuf = "BIG_STUF";
char* big_leee = "BIG_LEEE";

big.h:

#ifndef _BIG_H_
#define _BIG_H_

extern char* big_time;
extern char* big_mama;
extern char* big_stuf;
extern char* big_leee;

#endif // _BIG_H_

Makefile:

CC = gcc
CFLAGS  = -g
CFLAGS += -feliminate-unused-debug-symbols

test: prog
        @for i in a.o b.o c.o prog; \
                do echo $$i; \
                readelf --debug-dump $$i | grep big_; \
        done

prog: a.o b.o c.o
        gcc $(CFLAGS) -o $@ $^

clean:
        @$(RM) a.o b.o c.o prog

Result with gcc 4.9

$ make
gcc -g -feliminate-unused-debug-symbols   -c -o a.o a.c
gcc -g -feliminate-unused-debug-symbols   -c -o b.o b.c
gcc -g -feliminate-unused-debug-symbols   -c -o c.o c.c
gcc -g -feliminate-unused-debug-symbols -o prog a.o b.o c.o
a.o
    <a5>   DW_AT_name        : (indirect string, offset: 0xb4): big_time
  0x000000b0 696e7400 6269675f 74696d65 00756e73 int.big_time.uns
b.o
    <1e>   DW_AT_name        : (indirect string, offset: 0x9): big_time
    <40>   DW_AT_name        : (indirect string, offset: 0x0): big_mama
  0x00000000 6269675f 6d616d61 00626967 5f74696d big_mama.big_tim
c.o
    <1e>   DW_AT_name        : (indirect string, offset: 0x9): big_stuf
    <40>   DW_AT_name        : (indirect string, offset: 0x0): big_leee
  0x00000000 6269675f 6c656565 00626967 5f737475 big_leee.big_stu
prog
    <a5>   DW_AT_name        : (indirect string, offset: 0x95): big_time
    <ce>   DW_AT_name        : (indirect string, offset: 0x95): big_time
    <f0>   DW_AT_name        : (indirect string, offset: 0xd7): big_mama
    <123>   DW_AT_name        : (indirect string, offset: 0xe9): big_stuf
    <145>   DW_AT_name        : (indirect string, offset: 0xe0): big_leee
  0x00000090 20696e74 00626967 5f74696d 6500756e  int.big_time.un
  0x000000d0 7a657479 70650062 69675f6d 616d6100 zetype.big_mama.
  0x000000e0 6269675f 6c656565 00626967 5f737475 big_leee.big_stu

Result with gcc 6.3

$ make
gcc -g -feliminate-unused-debug-symbols   -c -o a.o a.c
gcc -g -feliminate-unused-debug-symbols   -c -o b.o b.c
gcc -g -feliminate-unused-debug-symbols   -c -o c.o c.c
gcc -g -feliminate-unused-debug-symbols -o prog a.o b.o c.o
a.o
    <312>   DW_AT_name        : (indirect string, offset: 0x20e): big_time
    <31d>   DW_AT_name        : (indirect string, offset: 0x1eb): big_mama
    <328>   DW_AT_name        : (indirect string, offset: 0x286): big_stuf
    <333>   DW_AT_name        : (indirect string, offset: 0x90): big_leee
  0x00000090 6269675f 6c656565 006c6f6e 6720696e big_leee.long in
  0x000001e0 74005f49 4f5f4649 4c450062 69675f6d t._IO_FILE.big_m
  0x00000280 6636345f 74006269 675f7374 7566005f f64_t.big_stuf._
b.o
    <1e>   DW_AT_name        : (indirect string, offset: 0x9): big_time
    <36>   DW_AT_name        : (indirect string, offset: 0x0): big_mama
    <41>   DW_AT_name        : (indirect string, offset: 0x12): big_stuf
    <4c>   DW_AT_name        : (indirect string, offset: 0x1b): big_leee
  0x00000000 6269675f 6d616d61 00626967 5f74696d big_mama.big_tim
  0x00000010 65006269 675f7374 75660062 69675f6c e.big_stuf.big_l
c.o
    <1e>   DW_AT_name        : (indirect string, offset: 0x9): big_time
    <36>   DW_AT_name        : (indirect string, offset: 0x0): big_mama
    <41>   DW_AT_name        : (indirect string, offset: 0x12): big_stuf
    <4c>   DW_AT_name        : (indirect string, offset: 0x1b): big_leee
  0x00000000 6269675f 6d616d61 00626967 5f74696d big_mama.big_tim
  0x00000010 65006269 675f7374 75660062 69675f6c e.big_stuf.big_l
prog
    <312>   DW_AT_name        : (indirect string, offset: 0x1d2): big_time
    <31d>   DW_AT_name        : (indirect string, offset: 0x1af): big_mama
    <328>   DW_AT_name        : (indirect string, offset: 0x245): big_stuf
    <333>   DW_AT_name        : (indirect string, offset: 0x84): big_leee
    <379>   DW_AT_name        : (indirect string, offset: 0x1d2): big_time
    <391>   DW_AT_name        : (indirect string, offset: 0x1af): big_mama
    <39c>   DW_AT_name        : (indirect string, offset: 0x245): big_stuf
    <3a7>   DW_AT_name        : (indirect string, offset: 0x84): big_leee
    <3f2>   DW_AT_name        : (indirect string, offset: 0x1d2): big_time
    <40a>   DW_AT_name        : (indirect string, offset: 0x1af): big_mama
    <415>   DW_AT_name        : (indirect string, offset: 0x245): big_stuf
    <420>   DW_AT_name        : (indirect string, offset: 0x84): big_leee
  0x00000080 656e6400 6269675f 6c656565 005f666c end.big_leee._fl
  0x000001d0 73006269 675f7469 6d65002f 686f6d65 s.big_time./home
  0x00000240 36345f74 00626967 5f737475 66005f49 64_t.big_stuf._I

GCC version info

gcc 4.9:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.9.2-10+deb8u1' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10+deb8u1)

gcc 6.3:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-18+deb9u1' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)

Observations and Comments

In both cases, the symbols included in the final prog executable are a summation of those in each of the object files - as expected - so I don't think that behavior is wrong. But the key difference is in each of the object files. With the older compiler, you only have symbols included that are relevant to the module. With the newer version, you get every symbol for every variable externally declared, even if it's not used or referenced in that module. This has a multiplicative effect in the final executable's amount of debug info.

This toy program is mimicking source code structure seen in a very large 3rd party SDK being worked with. The net effect of this problem results in library archive files that are several orders of magnitude larger than before.

The -g debug info needs to be kept in, so excluding that or using strip is not an option. Using -g1 does have the effect of lowering the amount of debug info back to a normal (or smaller) amount, but at the cost of useful debug info once were inside gdb.

Help me, Obi Wan Kenobi. You're my only hope.

c
gcc
debug-symbols
asked on Stack Overflow Aug 13, 2018 by JPL • edited Aug 14, 2018 by JPL

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0