[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