[lld] 6b035b6 - [LLD][ELF][ARM] Implement Thumb pc-relative relocations for adr and ldr

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 28 03:29:53 PST 2020


Author: Peter Smith
Date: 2020-02-28T11:29:29Z
New Revision: 6b035b607f5f5e4db6f1ca51340d7a87b5807a0c

URL: https://github.com/llvm/llvm-project/commit/6b035b607f5f5e4db6f1ca51340d7a87b5807a0c
DIFF: https://github.com/llvm/llvm-project/commit/6b035b607f5f5e4db6f1ca51340d7a87b5807a0c.diff

LOG: [LLD][ELF][ARM] Implement Thumb pc-relative relocations for adr and ldr

MC will now output the R_ARM_THM_PC8, R_ARM_THM_PC12 and
R_ARM_THM_PREL_11_0 relocations. These are short-ranged relocations that
are used to implement the adr rd, literal and ldr rd, literal pseudo
instructions.

The instructions use a new RelExpr called R_ARM_PCA in order to calculate
the required S + A - Pa expression, where Pa is AlignDown(P, 4) as the
instructions add their immediate to AlignDown(PC, 4). We also do not want
these relocations to generate or resolve against a PLT entry as the range
of these relocations is so short they would never reach.

The R_ARM_THM_PC8 has a special encoding convention for the relocation
addend, the immediate field is unsigned, yet the addend must be -4 to
account for the Thumb PC bias. The ABI (not the architecture) uses the
convention that the 8-byte immediate of 0xff represents -4.

Differential Revision: https://reviews.llvm.org/D75042

Added: 
    lld/test/ELF/arm-thumb-adr-err.s
    lld/test/ELF/arm-thumb-adr.s
    lld/test/ELF/arm-thumb-ldrlit-err.s
    lld/test/ELF/arm-thumb-ldrlit.s
    lld/test/ELF/arm-thumb-pc8-weak.s
    lld/test/ELF/arm-thumb2-adr-err.s
    lld/test/ELF/arm-thumb2-adr.s
    lld/test/ELF/arm-thumb2-ldrlit-err.s
    lld/test/ELF/arm-thumb2-ldrlit.s

Modified: 
    lld/ELF/Arch/ARM.cpp
    lld/ELF/InputSection.cpp
    lld/ELF/Relocations.h
    lld/test/ELF/arm-thumb-undefined-weak.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
index 50e7c3ff946f..0cb9d3a01af8 100644
--- a/lld/ELF/Arch/ARM.cpp
+++ b/lld/ELF/Arch/ARM.cpp
@@ -132,6 +132,10 @@ RelExpr ARM::getRelExpr(RelType type, const Symbol &s,
   case R_ARM_THM_MOVW_PREL_NC:
   case R_ARM_THM_MOVT_PREL:
     return R_PC;
+  case R_ARM_THM_ALU_PREL_11_0:
+  case R_ARM_THM_PC8:
+  case R_ARM_THM_PC12:
+    return R_ARM_PCA;
   case R_ARM_MOVW_BREL_NC:
   case R_ARM_MOVW_BREL:
   case R_ARM_MOVT_BREL:
@@ -570,6 +574,50 @@ void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
                   ((val << 4) & 0x7000) |    // imm3
                   (val & 0x00ff));           // imm8
     break;
+  case R_ARM_THM_ALU_PREL_11_0: {
+    // ADR encoding T2 (sub), T3 (add) i:imm3:imm8
+    int64_t imm = val;
+    uint16_t sub = 0;
+    if (imm < 0) {
+      imm = -imm;
+      sub = 0x00a0;
+    }
+    checkUInt(loc, imm, 12, rel);
+    write16le(loc, (read16le(loc) & 0xfb0f) | sub | (imm & 0x800) >> 1);
+    write16le(loc + 2,
+              (read16le(loc + 2) & 0x8f00) | (imm & 0x700) << 4 | (imm & 0xff));
+    break;
+  }
+  case R_ARM_THM_PC8:
+    // ADR and LDR literal encoding T1 positive offset only imm8:00
+    // R_ARM_THM_PC8 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a
+    // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
+    // bottom bit to recover S + A - Pa.
+    if (rel.sym->isFunc())
+      val &= ~0x1;
+    checkUInt(loc, val, 10, rel);
+    checkAlignment(loc, val, 4, rel);
+    write16le(loc, (read16le(loc) & 0xff00) | (val & 0x3fc) >> 2);
+    break;
+  case R_ARM_THM_PC12: {
+    // LDR (literal) encoding T2, add = (U == '1') imm12
+    // imm12 is unsigned
+    // R_ARM_THM_PC12 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a
+    // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
+    // bottom bit to recover S + A - Pa.
+    if (rel.sym->isFunc())
+      val &= ~0x1;
+    int64_t imm12 = val;
+    uint16_t u = 0x0080;
+    if (imm12 < 0) {
+      imm12 = -imm12;
+      u = 0;
+    }
+    checkUInt(loc, imm12, 12, rel);
+    write16le(loc, read16le(loc) | u);
+    write16le(loc + 2, (read16le(loc + 2) & 0xf000) | imm12);
+    break;
+  }
   default:
     error(getErrorLocation(loc) + "unrecognized relocation " +
           toString(rel.type));
@@ -660,6 +708,30 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {
                             ((lo & 0x7000) >> 4) |  // imm3
                             (lo & 0x00ff));         // imm8
   }
+  case R_ARM_THM_ALU_PREL_11_0: {
+    // Thumb2 ADR, which is an alias for a sub or add instruction with an
+    // unsigned immediate.
+    // ADR encoding T2 (sub), T3 (add) i:imm3:imm8
+    uint16_t hi = read16le(buf);
+    uint16_t lo = read16le(buf + 2);
+    uint64_t imm = (hi & 0x0400) << 1 | // i
+                   (lo & 0x7000) >> 4 | // imm3
+                   (lo & 0x00ff);       // imm8
+    // For sub, addend is negative, add is positive.
+    return (hi & 0x00f0) ? -imm : imm;
+  }
+  case R_ARM_THM_PC8:
+    // ADR and LDR (literal) encoding T1
+    // From ELF for the ARM Architecture the initial signed addend is formed
+    // from an unsigned field using expression (((imm8:00 + 4) & 0x3ff) – 4)
+    // this trick permits the PC bias of -4 to be encoded using imm8 = 0xff
+    return ((((read16le(buf) & 0xff) << 2) + 4) & 0x3ff) - 4;
+  case R_ARM_THM_PC12: {
+    // LDR (literal) encoding T2, add = (U == '1') imm12
+    bool u = read16le(buf) & 0x0080;
+    uint64_t imm12 = read16le(buf + 2) & 0x0fff;
+    return u ? imm12 : -imm12;
+  }
   }
 }
 

diff  --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index c77485539004..7aec542575a4 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -525,9 +525,14 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a,
   case R_ARM_MOVW_PREL_NC:
   case R_ARM_MOVT_PREL:
   case R_ARM_REL32:
+  case R_ARM_THM_ALU_PREL_11_0:
   case R_ARM_THM_MOVW_PREL_NC:
   case R_ARM_THM_MOVT_PREL:
+  case R_ARM_THM_PC12:
     return p + a;
+  // p + a is unrepresentable as negative immediates can't be encoded.
+  case R_ARM_THM_PC8:
+    return p;
   }
   llvm_unreachable("ARM pc-relative relocation expected\n");
 }
@@ -739,8 +744,12 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a,
                               *hiRel->sym, hiRel->expr);
     return 0;
   }
-  case R_PC: {
+  case R_PC:
+  case R_ARM_PCA: {
     uint64_t dest;
+    if (expr == R_ARM_PCA)
+      // Some PC relative ARM (Thumb) relocations align down the place.
+      p = p & 0xfffffffc;
     if (sym.isUndefWeak()) {
       // On ARM and AArch64 a branch to an undefined weak resolves to the
       // next instruction, otherwise the place.
@@ -865,7 +874,7 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
       std::string msg = getLocation<ELFT>(offset) +
                         ": has non-ABS relocation " + toString(type) +
                         " against symbol '" + toString(sym) + "'";
-      if (expr != R_PC) {
+      if (expr != R_PC && expr != R_ARM_PCA) {
         error(msg);
         return;
       }

diff  --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index bfec1e628851..4069fc5f4786 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -80,6 +80,7 @@ enum RelExpr {
   R_AARCH64_PAGE_PC,
   R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
   R_AARCH64_TLSDESC_PAGE,
+  R_ARM_PCA,
   R_ARM_SBREL,
   R_MIPS_GOTREL,
   R_MIPS_GOT_GP,

diff  --git a/lld/test/ELF/arm-thumb-adr-err.s b/lld/test/ELF/arm-thumb-adr-err.s
new file mode 100644
index 000000000000..79c9fcbaf828
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-adr-err.s
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -g --triple=thumbv6m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+ .section .text.0, "ax", %progbits
+ .balign 4
+ .thumb_func
+low:
+ bx lr
+
+ .section .text.1, "ax", %progbits
+ .balign 2
+ .global _start
+ .thumb_func
+_start:
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x0): relocation R_ARM_THM_PC8 out of range: 18446744073709551612 is not in [0, 1023]
+ adr r0, low
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x2): improper alignment for relocation R_ARM_THM_PC8: 0x2 is not aligned to 4 bytes
+ adr r1, unaligned
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x4): relocation R_ARM_THM_PC8 out of range: 1024 is not in [0, 1023]
+ adr r2, range
+
+ .section .text.2, "ax", %progbits
+ .balign 4
+ nop
+ .thumb_func
+unaligned:
+  bx lr
+ .space 1020
+range:
+  bx lr

diff  --git a/lld/test/ELF/arm-thumb-adr.s b/lld/test/ELF/arm-thumb-adr.s
new file mode 100644
index 000000000000..e61202979387
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-adr.s
@@ -0,0 +1,40 @@
+// RUN: llvm-mc --triple=thumbv6m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -d --no-show-raw-insn %t --triple=thumbv6m-none-eabi | FileCheck %s
+
+/// Test R_ARM_THM_PC8 as used in the adr pseudo instruction. Only positive
+/// 4-byte aligned offsets are permitted.
+ .section .text.01, "ax", %progbits
+ .balign 4
+ .global _start
+ .thumb_func
+_start:
+ adr r0, target1
+ adr r1, target2
+
+ .section .text.02, "ax", %progbits
+ .balign 4
+ .global target1
+ .type target1, %function
+target1:
+ nop
+ bx lr
+ .section .text.03, "ax", %progbits
+ .balign 4
+ .space 1016
+ .type target2, %function
+target2:
+ nop
+ bx lr
+
+// CHECK: 000110b4 _start:
+// CHECK-NEXT: 110b4: adr     r0, #0
+// CHECK-NEXT: 110b6: adr     r1, #1020
+
+// CHECK: 000110b8 target1:
+// CHECK-NEXT: 110b8: nop
+// CHECK-NEXT: 110ba: bx      lr
+
+// CHECK: 000114b4 target2:
+// CHECK-NEXT: 114b4: nop
+// CHECK-NEXT: 114b6: bx      lr

diff  --git a/lld/test/ELF/arm-thumb-ldrlit-err.s b/lld/test/ELF/arm-thumb-ldrlit-err.s
new file mode 100644
index 000000000000..752f494aed38
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-ldrlit-err.s
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -g --triple=thumbv6m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+ .section .text.0, "ax", %progbits
+ .balign 4
+ .thumb_func
+low:
+ bx lr
+
+ .section .text.1, "ax", %progbits
+ .balign 2
+ .global _start
+ .thumb_func
+_start:
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x0): relocation R_ARM_THM_PC8 out of range: 18446744073709551612 is not in [0, 1023]
+ ldr r0, low
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x2): improper alignment for relocation R_ARM_THM_PC8: 0x2 is not aligned to 4 bytes
+ ldr r1, unaligned
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x4): relocation R_ARM_THM_PC8 out of range: 1024 is not in [0, 1023]
+ ldr r2, range
+
+ .section .text.2, "ax", %progbits
+ .balign 4
+ nop
+ .thumb_func
+unaligned:
+  bx lr
+ .space 1020
+range:
+  bx lr

diff  --git a/lld/test/ELF/arm-thumb-ldrlit.s b/lld/test/ELF/arm-thumb-ldrlit.s
new file mode 100644
index 000000000000..3dea279f2d22
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-ldrlit.s
@@ -0,0 +1,40 @@
+// RUN: llvm-mc --triple=thumbv6m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-objdump -d --no-show-raw-insn %t --triple=thumbv6m-none-eabi | FileCheck %s
+
+/// Test R_ARM_THM_PC8 as used in the ldr pseudo instruction. Only positive
+/// 4-byte aligned offsets are permitted.
+ .section .text.01, "ax", %progbits
+ .balign 4
+ .global _start
+ .thumb_func
+_start:
+ ldr r0, target1
+ ldr r1, target2
+
+ .section .text.02, "ax", %progbits
+ .balign 4
+ .global target1
+ .type target1, %function
+target1:
+ nop
+ bx lr
+ .section .text.03, "ax", %progbits
+ .balign 4
+ .space 1016
+ .type target2, %function
+target2:
+ nop
+ bx lr
+
+// CHECK: 000110b4 _start:
+// CHECK-NEXT: 110b4: ldr     r0, [pc, #0]
+// CHECK-NEXT: 110b6: ldr     r1, [pc, #1020]
+
+// CHECK: 000110b8 target1:
+// CHECK-NEXT: 110b8: nop
+// CHECK-NEXT: 110ba: bx      lr
+
+// CHECK: 000114b4 target2:
+// CHECK-NEXT: 114b4: nop
+// CHECK-NEXT: 114b6: bx      lr

diff  --git a/lld/test/ELF/arm-thumb-pc8-weak.s b/lld/test/ELF/arm-thumb-pc8-weak.s
new file mode 100644
index 000000000000..aeb9036ff0c8
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-pc8-weak.s
@@ -0,0 +1,24 @@
+// REQUIRES: arm
+// RUN: llvm-mc --arm-add-build-attributes -filetype=obj -triple=thumbv6a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump --no-show-raw-insn -triple=thumbv6a-none-linux-gnueabi -d %t2
+
+/// Check that the ARM ABI rules for undefined weak symbols are applied.
+/// Relative relocations are resolved to the place. Although we can't encode
+/// this for R_ARM_THM_PC8 as negative addends are not permitted. Use smallest
+/// available value. These are corner cases.
+ .syntax unified
+
+ .weak target
+ .type target, %function
+
+ .text
+ .global _start
+_start:
+ /// R_ARM_THM_PC8
+ adr r0, target
+ ldr r0, target
+
+// CHECK: 000110b4 _start:
+// CHECK-NEXT: 110b4: adr     r0, #0
+// CHECK-NEXT:        ldr     r0, [pc, #0]

diff  --git a/lld/test/ELF/arm-thumb-undefined-weak.s b/lld/test/ELF/arm-thumb-undefined-weak.s
index 82069a7d9db5..3bdc3d773022 100644
--- a/lld/test/ELF/arm-thumb-undefined-weak.s
+++ b/lld/test/ELF/arm-thumb-undefined-weak.s
@@ -1,5 +1,5 @@
 // REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc --arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
 // RUN: ld.lld %t -o %t2
 // RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s
 
@@ -27,7 +27,10 @@ _start:
  movt r0, :upper16:target - .
 // R_ARM_THM_MOVW_PREL_NC
  movw r0, :lower16:target - .
-
+// R_ARM_THM_ALU_PREL_11_0
+ adr r0, target
+// R_ARM_THM_PC12
+ ldr r0, target
 // CHECK: Disassembly of section .text:
 // CHECK-EMPTY:
 // CHECK:         110b4: {{.*}} beq.w   #0 <_start+0x4>
@@ -37,3 +40,5 @@ _start:
 // CHECK-NEXT:    110c0: {{.*}} bl      #0
 // CHECK-NEXT:    110c4: {{.*}} movt    r0, #0
 // CHECK-NEXT:    110c8: {{.*}} movw    r0, #0
+// CHECK-NEXT:    110cc: {{.*}} adr.w   r0, #-4
+// CHECK-NEXT:    110d0: {{.*}} ldr.w   r0, [pc, #-4]

diff  --git a/lld/test/ELF/arm-thumb2-adr-err.s b/lld/test/ELF/arm-thumb2-adr-err.s
new file mode 100644
index 000000000000..0512cee37adc
--- /dev/null
+++ b/lld/test/ELF/arm-thumb2-adr-err.s
@@ -0,0 +1,25 @@
+// RUN: llvm-mc -g --triple=thumbv7m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+ .section .text.0, "ax", %progbits
+ .thumb_func
+ .balign 4
+low:
+  bx lr
+  nop
+  nop
+
+ .section .text.1, "ax", %progbits
+ .global _start
+ .thumb_func
+_start:
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x0): relocation R_ARM_THM_ALU_PREL_11_0 out of range: 4098 is not in [0, 4095]
+ adr.w r0, low - 4091
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x4): relocation R_ARM_THM_ALU_PREL_11_0 out of range: 4096 is not in [0, 4095]
+ adr.w r0, high + 4091
+
+ .section .text.2
+ .thumb_func
+ .balign 4
+high:
+ bx lr

diff  --git a/lld/test/ELF/arm-thumb2-adr.s b/lld/test/ELF/arm-thumb2-adr.s
new file mode 100644
index 000000000000..aeac2f3f4ee5
--- /dev/null
+++ b/lld/test/ELF/arm-thumb2-adr.s
@@ -0,0 +1,156 @@
+// RUN: llvm-mc --triple=thumbv7m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: echo "SECTIONS { \
+// RUN:                 .rodata.low 0x8012  : { *(.rodata.low) } \
+// RUN:                 .text.low   0x8f00  : { *(.text.low) } \
+// RUN:                 .text.neg   0x9000  : { *(.text.neg) } \
+// RUN:                 .text.pos   0x10000 : { *(.text.pos) } \
+// RUN:                 .text.high  0x10100 : { *(.text.high) } \
+// RUN:                 .data_high  0x1100f : { *(.data.high) } \
+// RUN:               } " > %t.script
+// RUN: ld.lld --script %t.script %t.o -o %t
+// RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=SYMS
+// RUN: llvm-objdump -d --no-show-raw-insn --triple=thumbv7m-none-eabi %t
+// RUN: llvm-objdump -d --no-show-raw-insn --triple=thumbv7m-none-eabi %t | FileCheck %s
+
+/// Test the various legal cases for the R_ARM_THM_ALU_PREL_11_0 relocation
+/// Interesting things to note
+/// Range is +- 4095 bytes
+/// The expression is S + A - Pa where Pa is AlignDown(PC, 4) so we will use
+/// 2-byte nops to make some of the adr psuedo instructions 2-byte aligned.
+ .section .rodata.low, "a", %progbits
+dat1:
+ .byte 0
+dat2:
+ .byte 1
+dat3:
+ .byte 2
+dat4:
+ .byte 3
+
+ .section .text.low, "ax", %progbits
+ .balign 4
+ .global target1
+ .type target1, %function
+target1:
+ bx lr
+ .type target2, %function
+target2:
+ bx lr
+
+ .section .text.neg, "ax", %progbits
+ .balign 4
+ .global _start
+ .thumb_func
+_start:
+ nop
+ adr.w r0, dat1
+ adr.w r1, dat2
+ nop
+ adr.w r2, dat3
+ adr.w r3, dat4
+ .balign 4
+ adr.w r0, target1
+ nop
+ adr.w r1, target2
+
+ .section .text.pos, "ax", %progbits
+ .balign 4
+ .global pos
+ .thumb_func
+pos:
+ adr.w r2, target3
+ nop
+ adr.w r3, target4
+ .balign 4
+ adr.w r0, dat5
+ adr.w r1, dat6
+ nop
+ adr.w r2, dat7
+ adr.w r3, dat8
+/// positive addend in instruction, all others are -4 (PC bias)
+ adr.w r4, dat5 + 8
+
+ .section .text.high, "ax", %progbits
+ .balign 4
+ .thumb_func
+ .global target3
+target3:
+ bx lr
+ .thumb_func
+target4:
+ bx lr
+
+ .section .data.high, "aw", %progbits
+dat5:
+ .byte 0
+dat6:
+ .byte 1
+dat7:
+ .byte 2
+dat8:
+ .byte 3
+
+// SYMS:     Name: dat1
+// SYMS-NEXT:     Value: 0x8012
+// SYMS:     Name: dat2
+// SYMS-NEXT:     Value: 0x8013
+// SYMS:     Name: dat3
+// SYMS-NEXT:     Value: 0x8014
+// SYMS:     Name: dat4
+// SYMS-NEXT:     Value: 0x8015
+
+// CHECK: 00008f00 target1:
+// CHECK-NEXT:     8f00: bx      lr
+// CHECK: 00008f02 target2:
+// CHECK-NEXT:     8f02: bx      lr
+
+// CHECK: 00009000 _start:
+// CHECK-NEXT:     9000: nop
+/// AlignDown(0x9002+4, 4) - 0xff2 = 0x8012
+// CHECK-NEXT:     9002: adr.w   r0, #-4082
+/// AlignDown(0x9006+4, 4) - 0xff5 = 0x8013
+// CHECK-NEXT:     9006: adr.w   r1, #-4085
+// CHECK-NEXT:     900a: nop
+/// AlignDown(0x900c+4, 4) - 0xffc = 0x8014
+// CHECK-NEXT:     900c: adr.w   r2, #-4092
+/// AlignDown(0x9010+4, 4) - 0xfff = 0x8015
+// CHECK-NEXT:     9010: adr.w   r3, #-4095
+/// AlignDown(0x9014+4, 4) - 0x117 = 0x8f01
+// CHECK-NEXT:     9014: adr.w   r0, #-279
+// CHECK-NEXT:     9018: nop
+/// AlignDown(0x901a+4, 4) - 0x119 = 0x8f03
+// CHECK-NEXT:     901a: adr.w   r1, #-281
+
+// CHECK: 00010000 pos:
+/// AlignDown(0x10000+4, 4) + 0xfd = 0x10101
+// CHECK-NEXT:    10000: adr.w   r2, #253
+// CHECK-NEXT:    10004: nop
+/// AlignDown(0x10006+4, 4) + 0xfb = 0x10103
+// CHECK-NEXT:    10006: adr.w   r3, #251
+// CHECK-NEXT:    1000a: nop
+/// AlignDown(0x1000c+4, 4) + 0xfff = 0x1100f
+// CHECK-NEXT:    1000c: adr.w   r0, #4095
+/// AlignDown(0x10010+4, 4) + 0xffc = 0x11010
+// CHECK-NEXT:    10010: adr.w   r1, #4092
+// CHECK-NEXT:    10014: nop
+/// AlignDown(0x10016+4, 4) + 0xff9 = 0x11011
+// CHECK-NEXT:    10016: adr.w   r2, #4089
+/// AlignDown(0x1001a+4, 4) + 0xff6 = 0x11012
+// CHECK-NEXT:    1001a: adr.w   r3, #4086
+/// AlignDown(0x1001e+4, 4) + 0xff7 = 0x11017 = dat5 + 8
+// CHECK-NEXT:   1001e:  adr.w  r4, #4087
+
+// CHECK: 00010100 target3:
+// CHECK-NEXT:    10100: bx      lr
+
+// CHECK: 00010102 target4:
+// CHECK-NEXT:    10102: bx      lr
+
+// SYMS:     Name: dat5
+// SYMS-NEXT:     Value: 0x1100F
+// SYMS:     Name: dat6
+// SYMS-NEXT:     Value: 0x11010
+// SYMS:     Name: dat7
+// SYMS-NEXT:     Value: 0x11011
+// SYMS:     Name: dat8
+// SYMS-NEXT:     Value: 0x11012

diff  --git a/lld/test/ELF/arm-thumb2-ldrlit-err.s b/lld/test/ELF/arm-thumb2-ldrlit-err.s
new file mode 100644
index 000000000000..c1dc246b8095
--- /dev/null
+++ b/lld/test/ELF/arm-thumb2-ldrlit-err.s
@@ -0,0 +1,25 @@
+// RUN: llvm-mc -g --triple=thumbv7m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+ .section .text.0, "ax", %progbits
+ .thumb_func
+ .balign 4
+low:
+  bx lr
+  nop
+  nop
+
+ .section .text.1, "ax", %progbits
+ .global _start
+ .thumb_func
+_start:
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x0): relocation R_ARM_THM_PC12 out of range: 4098 is not in [0, 4095]
+ ldr.w r0, low - 4091
+// CHECK: {{.*}}.s:[[# @LINE+1]]:(.text.1+0x4): relocation R_ARM_THM_PC12 out of range: 4096 is not in [0, 4095]
+ ldr.w r0, high + 4091
+
+ .section .text.2
+ .thumb_func
+ .balign 4
+high:
+ bx lr

diff  --git a/lld/test/ELF/arm-thumb2-ldrlit.s b/lld/test/ELF/arm-thumb2-ldrlit.s
new file mode 100644
index 000000000000..3c3bf078ac60
--- /dev/null
+++ b/lld/test/ELF/arm-thumb2-ldrlit.s
@@ -0,0 +1,156 @@
+// RUN: llvm-mc --triple=thumbv7m-none-eabi --arm-add-build-attributes -filetype=obj -o %t.o %s
+// RUN: echo "SECTIONS { \
+// RUN:                 .rodata.low 0x8012  : { *(.rodata.low) } \
+// RUN:                 .text.low   0x8f00  : { *(.text.low) } \
+// RUN:                 .text.neg   0x9000  : { *(.text.neg) } \
+// RUN:                 .text.pos   0x10000 : { *(.text.pos) } \
+// RUN:                 .text.high  0x10100 : { *(.text.high) } \
+// RUN:                 .data_high  0x1100f : { *(.data.high) } \
+// RUN:               } " > %t.script
+// RUN: ld.lld --script %t.script %t.o -o %t
+// RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=SYMS
+// RUN: llvm-objdump -d --no-show-raw-insn --triple=thumbv7m-none-eabi %t | FileCheck %s
+
+/// Test the various legal cases for the R_ARM_THM_PC12 relocation
+/// Interesting things to note
+/// Range is +- 4095 bytes
+/// The Thumb bit for function symbols is ignored
+/// The expression is S + A - Pa where Pa is AlignDown(PC, 4) so we will use
+/// 2-byte nops to make some of the ldr instructions 2-byte aligned.
+ .section .rodata.low, "a", %progbits
+dat1:
+ .byte 0
+dat2:
+ .byte 1
+dat3:
+ .byte 2
+dat4:
+ .byte 3
+
+ .section .text.low, "ax", %progbits
+ .balign 4
+ .global target1
+ .type target1, %function
+target1:
+ bx lr
+ .type target2, %function
+target2:
+ bx lr
+
+ .section .text.neg, "ax", %progbits
+ .balign 4
+ .global _start
+ .thumb_func
+_start:
+ nop
+ ldr r0, dat1
+ ldr r1, dat2
+ nop
+ ldr r2, dat3
+ ldr r3, dat4
+ .balign 4
+ ldr r0, target1
+ nop
+ ldr r1, target2
+
+ .section .text.pos, "ax", %progbits
+ .balign 4
+ .global pos
+ .thumb_func
+pos:
+ ldr r2, target3
+ nop
+ ldr r3, target4
+ .balign 4
+ ldr r0, dat5
+ ldr r1, dat6
+ nop
+ ldr r2, dat7
+ ldr r3, dat8
+/// positive addend in instruction, all others are -4 (PC bias)
+ ldr.w r4, dat5 + 8
+
+ .section .text.high, "ax", %progbits
+ .balign 4
+ .thumb_func
+ .global target3
+target3:
+ bx lr
+ .thumb_func
+target4:
+ bx lr
+
+ .section .data.high, "aw", %progbits
+dat5:
+ .byte 0
+dat6:
+ .byte 1
+dat7:
+ .byte 2
+dat8:
+ .byte 3
+
+// SYMS:     Name: dat1
+// SYMS-NEXT:     Value: 0x8012
+// SYMS:     Name: dat2
+// SYMS-NEXT:     Value: 0x8013
+// SYMS:     Name: dat3
+// SYMS-NEXT:     Value: 0x8014
+// SYMS:     Name: dat4
+// SYMS-NEXT:     Value: 0x8015
+
+// CHECK: 00008f00 target1:
+// CHECK-NEXT:     8f00: bx      lr
+// CHECK: 00008f02 target2:
+// CHECK-NEXT:     8f02: bx      lr
+
+// CHECK: 00009000 _start:
+// CHECK-NEXT:     9000: nop
+/// AlignDown(0x9002+4, 4) - 0xff2 = 0x8012
+// CHECK-NEXT:     9002: ldr.w   r0, [pc, #-4082]
+/// AlignDown(0x9006+4, 4) - 0xff5 = 0x8013
+// CHECK-NEXT:     9006: ldr.w   r1, [pc, #-4085]
+// CHECK-NEXT:     900a: nop
+/// AlignDown(0x900c+4, 4) - 0xffc = 0x8014
+// CHECK-NEXT:     900c: ldr.w   r2, [pc, #-4092]
+/// AlignDown(0x9010+4, 4) - 0xfff = 0x8015
+// CHECK-NEXT:     9010: ldr.w   r3, [pc, #-4095]
+/// AlignDown(0x9014+4, 4) - 0x118 = 0x8f00
+// CHECK-NEXT:     9014: ldr.w   r0, [pc, #-280]
+// CHECK-NEXT:     9018: nop
+/// AlignDown(0x901a+4, 4) - 0x11a = 0x8f02
+// CHECK-NEXT:     901a: ldr.w   r1, [pc, #-282]
+
+// CHECK: 00010000 pos:
+/// AlignDown(0x10000+4, 4) + 0x1c = 0x10100
+// CHECK-NEXT:    10000: ldr.w   r2, [pc, #252]
+// CHECK-NEXT:    10004: nop
+/// AlignDown(0x10006+4, 4) + 0x1a = 0x10122
+// CHECK-NEXT:    10006: ldr.w   r3, [pc, #250]
+// CHECK-NEXT:    1000a: nop
+/// AlignDown(0x1000c+4, 4) + 0xfff = 0x1100f
+// CHECK-NEXT:    1000c: ldr.w   r0, [pc, #4095]
+/// AlignDown(0x10010+4, 4) + 0xffc = 0x11010
+// CHECK-NEXT:    10010: ldr.w   r1, [pc, #4092]
+// CHECK-NEXT:    10014: nop
+/// AlignDown(0x10016+4, 4) + 0xff9 = 0x11011
+// CHECK-NEXT:    10016: ldr.w   r2, [pc, #4089]
+/// AlignDown(0x1001a+4, 4) + 0xff6 = 0x11012
+// CHECK-NEXT:    1001a: ldr.w   r3, [pc, #4086]
+/// AlignDown(0x1001e+4, 4) + 0xff7 = 0x11017 = dat5 + 8
+// CHECK-NEXT:    1001e: ldr.w   r4, [pc, #4087]
+
+// CHECK: 00010100 target3:
+// CHECK-NEXT:    10100: bx      lr
+
+// CHECK: 00010102 target4:
+// CHECK-NEXT:    10102: bx      lr
+
+// SYMS:     Name: dat5
+// SYMS-NEXT:     Value: 0x1100F
+// SYMS:     Name: dat6
+// SYMS-NEXT:     Value: 0x11010
+// SYMS:     Name: dat7
+// SYMS-NEXT:     Value: 0x11011
+// SYMS:     Name: dat8
+// SYMS-NEXT:     Value: 0x11012


        


More information about the llvm-commits mailing list