Bug 96385 - [8 Regression] GCC generates separate debug info with undefined symbols without relocations
Summary: [8 Regression] GCC generates separate debug info with undefined symbols witho...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: lto (show other bugs)
Version: 10.2.1
: P2 normal
Target Milestone: 8.5
Assignee: Richard Biener
URL:
Keywords: lto, wrong-debug
Depends on:
Blocks:
 
Reported: 2020-07-29 21:47 UTC by H.J. Lu
Modified: 2021-04-26 10:48 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 10.2.1, 11.0, 8.4.1, 9.3.1
Known to fail: 10.2.0, 8.4.0, 9.3.0
Last reconfirmed: 2020-07-30 00:00:00


Attachments
LTO debug output (1.38 KB, application/x-xz)
2020-07-29 21:47 UTC, H.J. Lu
Details
A testcase (850 bytes, application/octet-stream)
2020-08-01 01:12 UTC, H.J. Lu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2020-07-29 21:47:25 UTC
Created attachment 48956 [details]
LTO debug output

GCC may generate separate debug info files which contain undefined symbols
without relocations.  Here is the lto output from binutils LTO build:

[hjl@gnu-cfl-2 binutils-cross-run]$ readelf -rsW /tmp/gcc.lto.debug.o | grep lreal
    96: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND lrealpath
[hjl@gnu-cfl-2 binutils-cross-run]$ 

It triggered a linker bug:

https://sourceware.org/bugzilla/show_bug.cgi?id=26314
Comment 1 Richard Biener 2020-07-30 06:15:59 UTC
Such early debug is bogus - do you have the preprocessed source for the corresponding TU?
Comment 2 H.J. Lu 2020-07-30 11:48:04 UTC
A testcase is on pr96385 branch at:

https://gitlab.com/x86-gcc/gcc-bugs
Comment 3 rguenther@suse.de 2020-07-30 12:02:45 UTC
On Thu, 30 Jul 2020, hjl.tools at gmail dot com wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96385
> 
> H.J. Lu <hjl.tools at gmail dot com> changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>              Status|WAITING                     |NEW
> 
> --- Comment #2 from H.J. Lu <hjl.tools at gmail dot com> ---
> A testcase is on pr96385 branch at:
> 
> https://gitlab.com/x86-gcc/gcc-bugs

I'd like to have the _source_ to whichever of the .o files
has the bogus relocation in the .gnulto.debug_info section.

The bug happens at the compile stage.
Comment 4 rguenther@suse.de 2020-07-30 12:05:47 UTC
On Thu, 30 Jul 2020, rguenther at suse dot de wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96385
> 
> --- Comment #3 from rguenther at suse dot de <rguenther at suse dot de> ---
> On Thu, 30 Jul 2020, hjl.tools at gmail dot com wrote:
> 
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96385
> > 
> > H.J. Lu <hjl.tools at gmail dot com> changed:
> > 
> >            What    |Removed                     |Added
> > ----------------------------------------------------------------------------
> >              Status|WAITING                     |NEW
> > 
> > --- Comment #2 from H.J. Lu <hjl.tools at gmail dot com> ---
> > A testcase is on pr96385 branch at:
> > 
> > https://gitlab.com/x86-gcc/gcc-bugs
> 
> I'd like to have the _source_ to whichever of the .o files
> has the bogus relocation in the .gnulto.debug_info section.
> 
> The bug happens at the compile stage.

More specifically, .rela.gnu.debuglto_.debug_info may only contain
relocations to other .gnu.debuglto_.* sections and definitely
_not_ relocations to UNDEF symbols.
Comment 5 H.J. Lu 2020-07-30 12:17:22 UTC
Please get users/hjl/pr26314/test branch at

https://gitlab.com/x86-binutils/binutils-gdb/-/tree/users/hjl/pr26314/test

and build binutils with GCC 10:

CC="/usr/gcc-10.1.1-x32/bin/gcc -flto -ffat-lto-objects -Wl,--as-needed -fcf-protection" CXX="/usr/gcc-10.1.1-x32/bin/g++ -flto -ffat-lto-objects -Wl,--as-needed -fcf-protection" /export/gnu/import/git/gitlab/x86-binutils/configure \
	--enable-shared \
	 \
	--enable-plugins --disable-gdb --disable-gdbserver --disable-libdecnumber --disable-readline --disable-sim --with-sysroot=/ --with-system-zlib \
	--prefix=/usr/local \
	--with-local-prefix=/usr/local

I got

[hjl@gnu-cfl-2 build-x86_64-linux]$ nm -D binutils/.libs/ar | grep lrealpath
0000000000000000 A lrealpath
[hjl@gnu-cfl-2 build-x86_64-linux]$
Comment 6 H.J. Lu 2020-07-31 15:26:26 UTC
There is a small testcase in

https://sourceware.org/bugzilla/show_bug.cgi?id=26324
Comment 7 H.J. Lu 2020-07-31 15:27:27 UTC
[hjl@gnu-cfl-2 pr26324]$ cat pr15146a.c
extern int xxx;

int
bar (void)
{
  return xxx;
}

int
main ()
{ 
  return 0;
}
[hjl@gnu-cfl-2 pr26324]$ cat pr15146b.c
int xxx = 3;
[hjl@gnu-cfl-2 pr26324]$ cat pr15146c.c
[hjl@gnu-cfl-2 pr26324]$ make
gcc -B./  -O2 -g -o x -Wl,-R,. \
  -Wl,--no-copy-dt-needed-entries -Wl,--no-as-needed pr15146a.o pr15146c.so
./ld: /tmp/ccHirkTe.debug.temp.o: undefined reference to symbol 'xxx'
./ld: ./pr15146b.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
make: *** [Makefile:15: x] Error 1
[hjl@gnu-cfl-2 pr26324]$
Comment 8 H.J. Lu 2020-07-31 19:56:03 UTC
The original pr26324a.o debug info contains reference to xxx.  But reference
to xxx has been removed by LTO.  simple_object_copy_lto_debug_sections fails
to remove the un-referenced symbol, xxx, from symbol table.
Comment 9 H.J. Lu 2020-08-01 01:12:58 UTC
Created attachment 48975 [details]
A testcase

[hjl@gnu-cfl-2 pr26324]$ make
gcc -B./ -O2 -g -flto -ffat-lto-objects   -c -o pr26324a.o pr26324a.c
gcc -B./ -O2 -g -fPIC   -c -o pr15146c.o pr15146c.c
gcc -B./ -O2 -g -fPIC   -c -o pr15146b.o pr15146b.c
gcc -B./ -shared  -o pr15146b.so pr15146b.o
gcc -B./ -shared  -o pr15146c.so pr15146c.o pr15146b.so
gcc -B./  -O2 -g -o x -Wl,-R,. \
  -Wl,--no-copy-dt-needed-entries -Wl,--no-as-needed pr26324a.o pr15146c.so
./ld: /tmp/ccCGQCqp.debug.temp.o: undefined reference to symbol 'xxx'
./ld: ./pr15146b.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
make: *** [Makefile:20: x] Error 1
[hjl@gnu-cfl-2 pr26324]$ 

-flto -ffat-lto-objects is the key.
Comment 10 H.J. Lu 2020-08-01 01:15:00 UTC
(In reply to H.J. Lu from comment #8)
> The original pr26324a.o debug info contains reference to xxx.  But reference
> to xxx has been removed by LTO.  simple_object_copy_lto_debug_sections fails
> to remove the un-referenced symbol, xxx, from symbol table.

The alternative is to ask linker to handle it:

https://sourceware.org/pipermail/binutils/2020-July/112673.html
Comment 11 H.J. Lu 2020-08-02 12:40:00 UTC
GCC 7.3.1 is OK:

[hjl@gnu-cfl-2 pr26324]$ make
/usr/gcc-7.3.1-x32/bin/gcc -B./ -O2 -g -flto -ffat-lto-objects   -c -o pr26324a.o pr26324a.c
/usr/gcc-7.3.1-x32/bin/gcc -B./ -O2 -g -fPIC   -c -o pr15146c.o pr15146c.c
/usr/gcc-7.3.1-x32/bin/gcc -B./ -O2 -g -fPIC   -c -o pr15146b.o pr15146b.c
/usr/gcc-7.3.1-x32/bin/gcc -B./ -shared  -o pr15146b.so pr15146b.o
/usr/gcc-7.3.1-x32/bin/gcc -B./ -shared  -o pr15146c.so pr15146c.o pr15146b.so
/usr/gcc-7.3.1-x32/bin/gcc -B./  -O2 -g -o x -Wl,-R,. \
  -Wl,--no-copy-dt-needed-entries -Wl,--no-as-needed pr26324a.o pr15146c.so
./x
PASS
[hjl@gnu-cfl-2 pr26324]$
Comment 12 Richard Biener 2020-08-03 06:58:34 UTC
(In reply to H.J. Lu from comment #10)
> (In reply to H.J. Lu from comment #8)
> > The original pr26324a.o debug info contains reference to xxx.  But reference
> > to xxx has been removed by LTO.  simple_object_copy_lto_debug_sections fails
> > to remove the un-referenced symbol, xxx, from symbol table.
> 
> The alternative is to ask linker to handle it:
> 
> https://sourceware.org/pipermail/binutils/2020-July/112673.html

The bug is we create the reference in the first place.
Comment 13 Richard Biener 2020-08-03 07:41:12 UTC
(In reply to Richard Biener from comment #12)
> (In reply to H.J. Lu from comment #10)
> > (In reply to H.J. Lu from comment #8)
> > > The original pr26324a.o debug info contains reference to xxx.  But reference
> > > to xxx has been removed by LTO.  simple_object_copy_lto_debug_sections fails
> > > to remove the un-referenced symbol, xxx, from symbol table.
> > 
> > The alternative is to ask linker to handle it:
> > 
> > https://sourceware.org/pipermail/binutils/2020-July/112673.html
> 
> The bug is we create the reference in the first place.

Oh, I see.  So we had multiple choices for "pruning" symbols from the symbol
table during simple_object_copy_lto_debug_sections and factoring in
HP-UX and Solaris (sic!...) emptying UND symbol names didn't work out.
So we do now

              if (discard)
                {
                  /* Make discarded symbols undefined and unnamed
                     in case it is local.  */
                  int bind = ELF_ST_BIND (*st_info);
                  int other = STV_DEFAULT;
                  if (bind == STB_LOCAL)
                    {
                      /* Make discarded local symbols unnamed and
                         defined in the first prevailing section.  */
                      ELF_SET_FIELD (type_functions, ei_class, Sym,
                                     ent, st_name, Elf_Word, 0);
                      ELF_SET_FIELD (type_functions, ei_class, Sym,
                                     ent, st_shndx, Elf_Half,
                                     sh_map[first_shndx]);
                    }
                  else
                    {
                      /* Make discarded global symbols hidden weak
                         undefined and sharing a name of a prevailing
                         symbol.  */
                      bind = STB_WEAK;
                      other = STV_HIDDEN;
                      ELF_SET_FIELD (type_functions, ei_class, Sym,
                                     ent, st_name, Elf_Word,
                                     prevailing_name_idx);
                      ELF_SET_FIELD (type_functions, ei_class, Sym,
                                     ent, st_shndx, Elf_Half, SHN_UNDEF);
                    }
                  *st_other = other;
                  *st_info = ELF_ST_INFO (bind, STT_NOTYPE);
                  ELF_SET_FIELD (type_functions, ei_class, Sym,
                                 ent, st_value, Elf_Addr, 0);
                  ELF_SET_FIELD (type_functions, ei_class, Sym,
                                 ent, st_size, Elf_Word, 0);
                }

but somehow the else path isn't triggered(?).  Note that all we try to
avoid is the need to rewrite relocation sections if we really would
prune symbols rather than NULL-ifying them somehow.  You can trace history
as to how the above code morphed with various bugs in the past...

Hmm, we don't treat SHN_UNDEF any special here - I guess we could at most
make all of them WEAK ... the following should address this.

diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c
index c62d5bba551..7c9d492f6a4 100644
--- a/libiberty/simple-object-elf.c
+++ b/libiberty/simple-object-elf.c
@@ -1467,6 +1467,11 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
                       && st_shndx < shnum
                       && pfnret[st_shndx - 1] == -1)
                discard = 1;
+             /* We also need to remove global UNDEFs which can
+                cause link fails later.  */
+             else if (st_shndx == SHN_UNDEF
+                      && ELF_ST_BIND (*st_info) == STB_GLOBAL)
+               discard = 1;
 
              if (discard)
                {
Comment 14 Richard Biener 2020-08-03 07:53:32 UTC
Note the symbol table entry should be "unused" (if there's anything like that).
At least ld usually treats it like so.  IIRC I left those dangling because
UNDEFs into the copied .debug_info section are bogus - and I did not want to
parse relocation sections to see where it is referenced from (otherwise I'd
assert for such UNDEFs).

I know it's all a bit awkward but originally this was supposed to be
a temporary measure until ld + plugin API understands how to only
partly claim an object and make ld link the original .gnu.debuglto_
prefixed debug-info sections unchanged into the final object ...

So you basically found a case where ld does _not_ treat the UNDEF as "unused".
In case that is not a bug in ld I am not really understanding how the bug
manifests which means I have a hard time creating a testcase for GCCs
LTO testsuite :/

Now the patch itself should be quite safe (we shouldn't be left with any
global UNDEFs).  But I'm curious if it resolves a "real" bug...
Comment 15 Richard Biener 2020-08-03 08:02:57 UTC
I also wonder if the result of the patch,

    34: 0000000000000000     0 NOTYPE  WEAK   HIDDEN     1 t.c.5958f17d
    35: 0000000000000000     0 NOTYPE  WEAK   HIDDEN   UND t.c.5958f17d
    36: 0000000000000000     0 NOTYPE  WEAK   HIDDEN   UND t.c.5958f17d
    37: 0000000000000000     0 NOTYPE  WEAK   HIDDEN   UND t.c.5958f17d

is in any way "safer" from an ELF perspective (not so much GNU ld since
we've dealt with Solaris and HP-UX linker issues in the past).

Alan, you fiddled with this earlier so any comments?
Comment 16 Alan Modra 2020-08-03 12:22:10 UTC
It looks fine to me, assuming you don't need to keep any of these undefined symbols.
Comment 17 GCC Commits 2020-08-03 13:09:31 UTC
The master branch has been updated by Richard Biener <rguenth@gcc.gnu.org>:

https://gcc.gnu.org/g:b32c5d0b72fda2588b4e170e75a9c64e4bf266c7

commit r11-2506-gb32c5d0b72fda2588b4e170e75a9c64e4bf266c7
Author: Richard Biener <rguenther@suse.de>
Date:   Mon Aug 3 15:05:37 2020 +0200

    lto/96385 - avoid unused global UNDEFs in debug objects
    
    Unused global UNDEFs can have side-effects in some circumstances so
    the following patch avoids them by treating them the same as other
    to be discarded DEFs - make them local.
    
    2020-08-03  Richard Biener  <rguenther@suse.de>
    
            PR lto/96385
    libiberty/
            * simple-object-elf.c
            (simple_object_elf_copy_lto_debug_sections): Localize global
            UNDEFs and reuse the prevailing name.
Comment 18 Richard Biener 2020-08-03 13:10:07 UTC
So let's see whether HPUX or Solaris folks complain.
Comment 19 GCC Commits 2020-09-11 12:12:01 UTC
The releases/gcc-10 branch has been updated by Richard Biener <rguenth@gcc.gnu.org>:

https://gcc.gnu.org/g:63a2bdbfb42628800a6999e98804928855592ce7

commit r10-8746-g63a2bdbfb42628800a6999e98804928855592ce7
Author: Richard Biener <rguenther@suse.de>
Date:   Mon Aug 3 15:05:37 2020 +0200

    lto/96385 - avoid unused global UNDEFs in debug objects
    
    Unused global UNDEFs can have side-effects in some circumstances so
    the following patch avoids them by treating them the same as other
    to be discarded DEFs - make them local.
    
    2020-08-03  Richard Biener  <rguenther@suse.de>
    
            PR lto/96385
    libiberty/
            * simple-object-elf.c
            (simple_object_elf_copy_lto_debug_sections): Localize global
            UNDEFs and reuse the prevailing name.
    
    (cherry picked from commit b32c5d0b72fda2588b4e170e75a9c64e4bf266c7)
Comment 20 GCC Commits 2021-04-12 11:23:34 UTC
The releases/gcc-9 branch has been updated by Richard Biener <rguenth@gcc.gnu.org>:

https://gcc.gnu.org/g:969be2412231d3bdd73300ac32684d416345a029

commit r9-9340-g969be2412231d3bdd73300ac32684d416345a029
Author: Richard Biener <rguenther@suse.de>
Date:   Mon Aug 3 15:05:37 2020 +0200

    lto/96385 - avoid unused global UNDEFs in debug objects
    
    Unused global UNDEFs can have side-effects in some circumstances so
    the following patch avoids them by treating them the same as other
    to be discarded DEFs - make them local.
    
    2020-08-03  Richard Biener  <rguenther@suse.de>
    
            PR lto/96385
    libiberty/
            * simple-object-elf.c
            (simple_object_elf_copy_lto_debug_sections): Localize global
            UNDEFs and reuse the prevailing name.
    
    (cherry picked from commit b32c5d0b72fda2588b4e170e75a9c64e4bf266c7)
Comment 21 GCC Commits 2021-04-26 10:46:44 UTC
The releases/gcc-8 branch has been updated by Richard Biener <rguenth@gcc.gnu.org>:

https://gcc.gnu.org/g:e6a720bf5b1328ff018880063ae3d1e777e5b61d

commit r8-10922-ge6a720bf5b1328ff018880063ae3d1e777e5b61d
Author: Richard Biener <rguenther@suse.de>
Date:   Mon Aug 3 15:05:37 2020 +0200

    lto/96385 - avoid unused global UNDEFs in debug objects
    
    Unused global UNDEFs can have side-effects in some circumstances so
    the following patch avoids them by treating them the same as other
    to be discarded DEFs - make them local.
    
    2020-08-03  Richard Biener  <rguenther@suse.de>
    
            PR lto/96385
    libiberty/
            * simple-object-elf.c
            (simple_object_elf_copy_lto_debug_sections): Localize global
            UNDEFs and reuse the prevailing name.
    
    (cherry picked from commit b32c5d0b72fda2588b4e170e75a9c64e4bf266c7)
Comment 22 Richard Biener 2021-04-26 10:48:56 UTC
Fixed.