Why clang creates ELF section group with only one section in it?

Hello!

I have the following linking problem with clang on Solaris 10:

$ 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++ a.cpp b.cpp
ld: fatal: relocation error: file: /tmp/b-.qa4V1.o section: .rel.eh_frame symbol: : symbol has been discarded with discarded section: .text._Z3barIiEiT_
clang: error: linker command failed with exit code 1 (use -v to see invocation)

This happens only on releases < U10, so I suspect that this is due to some Solaris linker bug/restriction which was fixed/relaxed in U10.

But, I found that I can workaround this error by avoiding creating .group section in object files:

$ elfdump -g a.o

Group Section: .group
      index flags / section signature symbol
        [0] [ COMDAT ] _Z3barIiEiT_
        [1] .text._Z3barIiEiT_ [6]

This group contains only one section, is it really needed?

GCC (4.5.1, 4.7.0) doesn't create one.
Sun C++ 5.11 creates group with 2 sections: bar<int>() text and relocs.

But, I found that I can workaround this error by avoiding creating
.group section in object files:

$ elfdump -g a.o

Group Section: .group
index flags / section signature symbol
[0] [ COMDAT ] _Z3barIiEiT_
[1] .text._Z3barIiEiT_ [6]

This group contains only one section, is it really needed?

GCC (4.5.1, 4.7.0) doesn't create one.
Sun C++ 5.11 creates group with 2 sections: bar<int>() text and relocs.

gcc 4.6 on linux produces an output very similar to what clang does.
The groups (comdats) are a generic way to let the linker discard
sections very quickly. In this case it is used for discarding a
method instantiated in two files.

Just dropping the group would probably create an executable with two
copies of the method. Is that what you get?

From your description of the problem, it looks like old version of the

solaris linker cannot handle groups very well and expect sections to
be organized in some particular way. If you can figure that out you
might be able to implement it in llvm.

Cheers,
Rafael

But then it makes sense to put relocs against this section in the same group also so they can be discarded together (as Sun C++ does).

The problem is that discarded section is referenced from the section outside of the discarded group (.rela.eh_frame) via discarded section symbol.

If I understand correctly wording of ELF std this is not allowed:
() And here this discarded symbol is referenced via relocation against .eh_frame section. $ ld -r -o all.o a.o b.o 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 Yes, this is exactly what I get. But at least I can link :slight_smile:

But then it makes sense to put relocs against this section in the same group
also so they can be discarded together (as Sun C++ does).

I am not sure I understand. The regular way of relocations are
recorded on ELF is by having a relocation section for each section
that needs one. In your example we have (both gcc and clang):

Relocation section '.rela.text' at offset 0x690 contains 1 entries:
    Offset Info Type Symbol's
Value Symbol's Name + Addend
000000000000000a 0000000b00000002 R_X86_64_PC32
0000000000000000 _Z3barIiEiT_ - 4

It is a relocation on .text that points to _Z3barIiEiT_. We also have

Relocation section '.rela.text._Z3barIiEiT_' at offset 0x6a8 contains 1 entries:
    Offset Info Type Symbol's
Value Symbol's Name + Addend
0000000000000013 0000000c00000002 R_X86_64_PC32
0000000000000000 _ZN1SD1Ev -

Which is a relocation *in* _Z3barIiEiT_. Note that _Z3barIiEiT_ is
*not* STB_LOCAL.

Cheers,
Rafael

Hello Rafael!

There are actually 2 (related) questions.

But then it makes sense to put relocs against this section in the same group
also so they can be discarded together (as Sun C++ does).

I am not sure I understand. The regular way of relocations are
recorded on ELF is by having a relocation section for each section
that needs one.

Yes.
So if the section with function code (.text._Z3barIiEiT_) is discarded there is no point to have corresponding reloc section.
So it makes sense to put it in the same COMDAT group as .text._Z3barIiEiT_
This is what Sun CC does:

$ CC -V
usage: CC [ options ] files. Use 'CC -flags' for details
$ CC -c a.cpp
$ elfdump -g a.o

Group Section: .group%__1cDbar4Ci_6FTA_i_
      index flags / section signature symbol
        [0] [ COMDAT ] __1cDbar4Ci_6FTA_i_
        [1] .text%__1cDbar4Ci_6FTA_i_ [4]
        [2] .rel.text%__1cDbar4Ci_6FTA_i_ [18]
$ echo __1cDbar4Ci_6FTA_i_ | c++filt
int bar<int>(__type_0)

Compare with clang:

$ /opt/clang/bin/clang++ -c a.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]

This is the first question -- why clang doesn't put both sections to COMDAT group?

The second question is about relocation against .eh_frame section which Solaris ld is complaining about.

What I'm trying to do:

$ /opt/clang/bin/clang++ -c a.cpp
$ /opt/clang/bin/clang++ -c b.cpp
$ 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_

Of course, this is my understanding of what linker is saying.

Hello Rafael!

There are actually 2 (related) questions.

Yes, sorry, I was confusing the two.

So if the section with function code (.text._Z3barIiEiT_) is discarded there
is no point to have corresponding reloc section.
So it makes sense to put it in the same COMDAT group as .text._Z3barIiEiT_
This is what Sun CC does:

$ CC -V
CC: Sun C++ 5.11 SunOS_i386 145731-02 2011/02/11
usage: CC [ options ] files. Use 'CC -flags' for details
$ CC -c a.cpp
$ elfdump -g a.o

Group Section: .group%__1cDbar4Ci_6FTA_i_

index    flags / section         signature symbol
  \[0\]   \[ COMDAT \]               \_\_1cDbar4Ci\_6FTA\_i\_
  \[1\]   \.text%\_\_1cDbar4Ci\_6FTA\_i\_ \[4\]
  \[2\]   \.rel\.text%\_\_1cDbar4Ci\_6FTA\_i\_ \[18\]

$ echo __1cDbar4Ci_6FTA_i_ | c++filt
int bar<int>(__type_0)

Compare with clang:

$ /opt/clang/bin/clang++ -c a.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]

This is the first question -- why clang doesn't put both sections to COMDAT
group?

Good point. We can probably move it there (assuming gold and gnu ld
are OK with it). Would you mind opening a bug about just this bit?

The second question is about relocation against .eh_frame section which
Solaris ld is complaining about.

What I'm trying to do:

$ /opt/clang/bin/clang++ -c a.cpp
$ /opt/clang/bin/clang++ -c b.cpp
$ 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_

Of course, this is my understanding of what linker is saying.

OK, I understand this too now. It looks like the problem is coming
from the relocations for "FDE initial location". They are easy to see
with

$ clang -S a.cpp -fno-dwarf2-cfi-asm

We have something like

_Z3bazv: # @_Z3bazv
.Ltmp2:
  .long .Ltmp2 # FDE initial location

It would probably be OK to use the symbol directly. Would that fix the
link for you?

Cheers,
Rafael

Good point. We can probably move it there (assuming gold and gnu ld are OK with it). Would you mind opening a bug about just this bit?

Created http://llvm.org/bugs/show_bug.cgi?id=12843

OK, I understand this too now. It looks like the problem is coming
from the relocations for "FDE initial location". They are easy to see
with

$ clang -S a.cpp -fno-dwarf2-cfi-asm

We have something like

_Z3bazv: # @_Z3bazv
.Ltmp2:
  .long .Ltmp2 # FDE initial location

It would probably be OK to use the symbol directly. Would that fix the
link for you?

Yes, after changing .LtmpXX label to function name in 'FDE initial location' I was able to link fine using both old and new Solaris linkers.
Should I open another case for this?

Thank you!

Yes, after changing .LtmpXX label to function name in 'FDE initial location'
I was able to link fine using both old and new Solaris linkers.
Should I open another case for this?

I think so, yes.

If I remember correctly, we use a local symbol to avoid relocations in
cases gas is funny and produces them when we don't need, but an
.eh_frame will always be pointing to another section, so we need the
relocation anyway.

Thank you!

Thanks,
Rafael

Hi Rafael!