[lld] r352929 - [COFF] Create range extension thunks for ARM64

Hans Wennborg via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 5 03:19:27 PST 2019


Merged to 8.0 in r353158.

On Fri, Feb 1, 2019 at 11:07 PM Martin Storsjo via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
>
> Author: mstorsjo
> Date: Fri Feb  1 14:08:09 2019
> New Revision: 352929
>
> URL: http://llvm.org/viewvc/llvm-project?rev=352929&view=rev
> Log:
> [COFF] Create range extension thunks for ARM64
>
> On ARM64, this is normally necessary only after a module exceeds
> 128 MB in size (while the limit for thumb is 16 MB). For conditional
> branches, the range limit is only 1 MB though (the same as for thumb),
> and for the tbz instruction, the range is only 32 KB, which allows for
> a test much smaller than the full 128 MB.
>
> This fixes PR40467.
>
> Differential Revision: https://reviews.llvm.org/D57575
>
> Added:
>     lld/trunk/test/COFF/arm64-thunks.s
> Removed:
>     lld/trunk/test/COFF/arm64-branch-range.test
> Modified:
>     lld/trunk/COFF/Chunks.cpp
>     lld/trunk/COFF/Chunks.h
>     lld/trunk/COFF/Writer.cpp
>
> Modified: lld/trunk/COFF/Chunks.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.cpp?rev=352929&r1=352928&r2=352929&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Chunks.cpp (original)
> +++ lld/trunk/COFF/Chunks.cpp Fri Feb  1 14:08:09 2019
> @@ -670,18 +670,38 @@ const uint8_t ArmThunk[] = {
>      0xe7, 0x44,             // L1: add  pc, ip
>  };
>
> -size_t RangeExtensionThunk::getSize() const {
> +size_t RangeExtensionThunkARM::getSize() const {
>    assert(Config->Machine == ARMNT);
>    return sizeof(ArmThunk);
>  }
>
> -void RangeExtensionThunk::writeTo(uint8_t *Buf) const {
> +void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const {
>    assert(Config->Machine == ARMNT);
>    uint64_t Offset = Target->getRVA() - RVA - 12;
>    memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk));
>    applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset));
>  }
>
> +// A position independent ARM64 adrp+add thunk, with a maximum range of
> +// +/- 4 GB, which is enough for any PE-COFF.
> +const uint8_t Arm64Thunk[] = {
> +    0x10, 0x00, 0x00, 0x90, // adrp x16, Dest
> +    0x10, 0x02, 0x00, 0x91, // add  x16, x16, :lo12:Dest
> +    0x00, 0x02, 0x1f, 0xd6, // br   x16
> +};
> +
> +size_t RangeExtensionThunkARM64::getSize() const {
> +  assert(Config->Machine == ARM64);
> +  return sizeof(Arm64Thunk);
> +}
> +
> +void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const {
> +  assert(Config->Machine == ARM64);
> +  memcpy(Buf + OutputSectionOff, Arm64Thunk, sizeof(Arm64Thunk));
> +  applyArm64Addr(Buf + OutputSectionOff + 0, Target->getRVA(), RVA, 12);
> +  applyArm64Imm(Buf + OutputSectionOff + 4, Target->getRVA() & 0xfff, 0);
> +}
> +
>  void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
>    Res->emplace_back(getRVA());
>  }
>
> Modified: lld/trunk/COFF/Chunks.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Chunks.h?rev=352929&r1=352928&r2=352929&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Chunks.h (original)
> +++ lld/trunk/COFF/Chunks.h Fri Feb  1 14:08:09 2019
> @@ -357,9 +357,18 @@ private:
>    Defined *ImpSymbol;
>  };
>
> -class RangeExtensionThunk : public Chunk {
> +class RangeExtensionThunkARM : public Chunk {
>  public:
> -  explicit RangeExtensionThunk(Defined *T) : Target(T) {}
> +  explicit RangeExtensionThunkARM(Defined *T) : Target(T) {}
> +  size_t getSize() const override;
> +  void writeTo(uint8_t *Buf) const override;
> +
> +  Defined *Target;
> +};
> +
> +class RangeExtensionThunkARM64 : public Chunk {
> +public:
> +  explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {}
>    size_t getSize() const override;
>    void writeTo(uint8_t *Buf) const override;
>
>
> Modified: lld/trunk/COFF/Writer.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Writer.cpp?rev=352929&r1=352928&r2=352929&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Writer.cpp (original)
> +++ lld/trunk/COFF/Writer.cpp Fri Feb  1 14:08:09 2019
> @@ -335,16 +335,31 @@ void OutputSection::writeHeaderTo(uint8_
>  // Check whether the target address S is in range from a relocation
>  // of type RelType at address P.
>  static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) {
> -  assert(Config->Machine == ARMNT);
> -  int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
> -  switch (RelType) {
> -  case IMAGE_REL_ARM_BRANCH20T:
> -    return isInt<21>(Diff);
> -  case IMAGE_REL_ARM_BRANCH24T:
> -  case IMAGE_REL_ARM_BLX23T:
> -    return isInt<25>(Diff);
> -  default:
> -    return true;
> +  if (Config->Machine == ARMNT) {
> +    int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
> +    switch (RelType) {
> +    case IMAGE_REL_ARM_BRANCH20T:
> +      return isInt<21>(Diff);
> +    case IMAGE_REL_ARM_BRANCH24T:
> +    case IMAGE_REL_ARM_BLX23T:
> +      return isInt<25>(Diff);
> +    default:
> +      return true;
> +    }
> +  } else if (Config->Machine == ARM64) {
> +    int64_t Diff = AbsoluteDifference(S, P) + Margin;
> +    switch (RelType) {
> +    case IMAGE_REL_ARM64_BRANCH26:
> +      return isInt<28>(Diff);
> +    case IMAGE_REL_ARM64_BRANCH19:
> +      return isInt<21>(Diff);
> +    case IMAGE_REL_ARM64_BRANCH14:
> +      return isInt<16>(Diff);
> +    default:
> +      return true;
> +    }
> +  } else {
> +    llvm_unreachable("Unexpected architecture");
>    }
>  }
>
> @@ -356,7 +371,17 @@ getThunk(DenseMap<uint64_t, Defined *> &
>    Defined *&LastThunk = LastThunks[Target->getRVA()];
>    if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin))
>      return {LastThunk, false};
> -  RangeExtensionThunk *C = make<RangeExtensionThunk>(Target);
> +  Chunk *C;
> +  switch (Config->Machine) {
> +  case ARMNT:
> +    C = make<RangeExtensionThunkARM>(Target);
> +    break;
> +  case ARM64:
> +    C = make<RangeExtensionThunkARM64>(Target);
> +    break;
> +  default:
> +    llvm_unreachable("Unexpected architecture");
> +  }
>    Defined *D = make<DefinedSynthetic>("", C);
>    LastThunk = D;
>    return {D, true};
> @@ -458,7 +483,7 @@ static bool verifyRanges(const std::vect
>  // Assign addresses and add thunks if necessary.
>  void Writer::finalizeAddresses() {
>    assignAddresses();
> -  if (Config->Machine != ARMNT)
> +  if (Config->Machine != ARMNT && Config->Machine != ARM64)
>      return;
>
>    size_t OrigNumChunks = 0;
>
> Removed: lld/trunk/test/COFF/arm64-branch-range.test
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/arm64-branch-range.test?rev=352928&view=auto
> ==============================================================================
> --- lld/trunk/test/COFF/arm64-branch-range.test (original)
> +++ lld/trunk/test/COFF/arm64-branch-range.test (removed)
> @@ -1,16 +0,0 @@
> -// REQUIRES: aarch64
> -
> -// RUN: echo -e '.globl _start\n _start:\n bl too_far26\n' > %t.main26.s
> -// RUN: echo -e '.globl _start\n _start:\n b.ne too_far19\n' > %t.main19.s
> -// RUN: echo -e '.globl _start\n _start:\n tbz x0, #0, too_far14\n' > %t.main14.s
> -
> -// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main26.s -o %t.main26.obj
> -// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main19.s -o %t.main19.obj
> -// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main14.s -o %t.main14.obj
> -// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/far-arm64-abs.s -o %t.far.obj
> -
> -// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main26.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
> -// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main19.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
> -// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main14.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
> -
> -// CHECK: relocation out of range
>
> Added: lld/trunk/test/COFF/arm64-thunks.s
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/arm64-thunks.s?rev=352929&view=auto
> ==============================================================================
> --- lld/trunk/test/COFF/arm64-thunks.s (added)
> +++ lld/trunk/test/COFF/arm64-thunks.s Fri Feb  1 14:08:09 2019
> @@ -0,0 +1,27 @@
> +// REQUIRES: aarch64
> +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %s -o %t.obj
> +// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe -verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
> +// RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s
> +
> +// VERBOSE: Added 1 thunks with margin {{.*}} in 1 passes
> +
> +    .globl main
> +    .globl func1
> +    .text
> +main:
> +    tbz w0, #0, func1
> +    ret
> +    .section .text$a, "xr"
> +    .space 0x8000
> +    .section .text$b, "xr"
> +func1:
> +    ret
> +
> +// DISASM: 0000000140001000 .text:
> +// DISASM: 140001000:      40 00 00 36     tbz     w0, #0, #8 <.text+0x8>
> +// DISASM: 140001004:      c0 03 5f d6     ret
> +// DISASM: 140001008:      50 00 00 90     adrp    x16, #32768
> +// DISASM: 14000100c:      10 52 00 91     add     x16, x16, #20
> +// DISASM: 140001010:      00 02 1f d6     br      x16
> +
> +// DISASM: 140009014:      c0 03 5f d6     ret
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list