llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.01k stars 11.95k forks source link

clang generates relocs using discard-able symbols #13223

Open llvmbot opened 12 years ago

llvmbot commented 12 years ago
Bugzilla Link 12851
Version trunk
OS Solaris
Reporter LLVM Bugzilla Contributor
CC @majnemer

Extended Description

Hello!

I faced the following problem with clang and Solaris linker when building code that contains COMDAT groups with section containing template function instantiations.

$ cat -n a.cpp
      1  #include "a.h"
      2
      3  void baz()
      4  {
      5      bar(10);
      6  }
$ cat -n b.cpp
      1  #include "a.h"
      2
      3  void foo()
      4  {
      5      bar(12);
      6  }
$ cat -n a.h
      1  struct S
      2  {
      3      ~S();
      4  };
      5
      6  template<typename T>
      7  int bar(T t)
      8  {
      9      S s;
     10      return t*3;
     11  }
$ /opt/clang/bin/clang++ -c a.cpp
$ /opt/clang/bin/clang++ -c b.cpp
$ elfdump -c a.o | grep ^Section
Section Header[1]:  sh_name: .group
Section Header[2]:  sh_name: .text
Section Header[3]:  sh_name: .rel.text
Section Header[4]:  sh_name: .data
Section Header[5]:  sh_name: .bss
Section Header[6]:  sh_name: .text._Z3barIiEiT_
Section Header[7]:  sh_name: .rel.text._Z3barIiEiT_
Section Header[8]:  sh_name: .note.GNU-stack
Section Header[9]:  sh_name: .eh_frame
Section Header[10]:  sh_name: .rel.eh_frame
Section Header[11]:  sh_name: .shstrtab
Section Header[12]:  sh_name: .symtab
Section Header[13]:  sh_name: .strtab
$ elfdump -g a.o

Group Section:  .group
      index    flags / section         signature symbol
        [0]   [ COMDAT ]               _Z3barIiEiT_
        [1]   .text._Z3barIiEiT_ [6]
$ ld -Dsections -r -o all.o a.o b.o
debug:
debug: Solaris Linkers: 5.10-1.1505
debug:
debug: section=[1].group; input from file=a.o
debug: section=[1].group; input from file=a.o; defines COMDAT group: 
signature symbol: _Z3barIiEiT_
debug: section=.group; added to segment=extra (created)
...
debug: section=[6].text._Z3barIiEiT_; input from file=a.o
debug: section=[6].text._Z3barIiEiT_; input from file=a.o; member of 
COMDAT group: signature symbol: _Z3barIiEiT_
debug: section=.text._Z3barIiEiT_; added to segment=text (created)
...
debug: section=[9].eh_frame; input from file=a.o
debug: section=.eh_frame; added to segment=data (created)
...
debug: section=[1].group; input from file=b.o
debug: section=[1].group; input from file=b.o; defines COMDAT group: 
signature symbol: _Z3barIiEiT_
debug: section=[1].group; input from file=b.o; discarded in favor of 
group: signature symbol: _Z3barIiEiT_: file=a.o
...
debug: section=[6].text._Z3barIiEiT_; input from file=b.o
debug: section=[6].text._Z3barIiEiT_; input from file=b.o; member of 
COMDAT group: signature symbol: _Z3barIiEiT_
debug: section=[6].text._Z3barIiEiT_; input from file=b.o; discarded in 
favor of group: signature symbol: _Z3barIiEiT_: file=a.o
...
debug: section=[9].eh_frame; input from file=b.o
debug: section=.eh_frame; added to segment=data
debug:
ld: fatal: relocation error: R_386_32: file b.o: section 
[10].rel.eh_frame: symbol .text._Z3barIiEiT_ (section): symbol has been 
discarded with discarded section: [6].text._Z3barIiEiT_

So the linker successfully discarded .text.Z3barIiEiT in b.o in favor of the one in a.o

But it got problems when processing relocations for .eh_frame section in b.o

$ elfdump -r -N .rel.eh_frame b.o
Relocation Section:  .rel.eh_frame
     type                       offset             section        symbol
   R_386_32                       0x20             .rel.eh_frame  .text 
(section)
   R_386_32                       0x3c             .rel.eh_frame  
.text._Z3barIiEiT_ (section)

$ dump -r b.o
b.o:
     **** RELOCATION INFORMATION ****
...
.rel.eh_frame:
Offset      Symndx              Type
0x20        2                   1
0x3c        5                   1

$ elfdump -l -s b.o

Symbol Table Section:  .symtab
      index    value      size      type bind oth ver shndx / name
        [0]  0x00000000 0x00000000  NOTY LOCL  D    0 UNDEF
        [1]  0x00000000 0x00000000  FILE LOCL  D    0 ABS            b.cpp
        [2]  0x00000000 0x00000000  SECT LOCL  D    0 .text
        [3]  0x00000000 0x00000000  SECT LOCL  D    0 .data
        [4]  0x00000000 0x00000000  SECT LOCL  D    0 .bss
        [5]  0x00000000 0x00000000  SECT LOCL  D    0 .text._Z3barIiEiT_
        [6]  0x00000000 0x00000000  SECT LOCL  D    0 .note.GNU-stack
        [7]  0x00000000 0x00000000  SECT LOCL  D    0 .eh_frame
        [8]  0x00000000 0x00000000  SECT LOCL  D    0 .group
        [9]  0x00000000 0x00000030  FUNC WEAK  D    0 .text._Z3barIiEiT_ 
_Z3barIiEiT_
       [10]  0x00000000 0x00000022  FUNC GLOB  D    0 .text          _Z3foov
       [11]  0x00000000 0x00000000  NOTY GLOB  D    0 UNDEF          
_ZN1SD1Ev

The second relocation entry in .rel.eh_frame references section symbol [5].text._Z3barIiEiT_ which is LOCAL and thus is discarded with discarded section .text._Z3barIiEiT_

llvmbot commented 12 years ago

As suggested here http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-May/021478.html I manually edited generated asm replacing section symbol (.text._Z3barIiEiT_) in "FDE initial location" in .eh_frame with function symbol (_Z3barIiEiT_). And after assembling linking went fine.

llvmbot commented 12 years ago

According to ELF std related to COMDAT section groups:

http://www.sco.com/developers/gabi/latest/ch4.sheader.html#section_groups

A symbol table entry with STB_LOCAL binding that is defined relative to one of a group's sections, and that is contained in a symbol table section that is not part of the group, must be discarded if the group members are discarded. References to this symbol table entry from outside the group are not allowed.