This is an archive of the discontinued LLVM Phabricator instance.

[PowerPC][ELF] Place .toc in the same COMDAT group as the target object
AbandonedPublic

Authored by MaskRay on Feb 29 2020, 6:16 PM.

Details

Reviewers
Bdragon28
jhibbits
Group Reviewers
Restricted Project
Summary

.text.foo (SHF_GROUP) references .toc
.toc references .rodata.foo (SHF_GROUP)
If .text.foo and .rodata.foo are discarded by the section group rule =>
.toc referencing .rodata.foo (STB_LOCAL) is disallowed by the ELF spec (http://www.sco.com/developers/gabi/latest/ch4.sheader.html):

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.

lld .toc hacks (rL363126 and rL364391) allow this, but we should
eventually get rid of the hacks.

New PowerPC/ppc32-pic-large.ll tests check that we don't place .got2 in a COMDAT GROUP =>
lwz 3, .LC0-.LTOC(30) is not representable if .LC0 and .LTOC are in different .got2 sections

Diff Detail

Event Timeline

MaskRay created this revision.Feb 29 2020, 6:16 PM
MaskRay updated this revision to Diff 247472.Feb 29 2020, 6:20 PM

Make a LARGE-SECUREPLT: line generic

MaskRay edited the summary of this revision. (Show Details)Feb 29 2020, 6:21 PM

Still working on testing this one.

I'm not sure if this is an artifact of my attempts to force clang to be an external toolchain or if this is a break yet.

--- all_subdir_lib/libdevdctl ---
ld: error: relocation refers to a discarded section: .toc
>>> defined in event.pico
>>> referenced by event.cc:268 (/usr/src/lib/libdevdctl/event.cc:268)
>>>               event.pico:(DevdCtl::Event::GetTimestamp() const)
>>> referenced by event.cc:268 (/usr/src/lib/libdevdctl/event.cc:268)
>>>               event.pico:(DevdCtl::Event::GetTimestamp() const)
ld: error: relocation refers to a discarded section: .toc
>>> defined in exception.pico
>>> referenced by exception.cc:94 (/usr/src/lib/libdevdctl/exception.cc:94)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
>>> referenced by exception.cc:94 (/usr/src/lib/libdevdctl/exception.cc:94)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
ld: error: relocation refers to a discarded section: .toc
>>> defined in exception.pico
>>> referenced by sstream:911 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/sstream:911)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
>>> referenced by sstream:911 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/sstream:911)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
ld: error: relocation refers to a discarded section: .toc
>>> defined in exception.pico
>>> referenced by istream:191 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/istream:191)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
>>> referenced by istream:191 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/istream:191)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
ld: error: relocation refers to a discarded section: .toc
>>> defined in exception.pico
>>> referenced by sstream:244 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/sstream:244)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
>>> referenced by sstream:244 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/sstream:244)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
ld: error: relocation refers to a discarded section: .toc
>>> defined in exception.pico
>>> referenced by iosfwd:139 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/iosfwd:139)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
>>> referenced by iosfwd:139 (/usr/obj/usr/src/powerpc.powerpc64/tmp/usr/include/c++/v1/iosfwd:139)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
>>> referenced by exception.cc:0 (/usr/src/lib/libdevdctl/exception.cc:0)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
>>> referenced by exception.cc:0 (/usr/src/lib/libdevdctl/exception.cc:0)
>>>               exception.pico:(DevdCtl::ParseException::ParseException(DevdCtl::ParseException::Type, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long))
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

Still working on testing this one.

I'm not sure if this is an artifact of my attempts to force clang to be an external toolchain or if this is a break yet.

--- all_subdir_lib/libdevdctl ---
ld: error: relocation refers to a discarded section: .toc

ld: error: relocation refers to a discarded section: .toc was worked around in lld by rL363126.

Right, which is why it was so surprising to see it again in HEAD. I'm still trying to get a reproduce.

I'm pretty sure I'm just tripping over c++ weirdness related to trying to use an external llvm HEAD compiler as a toolchain for the same platform. I will retry from my cross build machine.

OK, I reinterpreted 9569a1472ee7fee37f7f991d34634c5d8d1f3559 (as a prereq to reduce the churn) and this patch in the context of llvm10 (mainly re-uppercasing function names so that stuff applies and converting the MCSection::NonUniqueID bit back into ~0) so I can run it in-tree for a FreeBSD buildworld, and I hit the exact same failure, so it looks like there's an actual problem here.

Here's the LLD_REPRODUCE using the cross toolchain (since I had it already and I hit the same thing on the backport, this one is probably the best one to look at)

MaskRay abandoned this revision.EditedMar 1 2020, 9:41 PM

This is a fundamental problem of .toc . It cannot be fixed, oh, well, without some ELF extensions.

For @Bdragon28's reproduce file,

A .text (not in a section group) references foo defined in .data.rel.ro.foo (in a section group) via .toc .

.text
addis 3,2,.LC0@toc@ha

.section .data.rel.ro.foo,"aGw",foo,comdat
.globl foo
foo:

.section .toc,"aGw",@progbits,foo,comdat  # caused by this patch
.LC0:
.tc foo[TC],foo

This patch emits .section .toc,"aGw",foo,comdat.
When .data.rel.ro.foo and the .toc are discarded due to the section group rule, the relocation from .text to the .toc becomes dangling.

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.

One thought is to change the .toc reference to a STB_GLOBAL:

.text
addis 3,2,foo.toc@toc@ha

.section .toc,"aGw",@progbits,foo,comdat
.globl foo.toc
foo.toc:
.tc foo[TC],foo

Say, both a.o and b.o have the code sequence above. If a.o(.toc) is the prevailing definition, the symbolic reference add 3,2,foo.toc@toc@ha from b.o will bind to a.o(.toc) (like an external reference).

Everything works fine except one thing: foo.toc is left in .symtab (unless --strip-all) and probably .dynsym. If we set the visibility of foo.toc to STB_HIDDEN or STB_INTERNAL, foo.toc will be omitted from .dynsym, but we cannot omit it from .symtab.
Unless we extend ELF and say STB_INTERNAL symbols are omitted from .symtab.

I have a feeling that the .tc directive was misdesigned for ELF. If we let foo@toc@ha create a TOC entry implicitly (like a GOT-generating relocation on other architectures), we would not need multiple .toc sections in the first place. Additionally, toc-indirect to toc-relative relaxation would become easier to implement. Note, explicit .section .toc,"aw",@progbits can still be allowed if we want to emit some non-symbol entries. They should still be explicit.

It is sad that .toc is prettier than ppc32 .got2, but that is the pot calling the kettle black.