[PATCH] D29327: [LLD][ELF] Use Synthetic Sections for Thunks (try 2)
Rafael Avila de Espindola via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 31 12:58:36 PST 2017
LGTM, we can refine it in trunk.
Peter Smith <peter.smith at linaro.org> writes:
> It is possible, although somewhat contrived, to mix executable and
> non-executable input sections within the same output section with
> linker scripts. From what I can tell it isn't possible for linker
> generated Output Sections.
>
> For example:
> SECTIONS {
> .text : { *(.text) *(.rodata) }
> }
> I've checked that with a simple assembler file:
> .syntax unified
> .text
> nop
> .rodata
> .word 10
>
> We get one .text OutputSection (--Map)
> 00000000 00000008 4 .text
> 00000000 00000004 4 .text
> 00000000 00000004 4 t.o
> 00000000 00000000 0 $a.0
> 00000004 00000004 1 .rodata
> 00000004 00000004 1 t.o
> 00000004 00000000 0 $d.1
>
> On 31 January 2017 at 15:45, Rafael Avila de Espindola
> <rafael.espindola at gmail.com> wrote:
>> When do we get both executable and non executable sections in the same
>> output section?
>>
>> I have attached the diff from the previous version to make it easier to
>> compare.
>>
>> Cheers,
>> Rafael
>>
>> diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
>> index 4d2ff37..3868de3 100644
>> --- a/ELF/Relocations.cpp
>> +++ b/ELF/Relocations.cpp
>> @@ -818,16 +818,21 @@ static void mergeThunks(OutputSection<ELFT> *OS,
>> // Merge sorted vectors of Thunks and InputSections by OutSecOff
>> std::vector<InputSection<ELFT> *> Tmp;
>> Tmp.reserve(OS->Sections.size() + Thunks.size());
>> - auto MergeCmp = [](const ThunkSection<ELFT> *Thunk,
>> - const InputSection<ELFT> *IS) {
>> - // All thunks go before any non-executable InputSections
>> - if ((IS->Flags & SHF_EXECINSTR) == 0)
>> + auto MergeCmp = [](const InputSection<ELFT> *A, const InputSection<ELFT> *B) {
>> + // MSVC debug implementation checks std library preconditions so we can't
>> + // assume A will be Thunk, also both Thunks and InputSections must be
>> + // ordered by MergeCmp prior to merge.
>> + if (A->OutSecOff < B->OutSecOff)
>> return true;
>> - // Some Thunk Sections such as the Mips LA25 thunk must be placed before
>> - // the InputSections that they target. We represent this by assigning the
>> - // ThunkSection the same OutSecOff and always placing the Thunk first if
>> - // the OutSecOff values are the same.
>> - return Thunk->OutSecOff <= IS->OutSecOff;
>> + if (A->OutSecOff == B->OutSecOff) {
>> + // Check if Thunk is immediately before any specific Target InputSection
>> + // for example Mips LA25 Thunks.
>> + auto *TA = dyn_cast<ThunkSection<ELFT>>(A);
>> + auto *TB = dyn_cast<ThunkSection<ELFT>>(B);
>> + if (TA && !TB && TA->getTargetInputSection() == B)
>> + return true;
>> + }
>> + return false;
>> };
>> std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(),
>> Thunks.end(), std::back_inserter(Tmp), MergeCmp);
>> @@ -875,10 +880,17 @@ void createThunks(ArrayRef<OutputSectionBase *> OutputSections) {
>> ThunkedSections[IS] = TS;
>> return TS;
>> };
>> - // Find or create a ThunkSection to be placed at the end of OS
>> + // Find or create a ThunkSection to be placed as last executable section in
>> + // OS.
>> auto GetOSThunkSec = [&](ThunkSection<ELFT> *&TS, OutputSection<ELFT> *OS) {
>> if (TS == nullptr) {
>> - TS = make<ThunkSection<ELFT>>(OS, OS->Size);
>> + uint32_t Off = 0;
>> + for (auto *IS : OS->Sections) {
>> + Off = IS->OutSecOff + IS->getSize();
>> + if ((IS->Flags & SHF_EXECINSTR) == 0)
>> + break;
>> + }
>> + TS = make<ThunkSection<ELFT>>(OS, Off);
>> ThunkSections[OS].push_back(TS);
>> }
>> return TS;
>> diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
>> index 0bfe5e4..0e6d798 100644
>> --- a/ELF/SyntheticSections.cpp
>> +++ b/ELF/SyntheticSections.cpp
>> @@ -1906,7 +1906,7 @@ void ARMExidxSentinelSection<ELFT>::writeTo(uint8_t *Buf) {
>>
>> template <class ELFT>
>> ThunkSection<ELFT>::ThunkSection(OutputSectionBase *OS, uint64_t Off)
>> - : SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS,
>> + : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
>> sizeof(typename ELFT::uint), ".text.thunk") {
>> this->OutSec = OS;
>> this->OutSecOff = Off;
>> @@ -1925,6 +1925,12 @@ template <class ELFT> void ThunkSection<ELFT>::writeTo(uint8_t *Buf) {
>> T->writeTo(Buf + T->Offset, *this);
>> }
>>
>> +template <class ELFT>
>> +InputSection<ELFT> *ThunkSection<ELFT>::getTargetInputSection() const {
>> + const Thunk<ELFT> *T = Thunks.front();
>> + return T->getTargetInputSection();
>> +}
>> +
>> template InputSection<ELF32LE> *elf::createCommonSection();
>> template InputSection<ELF32BE> *elf::createCommonSection();
>> template InputSection<ELF64LE> *elf::createCommonSection();
>> diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
>> index e5a6295..a666d73 100644
>> --- a/ELF/SyntheticSections.h
>> +++ b/ELF/SyntheticSections.h
>> @@ -713,6 +713,7 @@ public:
>> void addThunk(Thunk<ELFT> *T);
>> size_t getSize() const override { return Size; }
>> void writeTo(uint8_t *Buf) override;
>> + InputSection<ELFT> *getTargetInputSection() const;
>>
>> private:
>> std::vector<const Thunk<ELFT> *> Thunks;
>>
>>
>> Peter Smith via Phabricator <reviews at reviews.llvm.org> writes:
>>
>>> peter.smith created this revision.
>>>
>>> This is https://reviews.llvm.org/D29129 with the Windows debug build problems fixed.
>>>
>>> The MSVC debug implementation of std::merge enforces the preconditions required by the C++ standard. This includes checking that both ranges are sortable by the predicate and that if (A < B) then !(B > A). https://reviews.llvm.org/D29129 the comparison routine did not conform to the requirements of the standard. This change fixes the predicate.
>>>
>>> The changes made are all related to the comparison routine:
>>> SyntheticSections:
>>>
>>> - add getTargetInputSection to ThunkSection
>>> - correct section flags in constructor. ThunkSections was missing SHF_EXECINSTR
>>>
>>> Relocations:
>>>
>>> - Set the OutSecOff of the per-OutputSection ThunkSection to be the limit of the executable sections, previously we set the OutSecOff to size, and checked in the predicate whether the Thunk and InputSection were executable.
>>> - Rewrite the MergeComp predicate to use only OutSecOff and as a tie-breaker for Mips LA25 whether the next section is our Thunks Target.
>>>
>>> I've checked that this builds and runs the tests on MSVC 2015. Sending for review as it is more than just a simple syntax fix.
>>>
>>>
>>> https://reviews.llvm.org/D29327
>>>
>>> Files:
>>> ELF/InputFiles.cpp
>>> ELF/InputSection.cpp
>>> ELF/InputSection.h
>>> ELF/LTO.cpp
>>> ELF/LTO.h
>>> ELF/Relocations.cpp
>>> ELF/Relocations.h
>>> ELF/SymbolTable.cpp
>>> ELF/Symbols.cpp
>>> ELF/Symbols.h
>>> ELF/SyntheticSections.cpp
>>> ELF/SyntheticSections.h
>>> ELF/Target.cpp
>>> ELF/Target.h
>>> ELF/Thunks.cpp
>>> ELF/Thunks.h
>>> ELF/Writer.cpp
>>> test/ELF/arm-thumb-interwork-shared.s
>>> test/ELF/arm-thumb-interwork-thunk.s
>>> test/ELF/mips-npic-call-pic.s
>>>
>>> Index: test/ELF/mips-npic-call-pic.s
>>> ===================================================================
>>> --- test/ELF/mips-npic-call-pic.s
>>> +++ test/ELF/mips-npic-call-pic.s
>>> @@ -15,115 +15,124 @@
>>>
>>> # CHECK: Disassembly of section .text:
>>> # CHECK-NEXT: __start:
>>> -# CHECK-NEXT: 20000: 0c 00 80 0e jal 131128 <foo1b+0x4>
>>> -# ^-- .pic.foo1a
>>> +# CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 <__LA25Thunk_foo1a>
>>> # CHECK-NEXT: 20004: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20008: 0c 00 80 19 jal 131172 <foo2+0x4>
>>> -# ^-- .pic.foo2
>>> +# CHECK-NEXT: 20008: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2>
>>> # CHECK-NEXT: 2000c: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20010: 0c 00 80 12 jal 131144 <foo1b+0x14>
>>> -# ^-- .pic.foo1b
>>> +# CHECK-NEXT: 20010: 0c 00 80 10 jal 131136 <__LA25Thunk_foo1b>
>>> # CHECK-NEXT: 20014: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20018: 0c 00 80 19 jal 131172 <foo2+0x4>
>>> -# ^-- .pic.foo2
>>> +# CHECK-NEXT: 20018: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2>
>>> # CHECK-NEXT: 2001c: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20020: 0c 00 80 25 jal 131220 <fnpic+0x4>
>>> -# ^-- .pic.fpic
>>> +# CHECK-NEXT: 20020: 0c 00 80 1d jal 131188 <__LA25Thunk_fpic>
>>> # CHECK-NEXT: 20024: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20028: 0c 00 80 24 jal 131216 <fnpic>
>>> +# CHECK-NEXT: 20028: 0c 00 80 28 jal 131232 <fnpic>
>>> # CHECK-NEXT: 2002c: 00 00 00 00 nop
>>> #
>>> -# CHECK: foo1a:
>>> -# CHECK-NEXT: 20030: 00 00 00 00 nop
>>> -#
>>> -# CHECK: foo1b:
>>> -# CHECK-NEXT: 20034: 00 00 00 00 nop
>>> -#
>>> -# CHECK-NEXT: 20038: 3c 19 00 02 lui $25, 2
>>> -# CHECK-NEXT: 2003c: 08 00 80 0c j 131120 <foo1a>
>>> -# CHECK-NEXT: 20040: 27 39 00 30 addiu $25, $25, 48
>>> -# CHECK-NEXT: 20044: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20048: 3c 19 00 02 lui $25, 2
>>> -# CHECK-NEXT: 2004c: 08 00 80 0d j 131124 <foo1b>
>>> -# CHECK-NEXT: 20050: 27 39 00 34 addiu $25, $25, 52
>>> +# CHECK: __LA25Thunk_foo1a:
>>> +# CHECK-NEXT: 20030: 3c 19 00 02 lui $25, 2
>>> +# CHECK-NEXT: 20034: 08 00 80 14 j 131152 <foo1a>
>>> +# CHECK-NEXT: 20038: 27 39 00 50 addiu $25, $25, 80
>>> +# CHECK-NEXT: 2003c: 00 00 00 00 nop
>>> +
>>> +# CHECK: __LA25Thunk_foo1b:
>>> +# CHECK-NEXT: 20040: 3c 19 00 02 lui $25, 2
>>> +# CHECK-NEXT: 20044: 08 00 80 15 j 131156 <foo1b>
>>> +# CHECK-NEXT: 20048: 27 39 00 54 addiu $25, $25, 84
>>> +# CHECK-NEXT: 2004c: 00 00 00 00 nop
>>> +
>>> +# CHECK: foo1a:
>>> +# CHECK-NEXT: 20050: 00 00 00 00 nop
>>> +
>>> +# CHECK: foo1b:
>>> # CHECK-NEXT: 20054: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20058: 00 00 00 00 nop
>>> -# CHECK-NEXT: 2005c: 00 00 00 00 nop
>>> -#
>>> -# CHECK: foo2:
>>> -# CHECK-NEXT: 20060: 00 00 00 00 nop
>>> -#
>>> -# CHECK-NEXT: 20064: 3c 19 00 02 lui $25, 2
>>> -# CHECK-NEXT: 20068: 08 00 80 18 j 131168 <foo2>
>>> -# CHECK-NEXT: 2006c: 27 39 00 60 addiu $25, $25, 96
>>> +
>>> +# CHECK: __LA25Thunk_foo2:
>>> +# CHECK-NEXT: 20058: 3c 19 00 02 lui $25, 2
>>> +# CHECK-NEXT: 2005c: 08 00 80 1c j 131184 <foo2>
>>> +# CHECK-NEXT: 20060: 27 39 00 70 addiu $25, $25, 112
>>> +# CHECK-NEXT: 20064: 00 00 00 00 nop
>>> +# CHECK-NEXT: 20068: 00 00 00 00 nop
>>> +# CHECK-NEXT: 2006c: 00 00 00 00 nop
>>> +
>>> +# CHECK: foo2:
>>> # CHECK-NEXT: 20070: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20074: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20078: 00 00 00 00 nop
>>> -# CHECK-NEXT: 2007c: 00 00 00 00 nop
>>> -#
>>> -# CHECK: fpic:
>>> -# CHECK-NEXT: 20080: 00 00 00 00 nop
>>> -#
>>> -# CHECK: fnpic:
>>> +
>>> +# CHECK: __LA25Thunk_fpic:
>>> +# CHECK-NEXT: 20074: 3c 19 00 02 lui $25, 2
>>> +# CHECK-NEXT: 20078: 08 00 80 24 j 131216 <fpic>
>>> +# CHECK-NEXT: 2007c: 27 39 00 90 addiu $25, $25, 144
>>> +# CHECK-NEXT: 20080: 00 00 00 00 nop
>>> +# CHECK-NEXT: 20084: 00 00 00 00 nop
>>> +# CHECK-NEXT: 20088: 00 00 00 00 nop
>>> +# CHECK-NEXT: 2008c: 00 00 00 00 nop
>>> +
>>> +# CHECK: fpic:
>>> # CHECK-NEXT: 20090: 00 00 00 00 nop
>>> -# CHECK-NEXT: 20094: 3c 19 00 02 lui $25, 2
>>> -# CHECK-NEXT: 20098: 08 00 80 20 j 131200 <fpic>
>>> -# CHECK-NEXT: 2009c: 27 39 00 80 addiu $25, $25, 128
>>> +# CHECK-NEXT: 20094: 00 00 00 00 nop
>>> +# CHECK-NEXT: 20098: 00 00 00 00 nop
>>> +# CHECK-NEXT: 2009c: 00 00 00 00 nop
>>> +
>>> +# CHECK: fnpic:
>>> +# CHECK-NEXT: 200a0: 00 00 00 00 nop
>>>
>>> # Make sure the thunks are created properly no matter how
>>> # objects are laid out.
>>> #
>>> # RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe
>>> # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s
>>>
>>> -# REVERSE: foo1a:
>>> -# REVERSE-NEXT: 20000: 00 00 00 00 nop
>>> -#
>>> -# REVERSE: foo1b:
>>> -# REVERSE-NEXT: 20004: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20008: 3c 19 00 02 lui $25, 2
>>> -# REVERSE-NEXT: 2000c: 08 00 80 00 j 131072 <foo1a>
>>> -# REVERSE-NEXT: 20010: 27 39 00 00 addiu $25, $25, 0
>>> -# REVERSE-NEXT: 20014: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20018: 3c 19 00 02 lui $25, 2
>>> -# REVERSE-NEXT: 2001c: 08 00 80 01 j 131076 <foo1b>
>>> -# REVERSE-NEXT: 20020: 27 39 00 04 addiu $25, $25, 4
>>> +# REVERSE: Disassembly of section .text:
>>> +# REVERSE-NEXT: __LA25Thunk_foo1a:
>>> +# REVERSE-NEXT: 20000: 3c 19 00 02 lui $25, 2
>>> +# REVERSE-NEXT: 20004: 08 00 80 08 j 131104 <foo1a>
>>> +# REVERSE-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32
>>> +# REVERSE-NEXT: 2000c: 00 00 00 00 nop
>>> +# REVERSE: __LA25Thunk_foo1b:
>>> +# REVERSE-NEXT: 20010: 3c 19 00 02 lui $25, 2
>>> +# REVERSE-NEXT: 20014: 08 00 80 09 j 131108 <foo1b>
>>> +# REVERSE-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36
>>> +# REVERSE-NEXT: 2001c: 00 00 00 00 nop
>>> +# REVERSE: foo1a:
>>> +# REVERSE-NEXT: 20020: 00 00 00 00 nop
>>> +# REVERSE: foo1b:
>>> # REVERSE-NEXT: 20024: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20028: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 2002c: 00 00 00 00 nop
>>> -#
>>> -# REVERSE: foo2:
>>> -# REVERSE-NEXT: 20030: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20034: 3c 19 00 02 lui $25, 2
>>> -# REVERSE-NEXT: 20038: 08 00 80 0c j 131120 <foo2>
>>> -# REVERSE-NEXT: 2003c: 27 39 00 30 addiu $25, $25, 48
>>> +# REVERSE: __LA25Thunk_foo2:
>>> +# REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2
>>> +# REVERSE-NEXT: 2002c: 08 00 80 10 j 131136 <foo2>
>>> +# REVERSE-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64
>>> +# REVERSE-NEXT: 20034: 00 00 00 00 nop
>>> +# REVERSE-NEXT: 20038: 00 00 00 00 nop
>>> +# REVERSE-NEXT: 2003c: 00 00 00 00 nop
>>> +# REVERSE: foo2:
>>> # REVERSE-NEXT: 20040: 00 00 00 00 nop
>>> # REVERSE-NEXT: 20044: 00 00 00 00 nop
>>> # REVERSE-NEXT: 20048: 00 00 00 00 nop
>>> # REVERSE-NEXT: 2004c: 00 00 00 00 nop
>>> -#
>>> -# REVERSE: __start:
>>> -# REVERSE-NEXT: 20050: 0c 00 80 02 jal 131080 <foo1b+0x4>
>>> +# REVERSE: __start:
>>> +# REVERSE-NEXT: 20050: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a>
>>> # REVERSE-NEXT: 20054: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20058: 0c 00 80 0d jal 131124 <foo2+0x4>
>>> +# REVERSE-NEXT: 20058: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2>
>>> # REVERSE-NEXT: 2005c: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20060: 0c 00 80 06 jal 131096 <foo1b+0x14>
>>> +# REVERSE-NEXT: 20060: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b>
>>> # REVERSE-NEXT: 20064: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20068: 0c 00 80 0d jal 131124 <foo2+0x4>
>>> +# REVERSE-NEXT: 20068: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2>
>>> # REVERSE-NEXT: 2006c: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20070: 0c 00 80 25 jal 131220 <fnpic+0x4>
>>> +# REVERSE-NEXT: 20070: 0c 00 80 20 jal 131200 <__LA25Thunk_fpic>
>>> # REVERSE-NEXT: 20074: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20078: 0c 00 80 24 jal 131216 <fnpic>
>>> +# REVERSE-NEXT: 20078: 0c 00 80 28 jal 131232 <fnpic>
>>> # REVERSE-NEXT: 2007c: 00 00 00 00 nop
>>> -#
>>> -# REVERSE: fpic:
>>> -# REVERSE-NEXT: 20080: 00 00 00 00 nop
>>> -#
>>> -# REVERSE: fnpic:
>>> +# REVERSE: __LA25Thunk_fpic:
>>> +# REVERSE-NEXT: 20080: 3c 19 00 02 lui $25, 2
>>> +# REVERSE-NEXT: 20084: 08 00 80 24 j 131216 <fpic>
>>> +# REVERSE-NEXT: 20088: 27 39 00 90 addiu $25, $25, 144
>>> +# REVERSE-NEXT: 2008c: 00 00 00 00 nop
>>> +# REVERSE: fpic:
>>> # REVERSE-NEXT: 20090: 00 00 00 00 nop
>>> -# REVERSE-NEXT: 20094: 3c 19 00 02 lui $25, 2
>>> -# REVERSE-NEXT: 20098: 08 00 80 20 j 131200 <fpic>
>>> -# REVERSE-NEXT: 2009c: 27 39 00 80 addiu $25, $25, 128
>>> +# REVERSE-NEXT: 20094: 00 00 00 00 nop
>>> +# REVERSE-NEXT: 20098: 00 00 00 00 nop
>>> +# REVERSE-NEXT: 2009c: 00 00 00 00 nop
>>> +# REVERSE: fnpic:
>>> +# REVERSE-NEXT: 200a0: 00 00 00 00 nop
>>>
>>> .text
>>> .globl __start
>>> Index: test/ELF/arm-thumb-interwork-thunk.s
>>> ===================================================================
>>> --- test/ELF/arm-thumb-interwork-thunk.s
>>> +++ test/ELF/arm-thumb-interwork-thunk.s
>>> @@ -78,62 +78,65 @@
>>> beq arm_callee2
>>> bne arm_callee3
>>> bx lr
>>> -// CHECK-ABS-ARM: Disassembly of section .arm_caller:
>>> -// CHECK-ABS-ARM-NEXT: arm_caller:
>>> -// CHECK-ABS-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1>
>>> -// CHECK-ABS-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1>
>>> -// CHECK-ABS-ARM-NEXT: 1308: 06 00 00 ea b #24 <arm_caller+0x28>
>>> -// CHECK-ABS-ARM-NEXT: 130c: 05 00 00 ea b #20 <arm_caller+0x28>
>>> -// CHECK-ABS-ARM-NEXT: 1310: 07 00 00 ea b #28 <arm_caller+0x34>
>>> -// CHECK-ABS-ARM-NEXT: 1314: 09 00 00 ea b #36 <arm_caller+0x40>
>>> -// CHECK-ABS-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1>
>>> -// CHECK-ABS-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2>
>>> -// CHECK-ABS-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3>
>>> -// CHECK-ABS-ARM-NEXT: 1324: 1e ff 2f e1 bx lr
>>> +// CHECK-ARM-ABS-ARM: Disassembly of section .arm_caller:
>>> +// CHECK-ARM-ABS-ARM-NEXT: arm_caller:
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1308: 06 00 00 ea b #24 <__ARMToThumbv7ABSLongThunk_thumb_callee1>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 130c: 05 00 00 ea b #20 <__ARMToThumbv7ABSLongThunk_thumb_callee1>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1310: 07 00 00 ea b #28 <__ARMToThumbv7ABSLongThunk_thumb_callee2>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1314: 09 00 00 ea b #36 <__ARMToThumbv7ABSLongThunk_thumb_callee3>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3>
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1324: 1e ff 2f e1 bx lr
>>> +// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee1:
>>> // 0x1001 = thumb_callee1
>>> -// CHECK-ABS-ARM-NEXT: 1328: 01 c0 01 e3 movw r12, #4097
>>> -// CHECK-ABS-ARM-NEXT: 132c: 00 c0 40 e3 movt r12, #0
>>> -// CHECK-ABS-ARM-NEXT: 1330: 1c ff 2f e1 bx r12
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1328: 01 c0 01 e3 movw r12, #4097
>>> +// CHECK-ARM-ABS-ARM-NEXT: 132c: 00 c0 40 e3 movt r12, #0
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1330: 1c ff 2f e1 bx r12
>>> // 0x1501 = thumb_callee2
>>> -// CHECK-ABS-ARM-NEXT: 1334: 01 c5 01 e3 movw r12, #5377
>>> -// CHECK-ABS-ARM-NEXT: 1338: 00 c0 40 e3 movt r12, #0
>>> -// CHECK-ABS-ARM-NEXT: 133c: 1c ff 2f e1 bx r12
>>> +// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee2:
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1334: 01 c5 01 e3 movw r12, #5377
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1338: 00 c0 40 e3 movt r12, #0
>>> +// CHECK-ARM-ABS-ARM-NEXT: 133c: 1c ff 2f e1 bx r12
>>> // 0x1503 = thumb_callee3
>>> -// CHECK-ABS-ARM-NEXT: 1340: 03 c5 01 e3 movw r12, #5379
>>> -// CHECK-ABS-ARM-NEXT: 1344: 00 c0 40 e3 movt r12, #0
>>> -// CHECK-ABS-ARM-NEXT: 1348: 1c ff 2f e1 bx r12
>>> +// CHECK-ARM-ABS-ARM: __ARMToThumbv7ABSLongThunk_thumb_callee3:
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1340: 03 c5 01 e3 movw r12, #5379
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1344: 00 c0 40 e3 movt r12, #0
>>> +// CHECK-ARM-ABS-ARM-NEXT: 1348: 1c ff 2f e1 bx r12
>>>
>>> // CHECK-PI-ARM: Disassembly of section .arm_caller:
>>> // CHECK-PI-ARM-NEXT: arm_caller:
>>> -// CHECK-PI-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1>
>>> -// CHECK-PI-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1>
>>> -// 0x1308 + 8 + 0x18 = 0x1328
>>> -// CHECK-PI-ARM-NEXT: 1308: 06 00 00 ea b #24 <arm_caller+0x28>
>>> -// 0x130c + 8 + 0x14 = 0x1328
>>> -// CHECK-PI-ARM-NEXT: 130c: 05 00 00 ea b #20 <arm_caller+0x28>
>>> -// 0x1310 + 8 + 0x20 = 0x1338
>>> -// CHECK-PI-ARM-NEXT: 1310: 08 00 00 ea b #32 <arm_caller+0x38>
>>> -// 0x1314 + 8 + 0x2c = 0x1348
>>> -// CHECK-PI-ARM-NEXT: 1314: 0b 00 00 ea b #44 <arm_caller+0x48>
>>> -// CHECK-PI-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1>
>>> -// CHECK-PI-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2>
>>> -// CHECK-PI-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3>
>>> -// CHECK-PI-ARM-NEXT: 1324: 1e ff 2f e1 bx lr
>>> +// CHECK-PI-ARM-NEXT: 1300: 3e ff ff fa blx #-776 <thumb_callee1>
>>> +// CHECK-PI-ARM-NEXT: 1304: 3d ff ff fa blx #-780 <thumb_callee1>
>>> +// CHECK-PI-ARM-NEXT: 1308: 06 00 00 ea b #24 <__ARMToThumbV7PILongThunk_thumb_callee1>
>>> +// CHECK-PI-ARM-NEXT: 130c: 05 00 00 ea b #20 <__ARMToThumbV7PILongThunk_thumb_callee1>
>>> +// CHECK-PI-ARM-NEXT: 1310: 08 00 00 ea b #32 <__ARMToThumbV7PILongThunk_thumb_callee2>
>>> +// CHECK-PI-ARM-NEXT: 1314: 0b 00 00 ea b #44 <__ARMToThumbV7PILongThunk_thumb_callee3>
>>> +// CHECK-PI-ARM-NEXT: 1318: 78 ff ff ea b #-544 <arm_callee1>
>>> +// CHECK-PI-ARM-NEXT: 131c: b7 00 00 0a beq #732 <arm_callee2>
>>> +// CHECK-PI-ARM-NEXT: 1320: b7 00 00 1a bne #732 <arm_callee3>
>>> +// CHECK-PI-ARM-NEXT: 1324: 1e ff 2f e1 bx lr
>>> +// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee1:
>>> // 0x1330 + 8 - 0x337 = 0x1001 = thumb_callee1
>>> -// CHECK-PI-ARM-NEXT: 1328: c9 cc 0f e3 movw r12, #64713
>>> -// CHECK-PI-ARM-NEXT: 132c: ff cf 4f e3 movt r12, #65535
>>> -// CHECK-PI-ARM-NEXT: 1330: 0f c0 8c e0 add r12, r12, pc
>>> -// CHECK-PI-ARM-NEXT: 1334: 1c ff 2f e1 bx r12
>>> +// CHECK-PI-ARM-NEXT: 1328: c9 cc 0f e3 movw r12, #64713
>>> +// CHECK-PI-ARM-NEXT: 132c: ff cf 4f e3 movt r12, #65535
>>> +// CHECK-PI-ARM-NEXT: 1330: 0f c0 8c e0 add r12, r12, pc
>>> +// CHECK-PI-ARM-NEXT: 1334: 1c ff 2f e1 bx r12
>>> +// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee2:
>>> +
>>> +// CHECK-PI-ARM-NEXT: 1338: b9 c1 00 e3 movw r12, #441
>>> +// CHECK-PI-ARM-NEXT: 133c: 00 c0 40 e3 movt r12, #0
>>> +// CHECK-PI-ARM-NEXT: 1340: 0f c0 8c e0 add r12, r12, pc
>>> +// CHECK-PI-ARM-NEXT: 1344: 1c ff 2f e1 bx r12
>>> +// CHECK-PI-ARM: __ARMToThumbV7PILongThunk_thumb_callee3:
>>> // 0x1340 + 8 + 0x1b9 = 0x1501
>>> -// CHECK-PI-ARM-NEXT: 1338: b9 c1 00 e3 movw r12, #441
>>> -// CHECK-PI-ARM-NEXT: 133c: 00 c0 40 e3 movt r12, #0
>>> -// CHECK-PI-ARM-NEXT: 1340: 0f c0 8c e0 add r12, r12, pc
>>> -// CHECK-PI-ARM-NEXT: 1344: 1c ff 2f e1 bx r12
>>> +// CHECK-PI-ARM-NEXT: 1348: ab c1 00 e3 movw r12, #427
>>> +// CHECK-PI-ARM-NEXT: 134c: 00 c0 40 e3 movt r12, #0
>>> +// CHECK-PI-ARM-NEXT: 1350: 0f c0 8c e0 add r12, r12, pc
>>> +// CHECK-PI-ARM-NEXT: 1354: 1c ff 2f e1 bx r12
>>> // 1350 + 8 + 0x1ab = 0x1503
>>> -// CHECK-PI-ARM-NEXT: 1348: ab c1 00 e3 movw r12, #427
>>> -// CHECK-PI-ARM-NEXT: 134c: 00 c0 40 e3 movt r12, #0
>>> -// CHECK-PI-ARM-NEXT: 1350: 0f c0 8c e0 add r12, r12, pc
>>> -// CHECK-PI-ARM-NEXT: 1354: 1c ff 2f e1 bx r12
>>>
>>> // All PLT entries are ARM, no need for interworking thunks
>>> // CHECK-PI-ARM-PLT: Disassembly of section .arm_caller:
>>> @@ -182,60 +185,58 @@
>>> bne.w arm_callee3
>>> // CHECK-ABS-THUMB: Disassembly of section .thumb_caller:
>>> // CHECK-ABS-THUMB-NEXT: thumb_caller:
>>> -// 0x1400 + 4 - 0x304 = 0x1100 = arm_callee1
>>> -// CHECK-ABS-THUMB-NEXT: 1400: ff f7 7e ee blx #-772
>>> -// 0x1404 + 4 - 0x308 = 0x1100 = arm_callee1
>>> -// CHECK-ABS-THUMB-NEXT: 1404: ff f7 7c ee blx #-776
>>> -// 0x1408 + 4 + 0x14 = 0x520
>>> -// CHECK-ABS-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20
>>> -// 0x140c + 4 + 0x1a = 0x52a
>>> -// CHECK-ABS-THUMB-NEXT: 140c: 00 f0 0d b8 b.w #26
>>> -// 0x1410 + 4 + 0x20 = 0x534
>>> -// CHECK-ABS-THUMB-NEXT: 1410: 00 f0 10 b8 b.w #32
>>> -// 0x1414 + 4 + 8 = 0x520
>>> -// CHECK-ABS-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8
>>> -// 0x1418 + 4 + 0xe = 0x52a
>>> -// CHECK-ABS-THUMB-NEXT: 1418: 00 f0 07 80 beq.w #14
>>> -// 0x141c + 4 + 0x14 = 0x534
>>> -// CHECK-ABS-THUMB-NEXT: 141c: 40 f0 0a 80 bne.w #20
>>> +// CHECK-ABS-THUMB-NEXT: 1400: ff f7 7e ee blx #-772
>>> +// CHECK-ABS-THUMB-NEXT: 1404: ff f7 7c ee blx #-776
>>> +// CHECK-ABS-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20 <__ThumbToARMv7ABSLongThunk_arm_callee1+0x4>
>>> +// CHECK-ABS-THUMB-NEXT: 140c: 00 f0 0d b8 b.w #26 <__ThumbToARMv7ABSLongThunk_arm_callee2+0x4>
>>> +// CHECK-ABS-THUMB-NEXT: 1410: 00 f0 10 b8 b.w #32 <__ThumbToARMv7ABSLongThunk_arm_callee3+0x4>
>>> +// CHECK-ABS-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 <__ThumbToARMv7ABSLongThunk_arm_callee1+0x4>
>>> +// CHECK-ABS-THUMB-NEXT: 1418: 00 f0 07 80 beq.w #14 <__ThumbToARMv7ABSLongThunk_arm_callee2+0x4>
>>> +// CHECK-ABS-THUMB-NEXT: 141c: 40 f0 0a 80 bne.w #20 <__ThumbToARMv7ABSLongThunk_arm_callee3+0x4>
>>> +// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee1:
>>> // 0x1100 = arm_callee1
>>> -// CHECK-ABS-THUMB-NEXT: 1420: 41 f2 00 1c movw r12, #4352
>>> -// CHECK-ABS-THUMB-NEXT: 1424: c0 f2 00 0c movt r12, #0
>>> -// CHECK-ABS-THUMB-NEXT: 1428: 60 47 bx r12
>>> +// CHECK-ABS-THUMB-NEXT: 1420: 41 f2 00 1c movw r12, #4352
>>> +// CHECK-ABS-THUMB-NEXT: 1424: c0 f2 00 0c movt r12, #0
>>> +// CHECK-ABS-THUMB-NEXT: 1428: 60 47 bx r12
>>> +// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee2:
>>> // 0x1600 = arm_callee2
>>> -// CHECK-ABS-THUMB-NEXT: 142a: 41 f2 00 6c movw r12, #5632
>>> -// CHECK-ABS-THUMB-NEXT: 142e: c0 f2 00 0c movt r12, #0
>>> -// CHECK-ABS-THUMB-NEXT: 1432: 60 47 bx r12
>>> +// CHECK-ABS-THUMB-NEXT: 142a: 41 f2 00 6c movw r12, #5632
>>> +// CHECK-ABS-THUMB-NEXT: 142e: c0 f2 00 0c movt r12, #0
>>> +// CHECK-ABS-THUMB-NEXT: 1432: 60 47 bx r12
>>> // 0x1604 = arm_callee3
>>> -// CHECK-ABS-THUMB-NEXT: 1434: 41 f2 04 6c movw r12, #5636
>>> -// CHECK-ABS-THUMB-NEXT: 1438: c0 f2 00 0c movt r12, #0
>>> -// CHECK-ABS-THUMB-NEXT: 143c: 60 47 bx r12
>>> +// CHECK-ABS-THUMB: __ThumbToARMv7ABSLongThunk_arm_callee3:
>>> +// CHECK-ABS-THUMB-NEXT: 1434: 41 f2 04 6c movw r12, #5636
>>> +// CHECK-ABS-THUMB-NEXT: 1438: c0 f2 00 0c movt r12, #0
>>> +// CHECK-ABS-THUMB-NEXT: 143c: 60 47 bx r12
>>>
>>> // CHECK-PI-THUMB: Disassembly of section .thumb_caller:
>>> // CHECK-PI-THUMB-NEXT: thumb_caller:
>>> -// CHECK-PI-THUMB-NEXT: 1400: ff f7 7e ee blx #-772
>>> -// CHECK-PI-THUMB-NEXT: 1404: ff f7 7c ee blx #-776
>>> -// CHECK-PI-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20
>>> -// CHECK-PI-THUMB-NEXT: 140c: 00 f0 0e b8 b.w #28
>>> -// CHECK-PI-THUMB-NEXT: 1410: 00 f0 12 b8 b.w #36
>>> -// CHECK-PI-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8
>>> -// CHECK-PI-THUMB-NEXT: 1418: 00 f0 08 80 beq.w #16
>>> -// CHECK-PI-THUMB-NEXT: 141c: 40 f0 0c 80 bne.w #24
>>> +// CHECK-PI-THUMB-NEXT: 1400: ff f7 7e ee blx #-772
>>> +// CHECK-PI-THUMB-NEXT: 1404: ff f7 7c ee blx #-776
>>> +// CHECK-PI-THUMB-NEXT: 1408: 00 f0 0a b8 b.w #20 <__ThumbToARMV7PILongThunk_arm_callee1+0x4>
>>> +// CHECK-PI-THUMB-NEXT: 140c: 00 f0 0e b8 b.w #28 <__ThumbToARMV7PILongThunk_arm_callee2+0x4>
>>> +// CHECK-PI-THUMB-NEXT: 1410: 00 f0 12 b8 b.w #36 <__ThumbToARMV7PILongThunk_arm_callee3+0x4>
>>> +// CHECK-PI-THUMB-NEXT: 1414: 00 f0 04 80 beq.w #8 <__ThumbToARMV7PILongThunk_arm_callee1+0x4>
>>> +// CHECK-PI-THUMB-NEXT: 1418: 00 f0 08 80 beq.w #16 <__ThumbToARMV7PILongThunk_arm_callee2+0x4>
>>> +// CHECK-PI-THUMB-NEXT: 141c: 40 f0 0c 80 bne.w #24 <__ThumbToARMV7PILongThunk_arm_callee3+0x4>
>>> +// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee1:
>>> // 0x1428 + 4 - 0x32c = 0x1100 = arm_callee1
>>> -// CHECK-PI-THUMB-NEXT: 1420: 4f f6 d4 4c movw r12, #64724
>>> -// CHECK-PI-THUMB-NEXT: 1424: cf f6 ff 7c movt r12, #65535
>>> -// CHECK-PI-THUMB-NEXT: 1428: fc 44 add r12, pc
>>> -// CHECK-PI-THUMB-NEXT: 142a: 60 47 bx r12
>>> +// CHECK-PI-THUMB-NEXT: 1420: 4f f6 d4 4c movw r12, #64724
>>> +// CHECK-PI-THUMB-NEXT: 1424: cf f6 ff 7c movt r12, #65535
>>> +// CHECK-PI-THUMB-NEXT: 1428: fc 44 add r12, pc
>>> +// CHECK-PI-THUMB-NEXT: 142a: 60 47 bx r12
>>> +// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee2:
>>> // 0x1434 + 4 + 0x1c8 = 0x1600 = arm_callee2
>>> -// CHECK-PI-THUMB-NEXT: 142c: 40 f2 c8 1c movw r12, #456
>>> -// CHECK-PI-THUMB-NEXT: 1430: c0 f2 00 0c movt r12, #0
>>> -// CHECK-PI-THUMB-NEXT: 1434: fc 44 add r12, pc
>>> -// CHECK-PI-THUMB-NEXT: 1436: 60 47 bx r12
>>> +// CHECK-PI-THUMB-NEXT: 142c: 40 f2 c8 1c movw r12, #456
>>> +// CHECK-PI-THUMB-NEXT: 1430: c0 f2 00 0c movt r12, #0
>>> +// CHECK-PI-THUMB-NEXT: 1434: fc 44 add r12, pc
>>> +// CHECK-PI-THUMB-NEXT: 1436: 60 47 bx r12
>>> +// CHECK-PI-THUMB: __ThumbToARMV7PILongThunk_arm_callee3:
>>> // 0x1440 + 4 + 0x1c0 = 0x1604 = arm_callee3
>>> -// CHECK-PI-THUMB-NEXT: 1438: 40 f2 c0 1c movw r12, #448
>>> -// CHECK-PI-THUMB-NEXT: 143c: c0 f2 00 0c movt r12, #0
>>> -// CHECK-PI-THUMB-NEXT: 1440: fc 44 add r12, pc
>>> -// CHECK-PI-THUMB-NEXT: 1442: 60 47 bx r12
>>> +// CHECK-PI-THUMB-NEXT: 1438: 40 f2 c0 1c movw r12, #448
>>> +// CHECK-PI-THUMB-NEXT: 143c: c0 f2 00 0c movt r12, #0
>>> +// CHECK-PI-THUMB-NEXT: 1440: fc 44 add r12, pc
>>> +// CHECK-PI-THUMB-NEXT: 1442: 60 47 bx r12
>>>
>>> // CHECK-PI-THUMB-PLT: Disassembly of section .arm_caller:
>>> // CHECK-PI-THUMB-PLT-NEXT: thumb_caller:
>>> Index: test/ELF/arm-thumb-interwork-shared.s
>>> ===================================================================
>>> --- test/ELF/arm-thumb-interwork-shared.s
>>> +++ test/ELF/arm-thumb-interwork-shared.s
>>> @@ -16,12 +16,15 @@
>>>
>>> // CHECK: Disassembly of section .text:
>>> // CHECK-NEXT: sym1:
>>> -// CHECK: 1000: 00 f0 02 b8 b.w #4
>>> -// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12
>>> +// CHECK-NEXT: 1000: 00 f0 02 b8 b.w #4 <__ThumbToARMV7PILongThunk_elsewhere+0x4>
>>> +// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12 <__ThumbToARMV7PILongThunk_weakref+0x4>
>>> +// CHECK: __ThumbToARMV7PILongThunk_elsewhere:
>>> // CHECK-NEXT: 1008: 40 f2 20 0c movw r12, #32
>>> // CHECK-NEXT: 100c: c0 f2 00 0c movt r12, #0
>>> // CHECK-NEXT: 1010: fc 44 add r12, pc
>>> // CHECK-NEXT: 1012: 60 47 bx r12
>>> +
>>> +// CHECK: __ThumbToARMV7PILongThunk_weakref:
>>> // CHECK-NEXT: 1014: 40 f2 24 0c movw r12, #36
>>> // CHECK-NEXT: 1018: c0 f2 00 0c movt r12, #0
>>> // CHECK-NEXT: 101c: fc 44 add r12, pc
>>> Index: ELF/Writer.cpp
>>> ===================================================================
>>> --- ELF/Writer.cpp
>>> +++ ELF/Writer.cpp
>>> @@ -1031,6 +1031,12 @@
>>> if (In<ELFT>::Iplt && !In<ELFT>::Iplt->empty())
>>> In<ELFT>::Iplt->addSymbols();
>>>
>>> + // Some architectures use small displacements for jump instructions.
>>> + // It is linker's responsibility to create thunks containing long
>>> + // jump instructions if jump targets are too far. Create thunks.
>>> + if (Target->NeedsThunks)
>>> + createThunks<ELFT>(OutputSections);
>>> +
>>> // Now that we have defined all possible symbols including linker-
>>> // synthesized ones. Visit all symbols to give the finishing touches.
>>> for (Symbol *S : Symtab<ELFT>::X->getSymbols()) {
>>> @@ -1081,12 +1087,6 @@
>>> fixHeaders();
>>> }
>>>
>>> - // Some architectures use small displacements for jump instructions.
>>> - // It is linker's responsibility to create thunks containing long
>>> - // jump instructions if jump targets are too far. Create thunks.
>>> - if (Target->NeedsThunks)
>>> - createThunks<ELFT>(OutputSections);
>>> -
>>> // Fill other section headers. The dynamic table is finalized
>>> // at the end because some tags like RELSZ depend on result
>>> // of finalizing other sections.
>>> Index: ELF/Thunks.h
>>> ===================================================================
>>> --- ELF/Thunks.h
>>> +++ ELF/Thunks.h
>>> @@ -15,40 +15,44 @@
>>> namespace lld {
>>> namespace elf {
>>> class SymbolBody;
>>> -template <class ELFT> class InputSection;
>>> -
>>> +template <class ELFT> class ThunkSection;
>>> +class OutputSectionBase;
>>> // Class to describe an instance of a Thunk.
>>> // A Thunk is a code-sequence inserted by the linker in between a caller and
>>> // the callee. The relocation to the callee is redirected to the Thunk, which
>>> // after executing transfers control to the callee. Typical uses of Thunks
>>> // include transferring control from non-pi to pi and changing state on
>>> // targets like ARM.
>>> //
>>> -// Thunks can be created for DefinedRegular and Shared Symbols. The Thunk
>>> -// is stored in a field of the Symbol Destination.
>>> -// Thunks to be written to an InputSection are recorded by the InputSection.
>>> +// Thunks can be created for DefinedRegular, Shared and Undefined Symbols.
>>> +// Thunks are assigned to synthetic ThunkSections
>>> template <class ELFT> class Thunk {
>>> - typedef typename ELFT::uint uintX_t;
>>> -
>>> public:
>>> - Thunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner);
>>> + Thunk(const SymbolBody &Destination);
>>> virtual ~Thunk();
>>>
>>> virtual uint32_t size() const { return 0; }
>>> - virtual void writeTo(uint8_t *Buf) const {}
>>> - uintX_t getVA() const;
>>> + virtual void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const {}
>>> +
>>> + // All Thunks must define at least one symbol ThunkSym so that we can
>>> + // redirect relocations to it.
>>> + virtual void addSymbols(ThunkSection<ELFT> &IS) {}
>>> +
>>> + // Some Thunks must be placed immediately before their Target as they elide
>>> + // a branch and fall through to the first Symbol in the Target.
>>> + virtual InputSection<ELFT> *getTargetInputSection() const { return nullptr; }
>>>
>>> -protected:
>>> + // The alignment requirement for this Thunk, defaults to the size of the
>>> + // typical code section alignment.
>>> const SymbolBody &Destination;
>>> - const InputSection<ELFT> &Owner;
>>> + SymbolBody *ThunkSym;
>>> uint64_t Offset;
>>> + uint32_t alignment = 4;
>>> };
>>>
>>> -// For a Relocation to symbol S from InputSection Src, create a Thunk and
>>> -// update the fields of S and the InputSection that the Thunk body will be
>>> -// written to. At present there are implementations for ARM and Mips Thunks.
>>> -template <class ELFT>
>>> -void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &Src);
>>> +// For a Relocation to symbol S create a Thunk to be added to a synthetic
>>> +// ThunkSection. At present there are implementations for ARM and Mips Thunks.
>>> +template <class ELFT> Thunk<ELFT> *addThunk(uint32_t RelocType, SymbolBody &S);
>>>
>>> } // namespace elf
>>> } // namespace lld
>>> Index: ELF/Thunks.cpp
>>> ===================================================================
>>> --- ELF/Thunks.cpp
>>> +++ ELF/Thunks.cpp
>>> @@ -28,6 +28,7 @@
>>> #include "Memory.h"
>>> #include "OutputSections.h"
>>> #include "Symbols.h"
>>> +#include "SyntheticSections.h"
>>> #include "Target.h"
>>> #include "llvm/Support/Casting.h"
>>> #include "llvm/Support/ELF.h"
>>> @@ -52,53 +53,54 @@
>>> template <class ELFT>
>>> class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> {
>>> public:
>>> - ARMToThumbV7ABSLongThunk(const SymbolBody &Dest,
>>> - const InputSection<ELFT> &Owner)
>>> - : Thunk<ELFT>(Dest, Owner) {}
>>> + ARMToThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {}
>>>
>>> uint32_t size() const override { return 12; }
>>> - void writeTo(uint8_t *Buf) const override;
>>> + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
>>> + void addSymbols(ThunkSection<ELFT> &IS) override;
>>> };
>>>
>>> template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> {
>>> public:
>>> - ARMToThumbV7PILongThunk(const SymbolBody &Dest,
>>> - const InputSection<ELFT> &Owner)
>>> - : Thunk<ELFT>(Dest, Owner) {}
>>> + ARMToThumbV7PILongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {}
>>>
>>> uint32_t size() const override { return 16; }
>>> - void writeTo(uint8_t *Buf) const override;
>>> + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
>>> + void addSymbols(ThunkSection<ELFT> &IS) override;
>>> };
>>>
>>> template <class ELFT>
>>> class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> {
>>> public:
>>> - ThumbToARMV7ABSLongThunk(const SymbolBody &Dest,
>>> - const InputSection<ELFT> &Owner)
>>> - : Thunk<ELFT>(Dest, Owner) {}
>>> + ThumbToARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {
>>> + this->alignment = 2;
>>> + }
>>>
>>> uint32_t size() const override { return 10; }
>>> - void writeTo(uint8_t *Buf) const override;
>>> + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
>>> + void addSymbols(ThunkSection<ELFT> &IS) override;
>>> };
>>>
>>> template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> {
>>> public:
>>> - ThumbToARMV7PILongThunk(const SymbolBody &Dest,
>>> - const InputSection<ELFT> &Owner)
>>> - : Thunk<ELFT>(Dest, Owner) {}
>>> + ThumbToARMV7PILongThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {
>>> + this->alignment = 2;
>>> + }
>>>
>>> uint32_t size() const override { return 12; }
>>> - void writeTo(uint8_t *Buf) const override;
>>> + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
>>> + void addSymbols(ThunkSection<ELFT> &IS) override;
>>> };
>>>
>>> // MIPS LA25 thunk
>>> template <class ELFT> class MipsThunk final : public Thunk<ELFT> {
>>> public:
>>> - MipsThunk(const SymbolBody &Dest, const InputSection<ELFT> &Owner)
>>> - : Thunk<ELFT>(Dest, Owner) {}
>>> + MipsThunk(const SymbolBody &Dest) : Thunk<ELFT>(Dest) {}
>>>
>>> uint32_t size() const override { return 16; }
>>> - void writeTo(uint8_t *Buf) const override;
>>> + void writeTo(uint8_t *Buf, ThunkSection<ELFT> &IS) const override;
>>> + void addSymbols(ThunkSection<ELFT> &IS) override;
>>> + InputSection<ELFT> *getTargetInputSection() const override;
>>> };
>>>
>>> } // end anonymous namespace
>>> @@ -110,7 +112,8 @@
>>> }
>>>
>>> template <class ELFT>
>>> -void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
>>> +void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf,
>>> + ThunkSection<ELFT> &IS) const {
>>> const uint8_t Data[] = {
>>> 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
>>> 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
>>> @@ -123,7 +126,16 @@
>>> }
>>>
>>> template <class ELFT>
>>> -void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
>>> +void ARMToThumbV7ABSLongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
>>> + this->ThunkSym = addSyntheticLocal(
>>> + Saver.save("__ARMToThumbv7ABSLongThunk_" + this->Destination.getName()),
>>> + STT_FUNC, this->Offset, size(), &IS);
>>> + addSyntheticLocal("$a", STT_NOTYPE, this->Offset, 0, &IS);
>>> +}
>>> +
>>> +template <class ELFT>
>>> +void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf,
>>> + ThunkSection<ELFT> &IS) const {
>>> const uint8_t Data[] = {
>>> 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
>>> 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
>>> @@ -136,37 +148,64 @@
>>> }
>>>
>>> template <class ELFT>
>>> -void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
>>> +void ThumbToARMV7ABSLongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
>>> + this->ThunkSym = addSyntheticLocal(
>>> + Saver.save("__ThumbToARMv7ABSLongThunk_" + this->Destination.getName()),
>>> + STT_FUNC, this->Offset, size(), &IS);
>>> + addSyntheticLocal("$t", STT_NOTYPE, this->Offset, 0, &IS);
>>> +}
>>> +
>>> +template <class ELFT>
>>> +void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf,
>>> + ThunkSection<ELFT> &IS) const {
>>> const uint8_t Data[] = {
>>> 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8)
>>> 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8)
>>> 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
>>> 0x1c, 0xff, 0x2f, 0xe1, // bx r12
>>> };
>>> uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
>>> - uint64_t P = this->getVA();
>>> + uint64_t P = this->ThunkSym->template getVA<ELFT>();
>>> memcpy(Buf, Data, sizeof(Data));
>>> Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
>>> Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
>>> }
>>>
>>> template <class ELFT>
>>> -void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
>>> +void ARMToThumbV7PILongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
>>> + this->ThunkSym = addSyntheticLocal(
>>> + Saver.save("__ARMToThumbV7PILongThunk_" + this->Destination.getName()),
>>> + STT_FUNC, this->Offset, size(), &IS);
>>> + addSyntheticLocal("$a", STT_NOTYPE, this->Offset, 0, &IS);
>>> +}
>>> +
>>> +template <class ELFT>
>>> +void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf,
>>> + ThunkSection<ELFT> &IS) const {
>>> const uint8_t Data[] = {
>>> 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
>>> 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4)
>>> 0xfc, 0x44, // L1: add r12, pc
>>> 0x60, 0x47, // bx r12
>>> };
>>> uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
>>> - uint64_t P = this->getVA();
>>> + uint64_t P = this->ThunkSym->template getVA<ELFT>();
>>> memcpy(Buf, Data, sizeof(Data));
>>> Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
>>> Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
>>> }
>>>
>>> +template <class ELFT>
>>> +void ThumbToARMV7PILongThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
>>> + this->ThunkSym = addSyntheticLocal(
>>> + Saver.save("__ThumbToARMV7PILongThunk_" + this->Destination.getName()),
>>> + STT_FUNC, this->Offset, size(), &IS);
>>> + addSyntheticLocal("$t", STT_NOTYPE, this->Offset, 0, &IS);
>>> +}
>>> +
>>> // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
>>> -template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const {
>>> +template <class ELFT>
>>> +void MipsThunk<ELFT>::writeTo(uint8_t *Buf, ThunkSection<ELFT> &) const {
>>> const endianness E = ELFT::TargetEndianness;
>>>
>>> uint64_t S = this->Destination.template getVA<ELFT>();
>>> @@ -178,93 +217,62 @@
>>> Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
>>> }
>>>
>>> -template <class ELFT>
>>> -Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O)
>>> - : Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {}
>>> +template <class ELFT> void MipsThunk<ELFT>::addSymbols(ThunkSection<ELFT> &IS) {
>>> + this->ThunkSym = addSyntheticLocal(
>>> + Saver.save("__LA25Thunk_" + this->Destination.getName()), STT_FUNC,
>>> + this->Offset, size(), &IS);
>>> +}
>>>
>>> -template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const {
>>> - return Owner.OutSec->Addr + Owner.OutSecOff + Offset;
>>> +template <class ELFT>
>>> +InputSection<ELFT> *MipsThunk<ELFT>::getTargetInputSection() const {
>>> + auto *DR = dyn_cast<DefinedRegular<ELFT>>(&this->Destination);
>>> + return dyn_cast<InputSection<ELFT>>(DR->Section);
>>> }
>>>
>>> +template <class ELFT>
>>> +Thunk<ELFT>::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {}
>>> +
>>> template <class ELFT> Thunk<ELFT>::~Thunk() = default;
>>>
>>> // Creates a thunk for Thumb-ARM interworking.
>>> template <class ELFT>
>>> -static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
>>> - InputSection<ELFT> &IS) {
>>> +static Thunk<ELFT> *addThunkArm(uint32_t Reloc, SymbolBody &S) {
>>> // ARM relocations need ARM to Thumb interworking Thunks.
>>> // Thumb relocations need Thumb to ARM relocations.
>>> // Use position independent Thunks if we require position independent code.
>>> switch (Reloc) {
>>> case R_ARM_PC24:
>>> case R_ARM_PLT32:
>>> case R_ARM_JUMP24:
>>> if (Config->Pic)
>>> - return new (BAlloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
>>> - return new (BAlloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
>>> + return make<ARMToThumbV7PILongThunk<ELFT>>(S);
>>> + return make<ARMToThumbV7ABSLongThunk<ELFT>>(S);
>>> case R_ARM_THM_JUMP19:
>>> case R_ARM_THM_JUMP24:
>>> if (Config->Pic)
>>> - return new (BAlloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
>>> - return new (BAlloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
>>> + return make<ThumbToARMV7PILongThunk<ELFT>>(S);
>>> + return make<ThumbToARMV7ABSLongThunk<ELFT>>(S);
>>> }
>>> fatal("unrecognized relocation type");
>>> }
>>>
>>> -template <class ELFT>
>>> -static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) {
>>> - // Only one Thunk supported per symbol.
>>> - if (S.hasThunk<ELFT>())
>>> - return;
>>> -
>>> - // ARM Thunks are added to the same InputSection as the relocation. This
>>> - // isn't strictly necessary but it makes it more likely that a limited range
>>> - // branch can reach the Thunk, and it makes Thunks to the PLT section easier
>>> - Thunk<ELFT> *T = createThunkArm(Reloc, S, IS);
>>> - IS.addThunk(T);
>>> - if (auto *Sym = dyn_cast<DefinedRegular<ELFT>>(&S))
>>> - Sym->ThunkData = T;
>>> - else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S))
>>> - Sym->ThunkData = T;
>>> - else if (auto *Sym = dyn_cast<Undefined<ELFT>>(&S))
>>> - Sym->ThunkData = T;
>>> - else
>>> - fatal("symbol not DefinedRegular or Shared");
>>> -}
>>> -
>>> -template <class ELFT>
>>> -static void addThunkMips(uint32_t RelocType, SymbolBody &S,
>>> - InputSection<ELFT> &IS) {
>>> - // Only one Thunk supported per symbol.
>>> - if (S.hasThunk<ELFT>())
>>> - return;
>>> -
>>> - // Mips Thunks are added to the InputSection defining S.
>>> - auto *R = cast<DefinedRegular<ELFT>>(&S);
>>> - auto *Sec = cast<InputSection<ELFT>>(R->Section);
>>> - auto *T = new (BAlloc) MipsThunk<ELFT>(S, *Sec);
>>> - Sec->addThunk(T);
>>> - R->ThunkData = T;
>>> +template <class ELFT> static Thunk<ELFT> *addThunkMips(SymbolBody &S) {
>>> + return make<MipsThunk<ELFT>>(S);
>>> }
>>>
>>> -template <class ELFT>
>>> -void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) {
>>> +template <class ELFT> Thunk<ELFT> *addThunk(uint32_t RelocType, SymbolBody &S) {
>>> if (Config->EMachine == EM_ARM)
>>> - addThunkARM<ELFT>(RelocType, S, IS);
>>> + return addThunkArm<ELFT>(RelocType, S);
>>> else if (Config->EMachine == EM_MIPS)
>>> - addThunkMips<ELFT>(RelocType, S, IS);
>>> - else
>>> - llvm_unreachable("add Thunk only supported for ARM and Mips");
>>> + return addThunkMips<ELFT>(S);
>>> + llvm_unreachable("add Thunk only supported for ARM and Mips");
>>> + return nullptr;
>>> }
>>>
>>> -template void addThunk<ELF32LE>(uint32_t, SymbolBody &,
>>> - InputSection<ELF32LE> &);
>>> -template void addThunk<ELF32BE>(uint32_t, SymbolBody &,
>>> - InputSection<ELF32BE> &);
>>> -template void addThunk<ELF64LE>(uint32_t, SymbolBody &,
>>> - InputSection<ELF64LE> &);
>>> -template void addThunk<ELF64BE>(uint32_t, SymbolBody &,
>>> - InputSection<ELF64BE> &);
>>> +template Thunk<ELF32LE> *addThunk<ELF32LE>(uint32_t, SymbolBody &);
>>> +template Thunk<ELF32BE> *addThunk<ELF32BE>(uint32_t, SymbolBody &);
>>> +template Thunk<ELF64LE> *addThunk<ELF64LE>(uint32_t, SymbolBody &);
>>> +template Thunk<ELF64BE> *addThunk<ELF64BE>(uint32_t, SymbolBody &);
>>>
>>> template class Thunk<ELF32LE>;
>>> template class Thunk<ELF32BE>;
>>> Index: ELF/Target.h
>>> ===================================================================
>>> --- ELF/Target.h
>>> +++ ELF/Target.h
>>> @@ -41,24 +41,19 @@
>>> virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
>>> uint64_t PltEntryAddr, int32_t Index,
>>> unsigned RelOff) const {}
>>> - virtual void addPltHeaderSymbols(InputSectionData* IS) const {}
>>> - virtual void addPltSymbols(InputSectionData* IS, uint64_t Off) const {}
>>> + virtual void addPltHeaderSymbols(InputSectionData *IS) const {}
>>> + virtual void addPltSymbols(InputSectionData *IS, uint64_t Off) const {}
>>> // Returns true if a relocation only uses the low bits of a value such that
>>> // all those bits are in in the same page. For example, if the relocation
>>> // only uses the low 12 bits in a system with 4k pages. If this is true, the
>>> // bits will always have the same value at runtime and we don't have to emit
>>> // a dynamic relocation.
>>> virtual bool usesOnlyLowPageBits(uint32_t Type) const;
>>>
>>> // Decide whether a Thunk is needed for the relocation from File
>>> - // targeting S. Returns one of:
>>> - // Expr if there is no Thunk required
>>> - // R_THUNK_ABS if thunk is required and expression is absolute
>>> - // R_THUNK_PC if thunk is required and expression is pc rel
>>> - // R_THUNK_PLT_PC if thunk is required to PLT entry and expression is pc rel
>>> - virtual RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
>>> - const InputFile *File,
>>> - const SymbolBody &S) const;
>>> + // targeting S.
>>> + virtual bool needsThunk(RelExpr Expr, uint32_t RelocType,
>>> + const InputFile *File, const SymbolBody &S) const;
>>> virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
>>> virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
>>> virtual ~TargetInfo();
>>> Index: ELF/Target.cpp
>>> ===================================================================
>>> --- ELF/Target.cpp
>>> +++ ELF/Target.cpp
>>> @@ -228,8 +228,8 @@
>>> int32_t Index, unsigned RelOff) const override;
>>> void addPltSymbols(InputSectionData *IS, uint64_t Off) const override;
>>> void addPltHeaderSymbols(InputSectionData *ISD) const override;
>>> - RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile *File,
>>> - const SymbolBody &S) const override;
>>> + bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
>>> + const SymbolBody &S) const override;
>>> void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
>>> };
>>>
>>> @@ -246,8 +246,8 @@
>>> void writePltHeader(uint8_t *Buf) const override;
>>> void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
>>> int32_t Index, unsigned RelOff) const override;
>>> - RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile *File,
>>> - const SymbolBody &S) const override;
>>> + bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
>>> + const SymbolBody &S) const override;
>>> void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
>>> bool usesOnlyLowPageBits(uint32_t Type) const override;
>>> };
>>> @@ -298,10 +298,9 @@
>>>
>>> bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
>>>
>>> -RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
>>> - const InputFile *File,
>>> - const SymbolBody &S) const {
>>> - return Expr;
>>> +bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
>>> + const InputFile *File, const SymbolBody &S) const {
>>> + return false;
>>> }
>>>
>>> bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
>>> @@ -1771,15 +1770,15 @@
>>> addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS);
>>> }
>>>
>>> -RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
>>> - const InputFile *File,
>>> - const SymbolBody &S) const {
>>> +bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
>>> + const InputFile *File,
>>> + const SymbolBody &S) const {
>>> // If S is an undefined weak symbol in an executable we don't need a Thunk.
>>> // In a DSO calls to undefined symbols, including weak ones get PLT entries
>>> // which may need a thunk.
>>> if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
>>> !Config->Shared)
>>> - return Expr;
>>> + return false;
>>> // A state change from ARM to Thumb and vice versa must go through an
>>> // interworking thunk if the relocation type is not R_ARM_CALL or
>>> // R_ARM_THM_CALL.
>>> @@ -1790,19 +1789,17 @@
>>> // Source is ARM, all PLT entries are ARM so no interworking required.
>>> // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
>>> if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1))
>>> - return R_THUNK_PC;
>>> + return true;
>>> break;
>>> case R_ARM_THM_JUMP19:
>>> case R_ARM_THM_JUMP24:
>>> // Source is Thumb, all PLT entries are ARM so interworking is required.
>>> // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
>>> - if (Expr == R_PLT_PC)
>>> - return R_THUNK_PLT_PC;
>>> - if ((S.getVA<ELF32LE>() & 1) == 0)
>>> - return R_THUNK_PC;
>>> + if (Expr == R_PLT_PC || ((S.getVA<ELF32LE>() & 1) == 0))
>>> + return true;
>>> break;
>>> }
>>> - return Expr;
>>> + return false;
>>> }
>>>
>>> void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
>>> @@ -2215,26 +2212,26 @@
>>> }
>>>
>>> template <class ELFT>
>>> -RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
>>> - const InputFile *File,
>>> - const SymbolBody &S) const {
>>> +bool MipsTargetInfo<ELFT>::needsThunk(RelExpr Expr, uint32_t Type,
>>> + const InputFile *File,
>>> + const SymbolBody &S) const {
>>> // Any MIPS PIC code function is invoked with its address in register $t9.
>>> // So if we have a branch instruction from non-PIC code to the PIC one
>>> // we cannot make the jump directly and need to create a small stubs
>>> // to save the target function address.
>>> // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
>>> if (Type != R_MIPS_26)
>>> - return Expr;
>>> + return false;
>>> auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
>>> if (!F)
>>> - return Expr;
>>> + return false;
>>> // If current file has PIC code, LA25 stub is not required.
>>> if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
>>> - return Expr;
>>> + return false;
>>> auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
>>> // LA25 is required if target file has PIC code
>>> // or target symbol is a PIC symbol.
>>> - return D && D->isMipsPIC() ? R_THUNK_ABS : Expr;
>>> + return D && D->isMipsPIC();
>>> }
>>>
>>> template <class ELFT>
>>> Index: ELF/SyntheticSections.h
>>> ===================================================================
>>> --- ELF/SyntheticSections.h
>>> +++ ELF/SyntheticSections.h
>>> @@ -699,6 +699,27 @@
>>> void writeTo(uint8_t *Buf) override;
>>> };
>>>
>>> +// A container for one or more linker generated thunks. Instances of these
>>> +// thunks including ARM interworking and Mips LA25 PI to non-PI thunks.
>>> +template <class ELFT> class ThunkSection : public SyntheticSection<ELFT> {
>>> +public:
>>> + // ThunkSection in OS, with desired OutSecOff of Off
>>> + ThunkSection(OutputSectionBase *OS, uint64_t Off);
>>> +
>>> + // Add a newly created Thunk to this container:
>>> + // Thunk is given offset from start of this InputSection
>>> + // Thunk defines a symbol in this InputSection that can be used as target
>>> + // of a relocation
>>> + void addThunk(Thunk<ELFT> *T);
>>> + size_t getSize() const override { return Size; }
>>> + void writeTo(uint8_t *Buf) override;
>>> + InputSection<ELFT> *getTargetInputSection() const;
>>> +
>>> +private:
>>> + std::vector<const Thunk<ELFT> *> Thunks;
>>> + size_t Size = 0;
>>> +};
>>> +
>>> template <class ELFT> InputSection<ELFT> *createCommonSection();
>>> template <class ELFT> InputSection<ELFT> *createInterpSection();
>>> template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
>>> Index: ELF/SyntheticSections.cpp
>>> ===================================================================
>>> --- ELF/SyntheticSections.cpp
>>> +++ ELF/SyntheticSections.cpp
>>> @@ -1904,6 +1904,33 @@
>>> write32le(Buf + 4, 0x1);
>>> }
>>>
>>> +template <class ELFT>
>>> +ThunkSection<ELFT>::ThunkSection(OutputSectionBase *OS, uint64_t Off)
>>> + : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
>>> + sizeof(typename ELFT::uint), ".text.thunk") {
>>> + this->OutSec = OS;
>>> + this->OutSecOff = Off;
>>> +}
>>> +
>>> +template <class ELFT> void ThunkSection<ELFT>::addThunk(Thunk<ELFT> *T) {
>>> + uint64_t Off = alignTo(Size, T->alignment);
>>> + T->Offset = Off;
>>> + Thunks.push_back(T);
>>> + T->addSymbols(*this);
>>> + Size = Off + T->size();
>>> +}
>>> +
>>> +template <class ELFT> void ThunkSection<ELFT>::writeTo(uint8_t *Buf) {
>>> + for (const Thunk<ELFT> *T : Thunks)
>>> + T->writeTo(Buf + T->Offset, *this);
>>> +}
>>> +
>>> +template <class ELFT>
>>> +InputSection<ELFT> *ThunkSection<ELFT>::getTargetInputSection() const {
>>> + const Thunk<ELFT> *T = Thunks.front();
>>> + return T->getTargetInputSection();
>>> +}
>>> +
>>> template InputSection<ELF32LE> *elf::createCommonSection();
>>> template InputSection<ELF32BE> *elf::createCommonSection();
>>> template InputSection<ELF64LE> *elf::createCommonSection();
>>> @@ -2046,3 +2073,8 @@
>>> template class elf::ARMExidxSentinelSection<ELF32BE>;
>>> template class elf::ARMExidxSentinelSection<ELF64LE>;
>>> template class elf::ARMExidxSentinelSection<ELF64BE>;
>>> +
>>> +template class elf::ThunkSection<ELF32LE>;
>>> +template class elf::ThunkSection<ELF32BE>;
>>> +template class elf::ThunkSection<ELF64LE>;
>>> +template class elf::ThunkSection<ELF64BE>;
>>> Index: ELF/Symbols.h
>>> ===================================================================
>>> --- ELF/Symbols.h
>>> +++ ELF/Symbols.h
>>> @@ -76,7 +76,6 @@
>>>
>>> bool isInGot() const { return GotIndex != -1U; }
>>> bool isInPlt() const { return PltIndex != -1U; }
>>> - template <class ELFT> bool hasThunk() const;
>>>
>>> template <class ELFT>
>>> typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
>>> @@ -86,7 +85,6 @@
>>> template <class ELFT> typename ELFT::uint getGotPltOffset() const;
>>> template <class ELFT> typename ELFT::uint getGotPltVA() const;
>>> template <class ELFT> typename ELFT::uint getPltVA() const;
>>> - template <class ELFT> typename ELFT::uint getThunkVA() const;
>>> template <class ELFT> typename ELFT::uint getSize() const;
>>>
>>> // The file from which this symbol was created.
>>> @@ -210,10 +208,6 @@
>>> // If this is null, the symbol is an absolute symbol.
>>> InputSectionBase<ELFT> *&Section;
>>>
>>> - // If non-null the symbol has a Thunk that may be used as an alternative
>>> - // destination for callers of this Symbol.
>>> - Thunk<ELFT> *ThunkData = nullptr;
>>> -
>>> private:
>>> static InputSectionBase<ELFT> *NullInputSection;
>>> };
>>> @@ -242,21 +236,15 @@
>>> const OutputSectionBase *Section;
>>> };
>>>
>>> -template <class ELFT> class Undefined : public SymbolBody {
>>> +class Undefined : public SymbolBody {
>>> public:
>>> Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
>>> InputFile *F);
>>>
>>> static bool classof(const SymbolBody *S) {
>>> return S->kind() == UndefinedKind;
>>> }
>>>
>>> - // If non-null the symbol has a Thunk that may be used as an alternative
>>> - // destination for callers of this Symbol. When linking a DSO undefined
>>> - // symbols are implicitly imported, the symbol lookup will be performed by
>>> - // the dynamic loader. A call to an undefined symbol will be given a PLT
>>> - // entry and on ARM this may need a Thunk if the caller is in Thumb state.
>>> - Thunk<ELFT> *ThunkData = nullptr;
>>> InputFile *file() { return this->File; }
>>> };
>>>
>>> @@ -291,9 +279,6 @@
>>> // CopyOffset is significant only when needsCopy() is true.
>>> uintX_t CopyOffset = 0;
>>>
>>> - // If non-null the symbol has a Thunk that may be used as an alternative
>>> - // destination for callers of this Symbol.
>>> - Thunk<ELFT> *ThunkData = nullptr;
>>> bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
>>>
>>> OutputSection<ELFT> *getBssSectionForCopy() const;
>>> @@ -431,8 +416,7 @@
>>> // ELFT, and we verify this with the static_asserts in replaceBody.
>>> llvm::AlignedCharArrayUnion<
>>> DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic,
>>> - Undefined<llvm::object::ELF64LE>, SharedSymbol<llvm::object::ELF64LE>,
>>> - LazyArchive, LazyObject>
>>> + Undefined, SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject>
>>> Body;
>>>
>>> SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
>>> Index: ELF/Symbols.cpp
>>> ===================================================================
>>> --- ELF/Symbols.cpp
>>> +++ ELF/Symbols.cpp
>>> @@ -132,14 +132,6 @@
>>> return true;
>>> }
>>>
>>> -template <class ELFT> bool SymbolBody::hasThunk() const {
>>> - if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
>>> - return DR->ThunkData != nullptr;
>>> - if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
>>> - return S->ThunkData != nullptr;
>>> - return false;
>>> -}
>>> -
>>> template <class ELFT>
>>> typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
>>> typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
>>> @@ -171,16 +163,6 @@
>>> PltIndex * Target->PltEntrySize;
>>> }
>>>
>>> -template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
>>> - if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
>>> - return DR->ThunkData->getVA();
>>> - if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
>>> - return S->ThunkData->getVA();
>>> - if (const auto *S = dyn_cast<Undefined<ELFT>>(this))
>>> - return S->ThunkData->getVA();
>>> - fatal("getThunkVA() not supported for Symbol class\n");
>>> -}
>>> -
>>> template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
>>> if (const auto *C = dyn_cast<DefinedCommon>(this))
>>> return C->Size;
>>> @@ -241,9 +223,8 @@
>>> (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
>>> }
>>>
>>> -template <typename ELFT>
>>> -Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
>>> - uint8_t Type, InputFile *File)
>>> +Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
>>> + uint8_t Type, InputFile *File)
>>> : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
>>> this->File = File;
>>> }
>>> @@ -338,11 +319,6 @@
>>> return B.getName();
>>> }
>>>
>>> -template bool SymbolBody::hasThunk<ELF32LE>() const;
>>> -template bool SymbolBody::hasThunk<ELF32BE>() const;
>>> -template bool SymbolBody::hasThunk<ELF64LE>() const;
>>> -template bool SymbolBody::hasThunk<ELF64BE>() const;
>>> -
>>> template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
>>> template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
>>> template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
>>> @@ -363,11 +339,6 @@
>>> template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
>>> template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const;
>>>
>>> -template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
>>> -template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
>>> -template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
>>> -template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const;
>>> -
>>> template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const;
>>> template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
>>> template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
>>> @@ -383,11 +354,6 @@
>>> template uint64_t SymbolBody::template getSize<ELF64LE>() const;
>>> template uint64_t SymbolBody::template getSize<ELF64BE>() const;
>>>
>>> -template class elf::Undefined<ELF32LE>;
>>> -template class elf::Undefined<ELF32BE>;
>>> -template class elf::Undefined<ELF64LE>;
>>> -template class elf::Undefined<ELF64BE>;
>>> -
>>> template class elf::SharedSymbol<ELF32LE>;
>>> template class elf::SharedSymbol<ELF32BE>;
>>> template class elf::SharedSymbol<ELF64LE>;
>>> Index: ELF/SymbolTable.cpp
>>> ===================================================================
>>> --- ELF/SymbolTable.cpp
>>> +++ ELF/SymbolTable.cpp
>>> @@ -115,7 +115,7 @@
>>> // Compile bitcode files and replace bitcode symbols.
>>> LTO.reset(new BitcodeCompiler);
>>> for (BitcodeFile *F : BitcodeFiles)
>>> - LTO->add<ELFT>(*F);
>>> + LTO->add(*F);
>>>
>>> for (InputFile *File : LTO->compile()) {
>>> ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
>>> @@ -256,7 +256,7 @@
>>> insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File);
>>> if (WasInserted) {
>>> S->Binding = Binding;
>>> - replaceBody<Undefined<ELFT>>(S, Name, IsLocal, StOther, Type, File);
>>> + replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
>>> return S;
>>> }
>>> if (Binding != STB_WEAK) {
>>> @@ -428,7 +428,7 @@
>>> // Make sure we preempt DSO symbols with default visibility.
>>> if (Sym.getVisibility() == STV_DEFAULT)
>>> S->ExportDynamic = true;
>>> - if (WasInserted || isa<Undefined<ELFT>>(S->body())) {
>>> + if (WasInserted || isa<Undefined>(S->body())) {
>>> replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
>>> if (!S->isWeak())
>>> F->IsUsed = true;
>>> Index: ELF/Relocations.h
>>> ===================================================================
>>> --- ELF/Relocations.h
>>> +++ ELF/Relocations.h
>>> @@ -61,9 +61,6 @@
>>> R_RELAX_TLS_IE_TO_LE,
>>> R_RELAX_TLS_LD_TO_LE,
>>> R_SIZE,
>>> - R_THUNK_ABS,
>>> - R_THUNK_PC,
>>> - R_THUNK_PLT_PC,
>>> R_TLS,
>>> R_TLSDESC,
>>> R_TLSDESC_PAGE,
>>> Index: ELF/Relocations.cpp
>>> ===================================================================
>>> --- ELF/Relocations.cpp
>>> +++ ELF/Relocations.cpp
>>> @@ -43,6 +43,7 @@
>>>
>>> #include "Relocations.h"
>>> #include "Config.h"
>>> +#include "Memory.h"
>>> #include "OutputSections.h"
>>> #include "Strings.h"
>>> #include "SymbolTable.h"
>>> @@ -52,6 +53,7 @@
>>>
>>> #include "llvm/Support/Endian.h"
>>> #include "llvm/Support/raw_ostream.h"
>>> +#include <algorithm>
>>>
>>> using namespace llvm;
>>> using namespace llvm::ELF;
>>> @@ -300,16 +302,14 @@
>>> }
>>>
>>> static bool needsPlt(RelExpr Expr) {
>>> - return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC,
>>> - R_THUNK_PLT_PC>(Expr);
>>> + return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
>>> }
>>>
>>> // True if this expression is of the form Sym - X, where X is a position in the
>>> // file (PC, or GOT for example).
>>> static bool isRelExpr(RelExpr Expr) {
>>> return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
>>> - R_PAGE_PC, R_RELAX_GOT_PC, R_THUNK_PC, R_THUNK_PLT_PC>(
>>> - Expr);
>>> + R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
>>> }
>>>
>>> template <class ELFT>
>>> @@ -321,8 +321,7 @@
>>> if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
>>> R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_TLSGD,
>>> R_GOT_PAGE_PC, R_GOT_PC, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
>>> - R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
>>> - R_THUNK_PC, R_THUNK_PLT_PC>(E))
>>> + R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
>>> return true;
>>>
>>> // These never do, except if the entire file is position dependent or if
>>> @@ -467,7 +466,6 @@
>>> if (Expr == R_GOT_PC && !isAbsoluteValue<ELFT>(Body))
>>> Expr = Target->adjustRelaxExpr(Type, Data, Expr);
>>> }
>>> - Expr = Target->getThunkExpr(Expr, Type, &File, Body);
>>>
>>> if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
>>> return Expr;
>>> @@ -685,7 +683,6 @@
>>> continue;
>>>
>>> if (needsPlt(Expr) ||
>>> - isRelExprOneOf<R_THUNK_ABS, R_THUNK_PC, R_THUNK_PLT_PC>(Expr) ||
>>> refersToGotEntry(Expr) || !isPreemptible(Body, Type)) {
>>> // If the relocation points to something in the file, we can process it.
>>> bool Constant =
>>> @@ -805,33 +802,138 @@
>>> scanRelocs(S, S.rels());
>>> }
>>>
>>> +// Insert the Thunks for OutputSection OS into their designated place
>>> +// in the Sections vector, and recalculate the InputSection output section
>>> +// offsets.
>>> +// This may invalidate any output section offsets stored outside of InputSection
>>> +template <class ELFT>
>>> +static void mergeThunks(OutputSection<ELFT> *OS,
>>> + std::vector<ThunkSection<ELFT> *> &Thunks) {
>>> + // Order Thunks in ascending OutSecOff
>>> + auto ThunkCmp = [](const ThunkSection<ELFT> *A, const ThunkSection<ELFT> *B) {
>>> + return A->OutSecOff < B->OutSecOff;
>>> + };
>>> + std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp);
>>> +
>>> + // Merge sorted vectors of Thunks and InputSections by OutSecOff
>>> + std::vector<InputSection<ELFT> *> Tmp;
>>> + Tmp.reserve(OS->Sections.size() + Thunks.size());
>>> + auto MergeCmp = [](const InputSection<ELFT> *A, const InputSection<ELFT> *B) {
>>> + // MSVC debug implementation checks std library preconditions so we can't
>>> + // assume A will be Thunk, also both Thunks and InputSections must be
>>> + // ordered by MergeCmp prior to merge.
>>> + if (A->OutSecOff < B->OutSecOff)
>>> + return true;
>>> + if (A->OutSecOff == B->OutSecOff) {
>>> + // Check if Thunk is immediately before any specific Target InputSection
>>> + // for example Mips LA25 Thunks.
>>> + auto *TA = dyn_cast<ThunkSection<ELFT>>(A);
>>> + auto *TB = dyn_cast<ThunkSection<ELFT>>(B);
>>> + if (TA && !TB && TA->getTargetInputSection() == B)
>>> + return true;
>>> + }
>>> + return false;
>>> + };
>>> + std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(),
>>> + Thunks.end(), std::back_inserter(Tmp), MergeCmp);
>>> + OS->Sections = std::move(Tmp);
>>> + OS->Size = 0;
>>> + OS->assignOffsets();
>>> +}
>>> +
>>> +// Process all relocations from the InputSections that have been assigned
>>> +// to OutputSections and redirect through Thunks if needed.
>>> +//
>>> +// createThunks must be called after scanRelocs has created the Relocations for
>>> +// each InputSection. It must be called before the static symbol table is
>>> +// finalized. If any Thunks are added to an OutputSection the output section
>>> +// offsets of the InputSections will change.
>>> +//
>>> +// FIXME: All Thunks are assumed to be in range of the relocation. Range
>>> +// extension Thunks are not yet supported.
>>> template <class ELFT>
>>> void createThunks(ArrayRef<OutputSectionBase *> OutputSections) {
>>> + // Track Symbols that already have a Thunk
>>> + DenseMap<SymbolBody *, Thunk<ELFT> *> ThunkedSymbols;
>>> + // Track InputSections that have a ThunkSection placed in front
>>> + DenseMap<InputSection<ELFT> *, ThunkSection<ELFT> *> ThunkedSections;
>>> + // Track the ThunksSections that need to be inserted into an OutputSection
>>> + std::map<OutputSection<ELFT> *, std::vector<ThunkSection<ELFT> *>>
>>> + ThunkSections;
>>> +
>>> + // Find or create a Thunk for Body for relocation Type
>>> + auto GetThunk = [&](SymbolBody &Body, uint32_t Type) {
>>> + auto res = ThunkedSymbols.insert({&Body, nullptr});
>>> + if (res.second == true)
>>> + res.first->second = addThunk<ELFT>(Type, Body);
>>> + return std::make_pair(res.first->second, res.second);
>>> + };
>>> +
>>> + // Find or create a ThunkSection to be placed immediately before IS
>>> + auto GetISThunkSec = [&](InputSection<ELFT> *IS, OutputSection<ELFT> *OS) {
>>> + ThunkSection<ELFT> *TS = ThunkedSections.lookup(IS);
>>> + if (TS)
>>> + return TS;
>>> + auto *TOS = cast<OutputSection<ELFT>>(IS->OutSec);
>>> + TS = make<ThunkSection<ELFT>>(TOS, IS->OutSecOff);
>>> + ThunkSections[OS].push_back(TS);
>>> + ThunkedSections[IS] = TS;
>>> + return TS;
>>> + };
>>> + // Find or create a ThunkSection to be placed as last executable section in
>>> + // OS.
>>> + auto GetOSThunkSec = [&](ThunkSection<ELFT> *&TS, OutputSection<ELFT> *OS) {
>>> + if (TS == nullptr) {
>>> + uint32_t Off = 0;
>>> + for (auto *IS : OS->Sections) {
>>> + Off = IS->OutSecOff + IS->getSize();
>>> + if ((IS->Flags & SHF_EXECINSTR) == 0)
>>> + break;
>>> + }
>>> + TS = make<ThunkSection<ELFT>>(OS, Off);
>>> + ThunkSections[OS].push_back(TS);
>>> + }
>>> + return TS;
>>> + };
>>> + // Create all the Thunks and insert them into synthetic ThunkSections. The
>>> + // ThunkSections are later inserted back into the OutputSection.
>>> +
>>> + // We separate the creation of ThunkSections from the insertion of the
>>> + // ThunkSections back into the OutputSection as ThunkSections are not always
>>> + // inserted into the same OutputSection as the caller.
>>> for (OutputSectionBase *Base : OutputSections) {
>>> auto *OS = dyn_cast<OutputSection<ELFT>>(Base);
>>> if (OS == nullptr)
>>> continue;
>>> +
>>> + ThunkSection<ELFT> *OSTS = nullptr;
>>> for (InputSection<ELFT> *IS : OS->Sections) {
>>> - for (const Relocation &Rel : IS->Relocations) {
>>> - if (Rel.Sym == nullptr)
>>> - continue;
>>> - RelExpr Expr = Rel.Expr;
>>> - // Some targets might require creation of thunks for relocations.
>>> - // Now we support only MIPS which requires LA25 thunk to call PIC
>>> - // code from non-PIC one, and ARM which requires interworking.
>>> - if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC ||
>>> - Expr == R_THUNK_PLT_PC)
>>> - addThunk<ELFT>(Rel.Type, *Rel.Sym, *IS);
>>> + for (Relocation &Rel : IS->Relocations) {
>>> + SymbolBody &Body = *Rel.Sym;
>>> + if (Target->needsThunk(Rel.Expr, Rel.Type, IS->getFile(), Body)) {
>>> + Thunk<ELFT> *T;
>>> + bool IsNew;
>>> + std::tie(T, IsNew) = GetThunk(Body, Rel.Type);
>>> + if (IsNew) {
>>> + // Find or create a ThunkSection for the new Thunk
>>> + ThunkSection<ELFT> *TS;
>>> + if (auto *TIS = T->getTargetInputSection())
>>> + TS = GetISThunkSec(TIS, OS);
>>> + else
>>> + TS = GetOSThunkSec(OSTS, OS);
>>> + TS->addThunk(T);
>>> + }
>>> + // Redirect relocation to Thunk, we never go via the PLT to a Thunk
>>> + Rel.Sym = T->ThunkSym;
>>> + Rel.Expr = fromPlt(Rel.Expr);
>>> + }
>>> }
>>> }
>>> }
>>> - // Added thunks may affect the output section offset
>>> - for (OutputSectionBase *Base : OutputSections)
>>> - if (auto *OS = dyn_cast<OutputSection<ELFT>>(Base))
>>> - if (OS->Type == SHT_PROGBITS) {
>>> - OS->Size = 0;
>>> - OS->assignOffsets();
>>> - }
>>> +
>>> + // Merge all created synthetic ThunkSections back into OutputSection
>>> + for (auto &KV : ThunkSections)
>>> + mergeThunks<ELFT>(KV.first, KV.second);
>>> }
>>>
>>> template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &);
>>> Index: ELF/LTO.h
>>> ===================================================================
>>> --- ELF/LTO.h
>>> +++ ELF/LTO.h
>>> @@ -43,7 +43,7 @@
>>> BitcodeCompiler();
>>> ~BitcodeCompiler();
>>>
>>> - template <class ELFT> void add(BitcodeFile &F);
>>> + void add(BitcodeFile &F);
>>> std::vector<InputFile *> compile();
>>>
>>> private:
>>> Index: ELF/LTO.cpp
>>> ===================================================================
>>> --- ELF/LTO.cpp
>>> +++ ELF/LTO.cpp
>>> @@ -96,12 +96,12 @@
>>>
>>> BitcodeCompiler::~BitcodeCompiler() = default;
>>>
>>> -template <class ELFT> static void undefine(Symbol *S) {
>>> - replaceBody<Undefined<ELFT>>(S, S->body()->getName(), /*IsLocal=*/false,
>>> - STV_DEFAULT, S->body()->Type, nullptr);
>>> +static void undefine(Symbol *S) {
>>> + replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
>>> + STV_DEFAULT, S->body()->Type, nullptr);
>>> }
>>>
>>> -template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
>>> +void BitcodeCompiler::add(BitcodeFile &F) {
>>> lto::InputFile &Obj = *F.Obj;
>>> unsigned SymNum = 0;
>>> std::vector<Symbol *> Syms = F.getSymbols();
>>> @@ -126,7 +126,7 @@
>>> R.VisibleToRegularObj =
>>> Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
>>> if (R.Prevailing)
>>> - undefine<ELFT>(Sym);
>>> + undefine(Sym);
>>> }
>>> checkError(LTOObj->add(std::move(F.Obj), Resols));
>>> }
>>> @@ -157,8 +157,3 @@
>>> }
>>> return Ret;
>>> }
>>> -
>>> -template void BitcodeCompiler::template add<ELF32LE>(BitcodeFile &);
>>> -template void BitcodeCompiler::template add<ELF32BE>(BitcodeFile &);
>>> -template void BitcodeCompiler::template add<ELF64LE>(BitcodeFile &);
>>> -template void BitcodeCompiler::template add<ELF64BE>(BitcodeFile &);
>>> Index: ELF/InputSection.h
>>> ===================================================================
>>> --- ELF/InputSection.h
>>> +++ ELF/InputSection.h
>>> @@ -280,17 +280,6 @@
>>>
>>> InputSectionBase<ELFT> *getRelocatedSection();
>>>
>>> - // Register thunk related to the symbol. When the section is written
>>> - // to a mmap'ed file, target is requested to write an actual thunk code.
>>> - // Now thunks is supported for MIPS and ARM target only.
>>> - void addThunk(const Thunk<ELFT> *T);
>>> -
>>> - // The offset of synthetic thunk code from beginning of this section.
>>> - uint64_t getThunkOff() const;
>>> -
>>> - // Size of chunk with thunks code.
>>> - uint64_t getThunksSize() const;
>>> -
>>> template <class RelTy>
>>> void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
>>>
>>> @@ -303,8 +292,6 @@
>>> private:
>>> template <class RelTy>
>>> void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
>>> -
>>> - llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
>>> };
>>>
>>> template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded;
>>> Index: ELF/InputSection.cpp
>>> ===================================================================
>>> --- ELF/InputSection.cpp
>>> +++ ELF/InputSection.cpp
>>> @@ -99,10 +99,6 @@
>>> if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this))
>>> return S->getSize();
>>>
>>> - if (auto *D = dyn_cast<InputSection<ELFT>>(this))
>>> - if (D->getThunksSize() > 0)
>>> - return D->getThunkOff() + D->getThunksSize();
>>> -
>>> return Data.size();
>>> }
>>>
>>> @@ -214,21 +210,6 @@
>>> return Sections[this->Info];
>>> }
>>>
>>> -template <class ELFT> void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
>>> - Thunks.push_back(T);
>>> -}
>>> -
>>> -template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
>>> - return this->Data.size();
>>> -}
>>> -
>>> -template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
>>> - uint64_t Total = 0;
>>> - for (const Thunk<ELFT> *T : Thunks)
>>> - Total += T->size();
>>> - return Total;
>>> -}
>>> -
>>> // This is used for -r. We can't use memcpy to copy relocations because we need
>>> // to update symbol table offset and section index for each relocation. So we
>>> // copy relocations one by one.
>>> @@ -302,11 +283,6 @@
>>> return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
>>> case R_TLSLD_PC:
>>> return In<ELFT>::Got->getTlsIndexVA() + A - P;
>>> - case R_THUNK_ABS:
>>> - return Body.getThunkVA<ELFT>() + A;
>>> - case R_THUNK_PC:
>>> - case R_THUNK_PLT_PC:
>>> - return Body.getThunkVA<ELFT>() + A - P;
>>> case R_PPC_TOC:
>>> return getPPC64TocBase() + A;
>>> case R_TLSGD:
>>> @@ -551,19 +527,6 @@
>>> // Iterate over all relocation sections that apply to this section.
>>> uint8_t *BufEnd = Buf + OutSecOff + Data.size();
>>> this->relocate(Buf, BufEnd);
>>> -
>>> - // The section might have a data/code generated by the linker and need
>>> - // to be written after the section. Usually these are thunks - small piece
>>> - // of code used to jump between "incompatible" functions like PIC and non-PIC
>>> - // or if the jump target too far and its address does not fit to the short
>>> - // jump istruction.
>>> - if (!Thunks.empty()) {
>>> - Buf += OutSecOff + getThunkOff();
>>> - for (const Thunk<ELFT> *T : Thunks) {
>>> - T->writeTo(Buf);
>>> - Buf += T->size();
>>> - }
>>> - }
>>> }
>>>
>>> template <class ELFT>
>>> Index: ELF/InputFiles.cpp
>>> ===================================================================
>>> --- ELF/InputFiles.cpp
>>> +++ ELF/InputFiles.cpp
>>> @@ -488,7 +488,7 @@
>>> StringRefZ Name = this->StringTable.data() + Sym->st_name;
>>> if (Sym->st_shndx == SHN_UNDEF)
>>> return new (BAlloc)
>>> - Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this);
>>> + Undefined(Name, /*IsLocal=*/true, StOther, Type, this);
>>>
>>> return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
>>> Type, Value, Size, Sec, this);
>>
>> ...
>>
>> [Message clipped]
More information about the llvm-commits
mailing list