[PATCH] D29327: [LLD][ELF] Use Synthetic Sections for Thunks (try 2)

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 1 02:42:14 PST 2017


Thanks for the comments, everyone. I've incorporated Rui's suggestions
and committed r293757.

There is a marginal benefit from putting the Thunks before any RO
data, in that the amount of RO could be large and the calls could be
out of range. It will need improving for range extension thunks.

Peter

On 31 January 2017 at 20:58, Rafael Avila de Espindola
<rafael.espindola at gmail.com> wrote:
> 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