Index: lld/ELF/Arch/ARM.cpp =================================================================== --- lld/ELF/Arch/ARM.cpp +++ lld/ELF/Arch/ARM.cpp @@ -132,6 +132,10 @@ 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 @@ ((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 && 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 && 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 @@ ((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; + } } } Index: lld/ELF/InputSection.cpp =================================================================== --- lld/ELF/InputSection.cpp +++ lld/ELF/InputSection.cpp @@ -525,9 +525,14 @@ 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 @@ *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 @@ std::string msg = getLocation(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; } Index: lld/ELF/Relocations.h =================================================================== --- lld/ELF/Relocations.h +++ lld/ELF/Relocations.h @@ -80,6 +80,7 @@ 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, Index: lld/test/ELF/arm-thumb-adr-err.s =================================================================== --- /dev/null +++ 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 -n %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 Index: lld/test/ELF/arm-thumb-adr.s =================================================================== --- /dev/null +++ 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 Index: lld/test/ELF/arm-thumb-ldrlit-err.s =================================================================== --- /dev/null +++ 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 -n %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 Index: lld/test/ELF/arm-thumb-ldrlit.s =================================================================== --- /dev/null +++ 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 Index: lld/test/ELF/arm-thumb-pc8-weak.s =================================================================== --- /dev/null +++ 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] Index: lld/test/ELF/arm-thumb-undefined-weak.s =================================================================== --- lld/test/ELF/arm-thumb-undefined-weak.s +++ 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 @@ 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 @@ // 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] Index: lld/test/ELF/arm-thumb2-adr-err.s =================================================================== --- /dev/null +++ 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 -n %t.o -o %t 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 Index: lld/test/ELF/arm-thumb2-adr.s =================================================================== --- /dev/null +++ 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 -n --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 Index: lld/test/ELF/arm-thumb2-ldrlit-err.s =================================================================== --- /dev/null +++ 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 -n %t.o -o %t 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 Index: lld/test/ELF/arm-thumb2-ldrlit.s =================================================================== --- /dev/null +++ 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 -n --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