[ELF][ARM] Support /DISCARD/ of subset of .ARM.exidx sections

Both the .ARM.exidx and .eh_frame sections have a custom SyntheticSection
that acts as a container for the InputSections. The InputSections are added
to the SyntheticSection prior to /DISCARD/ which limits the affect a
/DISCARD/ can have to the whole SyntheticSection. In the majority of cases
this is sufficient as it is not common to discard subsets of the
InputSections. The Linux kernel has one of these scripts which has something
like:
/DISCARD/ : { *(.ARM.exidx.exit.text) *(.ARM.extab.exit.text) ... }
The .ARM.exidx.exit.text are not discarded because the InputSection has been
transferred to the Synthetic Section. The *(.ARM.extab.exit.text) sections
have not so they are discarded. When we come to write out the .ARM.exidx
sections the dangling references from .ARM.exidx.exit.text to
.ARM.extab.exit.text currently cause relocation out of range errors, but
could as easily cause a fatal error message if we check for dangling
references at relocation time.

This patch attempts to respect the /DISCARD/ command by running it on the
.ARM.exidx InputSections stored in the SyntheticSection.

The .eh_frame is in theory affected by this problem, but I don't think that
there is a dangling reference problem that can happen with these sections.

Fixes remaining part of pr44824

Differential Revision: https://reviews.llvm.org/D79687
This commit is contained in:
Peter Smith 2020-05-08 13:19:12 +01:00
parent 0e50b9a43b
commit 0ae7990b60
4 changed files with 74 additions and 5 deletions

View file

@ -407,14 +407,15 @@ static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
// Compute and remember which sections the InputSectionDescription matches.
std::vector<InputSectionBase *>
LinkerScript::computeInputSections(const InputSectionDescription *cmd) {
LinkerScript::computeInputSections(const InputSectionDescription *cmd,
ArrayRef<InputSectionBase *> sections) {
std::vector<InputSectionBase *> ret;
// Collects all sections that satisfy constraints of Cmd.
for (const SectionPattern &pat : cmd->sectionPatterns) {
size_t sizeBefore = ret.size();
for (InputSectionBase *sec : inputSections) {
for (InputSectionBase *sec : sections) {
if (!sec->isLive() || sec->parent)
continue;
@ -465,13 +466,29 @@ void LinkerScript::discard(InputSectionBase *s) {
discard(ds);
}
void LinkerScript::discardSynthetic(OutputSection &outCmd) {
for (Partition &part : partitions) {
if (!part.armExidx || !part.armExidx->isLive())
continue;
std::vector<InputSectionBase *> secs(part.armExidx->exidxSections.begin(),
part.armExidx->exidxSections.end());
for (BaseCommand *base : outCmd.sectionCommands)
if (auto *cmd = dyn_cast<InputSectionDescription>(base)) {
std::vector<InputSectionBase *> matches =
computeInputSections(cmd, secs);
for (InputSectionBase *s : matches)
discard(s);
}
}
}
std::vector<InputSectionBase *>
LinkerScript::createInputSectionList(OutputSection &outCmd) {
std::vector<InputSectionBase *> ret;
for (BaseCommand *base : outCmd.sectionCommands) {
if (auto *cmd = dyn_cast<InputSectionDescription>(base)) {
cmd->sectionBases = computeInputSections(cmd);
cmd->sectionBases = computeInputSections(cmd, inputSections);
for (InputSectionBase *s : cmd->sectionBases)
s->parent = &outCmd;
ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end());
@ -492,6 +509,7 @@ void LinkerScript::processSectionCommands() {
if (sec->name == "/DISCARD/") {
for (InputSectionBase *s : v)
discard(s);
discardSynthetic(*sec);
sec->sectionCommands.clear();
continue;
}

View file

@ -245,10 +245,13 @@ class LinkerScript final {
void expandMemoryRegions(uint64_t size);
std::vector<InputSectionBase *>
computeInputSections(const InputSectionDescription *);
computeInputSections(const InputSectionDescription *,
ArrayRef<InputSectionBase *>);
std::vector<InputSectionBase *> createInputSectionList(OutputSection &cmd);
void discardSynthetic(OutputSection &);
std::vector<size_t> getPhdrIndices(OutputSection *sec);
MemoryRegion *findMemoryRegion(OutputSection *sec);

View file

@ -3263,7 +3263,7 @@ ARMExidxSyntheticSection::ARMExidxSyntheticSection()
static InputSection *findExidxSection(InputSection *isec) {
for (InputSection *d : isec->dependentSections)
if (d->type == SHT_ARM_EXIDX)
if (d->type == SHT_ARM_EXIDX && d->isLive())
return d;
return nullptr;
}

View file

@ -0,0 +1,48 @@
// REQUIRES: arm
// RUN: llvm-mc --arm-add-build-attributes --triple=armv7a-linux-gnueabihf -filetype=obj %s -o %t.o
// RUN: echo "SECTIONS { \
// RUN: /DISCARD/ : { *(.ARM.exidx.exit.text) *(.ARM.extab.exit.text)} \
// RUN: . = 0x90000000; \
// RUN: .ARM.exidx : { *(.ARM.exidx) } \
// RUN: .text : { *(.text) } \
// RUN: .exit.text : { *(.exit.text) } \
// RUN: .rodata : { *(.rodata) } \
// RUN: } " > %t.script
// RUN: ld.lld --script %t.script %t.o -o %t
// RUN: llvm-readelf -x .ARM.exidx %t | FileCheck %s
/// The linker script /DISCARDS/ the .ARM.exidx and .ARM.extab for the
/// .exit.text . If we do not discard both sections we will end up with
/// a dangling reference. We expect no linker error for an out of range
/// relocation/dangling reference and just a single .ARM.exidx entry
/// for _start and an entry for the terminating sentinel.
// CHECK: Hex dump of section '.ARM.exidx':
// CHECK-NEXT: 0x90000000 10000000 01000000 10000000 01000000
// CHECK-NOT: 0x90000010
.text
.global _start
.type _start, %function
_start:
.fnstart
bx lr
.cantunwind
.fnend
.section .exit.text, "ax", %progbits
.global exit_text
.type exit_text, %function
exit_text:
.fnstart
bx lr
.personality __gxx_personality_v0
.handlerdata
.long 0
.fnend
/// Dummy definition for a reference from the personality routine created by
/// the assembler, use .data to avoid generating a cantunwind table.
.section .rodata
.global __aeabi_unwind_cpp_pr0
__aeabi_unwind_cpp_pr0:
.word 0