Bug 228753 - [i386] lld emits malformed DWARF info for crt1.o
Summary: [i386] lld emits malformed DWARF info for crt1.o
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: i386 Any
: --- Affects Only Me
Assignee: Mark Johnston
Depends on:
Blocks: 225128
  Show dependency treegraph
Reported: 2018-06-04 21:02 UTC by Mark Johnston
Modified: 2018-07-30 00:09 UTC (History)
1 user (show)

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Mark Johnston freebsd_committer 2018-06-04 21:02:48 UTC
With an lld-linked i386 world, ld.bfd hangs when linking the following program:

$ cat conftest.c
int k; int foo () { __builtin_alloca (k); }

During the link, ld emits a warning referencing _start1; it looks like ld from binutils 2.18.5 gets into an infinite loop when performing a lookup in the DWARF info:

(gdb) bt                                                                                                                                                     
#0  0x000d0c1c in add_line_info (table=0x207d4548, address=<optimized out>, filename=0x201a80c0 "\001/usr/home/markj/src/freebsd-dev/lib/csu/i386", line=1,
    column=0, end_sequence=0) at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/dwarf2.c:849
#1  0x000cfd1e in decode_line_info (unit=<optimized out>, stash=<optimized out>)
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/dwarf2.c:1169
#2  0x000cf693 in comp_unit_find_nearest_line (unit=0x207d44bc, addr=<optimized out>, filename_ptr=0xffbfe5d0, functionname_ptr=0xffbfe5cc,
    linenumber_ptr=0xffbfe5c8, stash=0x20469e30)
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/dwarf2.c:2103                                            
#3  0x000ced29 in find_line (abfd=0x201d50c0, section=<optimized out>, offset=160, symbol=0x0, symbols=0x20480000, filename_ptr=0xffbfe5d0,                  
    functionname_ptr=0xffbfe5cc, linenumber_ptr=0xffbfe5c8, addr_size=0, pinfo=0x20197344)                                                                   
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/dwarf2.c:2575                                            
#4  0x000ce063 in _bfd_dwarf2_find_nearest_line (abfd=0x201d50c0, section=0x201990d0, symbols=0x20480000, offset=160, filename_ptr=0xffbfe5d0,               
    functionname_ptr=0xffbfe5cc, linenumber_ptr=0xffbfe5c8, addr_size=0, pinfo=0x20197344)                                                                   
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/dwarf2.c:2607                                            
#5  0x000ac37e in _bfd_elf_find_nearest_line (abfd=0x201d50c0, section=0x201990d0, symbols=0x20480000, offset=160, filename_ptr=0xffbfe5d0,                  
    functionname_ptr=0xffbfe5cc, line_ptr=0xffbfe5c8)                                                                                                        
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/elf.c:7198                                               
#6  0x0007c3a9 in vfinfo (fp=0x181bac <__sF+472>, fmt=0x250e8 " undefined reference to `%T'\n", arg=0xffbfe668 "\300P\035 \320\220\031 \240", is_warning=1)  
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/ld/../../../../contrib/binutils/ld/ldmisc.c:324                                                  
#7  0x0007c82d in einfo (fmt=0x250e3 "%X%C: undefined reference to `%T'\n")                                                                                  
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/ld/../../../../contrib/binutils/ld/ldmisc.c:465                                                  
#8  0x0007b838 in undefined_symbol (info=0x1831d0 <link_info>, name=0x201bf6c8 "main", abfd=0x201d50c0, section=0x201990d0, address=160, error=1)            
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/ld/../../../../contrib/binutils/ld/ldmain.c:1397                                                 
#9  0x0008f1d6 in elf_i386_relocate_section (output_bfd=0x201d5000, info=0x1831d0 <link_info>, input_bfd=0x201d50c0, input_section=0x201990d0,               
    contents=0x206d5000 "1\355U\211\345\203\344\360\215E\b\203\354\004P\377u\004R\350\b", relocs=0x201d8288, local_syms=0x2046be00,                          
    local_sections=0x201ff400) at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/elf32-i386.c:2346             
#10 0x000bb38d in elf_link_input_bfd (input_bfd=<optimized out>, finfo=<optimized out>)                                                                      
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/elflink.c:8706                                           
#11 bfd_elf_final_link (abfd=0x201d5000, info=0x1831d0 <link_info>)                                                                                          
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/libbfd/../../../../contrib/binutils/bfd/elflink.c:9843                                           
#12 0x0007cf35 in ldwrite () at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/ld/../../../../contrib/binutils/ld/ldwrite.c:557                        
#13 0x0007a728 in main (argc=<optimized out>, argv=<optimized out>)                                                                                          
    at /usr/home/markj/src/freebsd-dev/gnu/usr.bin/binutils/ld/../../../../contrib/binutils/ld/ldmain.c:468

The problem seems to occur only if crt1.o, which is a partial link of crt1_c.o and crt1_s.o, is linked using lld. That is, if I link everything under lib/csu using lld and just link crt1.o using ld.bfd, the infinite loop doesn't occur.

If I try to link conftest.c using ld from binutils 2.30, I get an internal warning instead of a hang:

$ clang conftest.c                                                     
conftest.c:1:43: warning: control reaches end of non-void function [-Wreturn-type]                                                                           
int k; int foo () { __builtin_alloca (k); }                                            
1 warning generated.                                                                                           
/usr/bin/ld: Dwarf Error: Line info data is bigger (0xefb0101) than the space remaining in the section (0x23f)
/usr/lib/crt1.o: In function `_start1':                                        
(.text+0xa0): undefined reference to `main'                                    
clang: error: linker command failed with exit code 1 (use -v to see invocation)

So it looks like lld is somehow messing up the DWARF info when merging crt1_c.o and crt1_s.o.
Comment 1 Mark Johnston freebsd_committer 2018-06-04 21:14:17 UTC
The problem occurs with lld from the llvm-devel port as well:

$ ld --version
LLD 7.0.0 (compatible with GNU linkers)
Comment 2 Mark Johnston freebsd_committer 2018-06-06 15:33:48 UTC
The problem has to do with lld's implementation of partial linking (-r).  crt1.o is created with "ld -r -o crt1.o crt1_s.o crt1_c.o".  Both input object files contain debug info and relocations against that debug info.  Some of the relocations are against section symbols (STT_SECTION), so they must be processed before identical sections are merged.  However, lld doesn't do any of that:

 542     // This section contains relocation information.                                                      
 543     // If -r is given, we do not interpret or apply relocation                                            
 544     // but just copy relocation sections to output.                                                       
 545     if (Config->Relocatable)                                                                              
 546       return make<InputSection>(*this, Sec, Name);

As a result, one of the DIEs in the output object file contains a DW_AT_stmt_list with a bogus value.  That attribute is supposed to be an offset into .debug_line, and isn't getting adjusted properly when the two input .debug_line sections are concatenated.

We can potentially work around this by combining crt1_c.c and crt1_s.S into one file, but that would be rather unsatisfying.  I suspect that the next step would be to post to the LLVM ML and try to get a sense of how difficult this would be to fix.
Comment 3 Mark Johnston freebsd_committer 2018-06-07 16:30:25 UTC
Comment 4 Ed Maste freebsd_committer 2018-07-24 14:14:37 UTC
Oops, I should have tagged r336664 with this PR as well; I believe this issue should now be fixed.

Comment 5 Mark Johnston freebsd_committer 2018-07-24 21:24:40 UTC
(In reply to Ed Maste from comment #4)
Confirmed fixed with r336664.  Presumably we should MFC before marking the issue resolved?
Comment 6 Ed Maste freebsd_committer 2018-07-25 00:35:34 UTC
(In reply to Mark Johnston from comment #5)
Sounds good.
Comment 7 commit-hook freebsd_committer 2018-07-30 00:09:31 UTC
A commit references this bug:

Author: emaste
Date: Mon Jul 30 00:08:36 UTC 2018
New revision: 336880
URL: https://svnweb.freebsd.org/changeset/base/336880

  MFC r336664: lld: fix addends with partial linking

  [ELF] Update addends in non-allocatable sections for REL targets when
  creating a relocatable output.

  LLVM PR: 37735
  LLVM Differential Revision: https://reviews.llvm.org/D48929

  PR:		225128, 228753
  Obtained from:	LLVM r336799 by Igor Kudrin

_U  stable/11/
Comment 8 Ed Maste freebsd_committer 2018-07-30 00:09:40 UTC
r336664 now MFC'd as r336880