aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Smith <peter.smith@arm.com>2016-05-24 18:42:28 +0100
committerPeter Smith <peter.smith@arm.com>2016-06-07 09:51:01 +0100
commit37bd5eb5059e9761df155341a0a5b8a1ab521ed6 (patch)
treee54a13bece951a803930a5b6da3b8d18bd97641a
parentb75bd9cb41ff4a16606d75aa1b3dbd82e7a93430 (diff)
Initial support for ARM in lld.linaro-local/ARMportforupstream
Add support for an ARM Target and the initial set of relocations and PLT entries that are necessary for an ARM only hello world to link. This has been tested against an ARM only sysroot from the 4.2.0 CodeSourcery Lite release. Tests have been added to test/ELF for the support that has been implemented. Main limitations: - No Thumb support - Relocations incomplete - No C++ exceptions support - No TLS support - No range extension or interworking veneer (thunk) support - No Build Attribute support - No Big-endian support The deprecated relocations R_ARM_PLT32 and R_ARM_PC24 have been implemented as these are used by the 4.2.0 CodeSourcery Lite release. Change-Id: I72b5105ee1e04c7c0288dba53ca278b96ee147b7
-rw-r--r--ELF/Driver.cpp2
-rw-r--r--ELF/InputFiles.cpp5
-rw-r--r--ELF/Target.cpp171
-rw-r--r--test/ELF/Inputs/arm-plt-reloc.s14
-rw-r--r--test/ELF/Inputs/far-arm-abs.s13
-rw-r--r--test/ELF/Inputs/relocation-copy-arm.s22
-rw-r--r--test/ELF/arm-abs32-dyn.s32
-rw-r--r--test/ELF/arm-attributes-remove.s44
-rw-r--r--test/ELF/arm-branch-error.s19
-rw-r--r--test/ELF/arm-branch.s59
-rw-r--r--test/ELF/arm-copy.s81
-rw-r--r--test/ELF/arm-data-prel.s63
-rw-r--r--test/ELF/arm-data-relocs.s20
-rw-r--r--test/ELF/arm-fpic-got.s63
-rw-r--r--test/ELF/arm-gnu-ifunc-nosym.s27
-rw-r--r--test/ELF/arm-gnu-ifunc.s131
-rw-r--r--test/ELF/arm-got-relative.s53
-rw-r--r--test/ELF/arm-gotoff.s74
-rw-r--r--test/ELF/arm-mov-relocs.s53
-rw-r--r--test/ELF/arm-plt-reloc.s90
20 files changed, 1036 insertions, 0 deletions
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 866656b1b..18893f918 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -71,6 +71,8 @@ static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {
return {ELF64LEKind, EM_X86_64};
if (S == "aarch64linux")
return {ELF64LEKind, EM_AARCH64};
+ if (S == "armelf_linux_eabi")
+ return {ELF32LEKind, EM_ARM};
if (S == "i386pe" || S == "i386pep" || S == "thumb2pe")
error("Windows targets are not supported on the ELF frontend: " + S);
else
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 48d04f894..19109bfa6 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -244,6 +244,11 @@ void elf::ObjectFile<ELFT>::initializeSections(
}
fatal("relocations pointing to SHF_MERGE are not supported");
}
+ case SHT_ARM_ATTRIBUTES:
+ // FIXME: ARM meta-data section. At present attributes are ignored,
+ // they can be used to reason about object compatibility.
+ Sections[I] = &InputSection<ELFT>::Discarded;
+ break;
default:
Sections[I] = createInputSection(Sec);
}
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 529abacae..562c97105 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -170,6 +170,19 @@ public:
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
};
+class ARMTargetInfo final : public TargetInfo {
+public:
+ ARMTargetInfo();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ uint32_t getDynRel(uint32_t Type) const override;
+ uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
+ void writePltZero(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+
template <class ELFT> class MipsTargetInfo final : public TargetInfo {
public:
MipsTargetInfo();
@@ -196,6 +209,8 @@ TargetInfo *createTarget() {
return new AArch64TargetInfo();
case EM_AMDGPU:
return new AMDGPUTargetInfo();
+ case EM_ARM:
+ return new ARMTargetInfo();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
@@ -1427,6 +1442,162 @@ RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
llvm_unreachable("not implemented");
}
+ARMTargetInfo::ARMTargetInfo() {
+ CopyRel = R_ARM_COPY;
+ RelativeRel = R_ARM_RELATIVE;
+ IRelativeRel = R_ARM_IRELATIVE;
+ GotRel = R_ARM_GLOB_DAT;
+ PltRel = R_ARM_JUMP_SLOT;
+ TlsGotRel = R_ARM_TLS_TPOFF32;
+ TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
+ TlsOffsetRel = R_ARM_TLS_DTPOFF32;
+ PltEntrySize = 16;
+ PltZeroSize = 20;
+}
+
+RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ return R_PLT_PC;
+ case R_ARM_GOTOFF32:
+ // (S + A) - GOT_ORG
+ return R_GOTREL;
+ case R_ARM_GOT_BREL:
+ // GOT(S) + A - GOT_ORG
+ return R_GOT_OFF;
+ case R_ARM_GOT_PREL:
+ // GOT(S) + - GOT_ORG
+ return R_GOT_PC;
+ case R_ARM_BASE_PREL:
+ // B(S) + A - P
+ // FIXME: currently B(S) assumed to be .got, this may not hold for all
+ // platforms.
+ return R_GOTONLY_PC;
+ case R_ARM_PREL31:
+ case R_ARM_REL32:
+ return R_PC;
+ }
+}
+
+uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const {
+ if (Type == R_ARM_ABS32)
+ return Type;
+ StringRef S = getELFRelocationTypeName(EM_ARM, Type);
+ error("relocation " + S + " cannot be used when making a shared object; "
+ "recompile with -fPIC.");
+ // Keep it going with a dummy value so that we can find more reloc errors.
+ return R_ARM_ABS32;
+}
+
+void ARMTargetInfo::writeGotPlt(uint8_t *Buf, uint64_t Plt) const {
+ write32le(Buf, Out<ELF32LE>::Plt->getVA());
+}
+
+void ARMTargetInfo::writePltZero(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]!
+ 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2
+ 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr
+ 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t GotPlt = Out<ELF32LE>::GotPlt->getVA();
+ uint64_t L1 = Out<ELF32LE>::Plt->getVA() + 8;
+ write32le(Buf + 16, GotPlt - L1 - 8);
+}
+
+void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ // FIXME: Using simple code sequence with simple relocations.
+ // There is a more optimal sequence but it requires support for the group
+ // relocations. See ELF for the ARM Architecture Appendix A.3
+ const uint8_t PltData[] = {
+ 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2
+ 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+ 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t L1 = PltEntryAddr + 4;
+ write32le(Buf + 12, GotEntryAddr - L1 - 8);
+}
+
+void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ switch (Type) {
+ case R_ARM_NONE:
+ break;
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ write32le(Loc, Val);
+ break;
+ case R_ARM_PREL31:
+ checkInt<31>(Val, Type);
+ write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
+ break;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ checkInt<26>(Val, Type);
+ write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
+ break;
+ case R_ARM_MOVW_ABS_NC:
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
+ (Val & 0x0fff));
+ break;
+ case R_ARM_MOVT_ABS:
+ checkUInt<32>(Val, Type);
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
+ (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
+ break;
+ default:
+ fatal("unrecognized reloc " + Twine(Type));
+ }
+}
+
+uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
+ switch (Type) {
+ default:
+ return 0;
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ return SignExtend64<32>(read32le(Buf));
+ break;
+ case R_ARM_PREL31:
+ return SignExtend64<31>(read32le(Buf));
+ break;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ return SignExtend64<26>((read32le(Buf) & 0x00ffffff) << 2);
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS: {
+ // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
+ // MOVT is in the range -32768 <= A < 32768
+ uint64_t Val = read32le(Buf) & 0x000f0fff;
+ return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
+ }
+ }
+}
+
template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
GotPltHeaderEntriesNum = 2;
PageSize = 65536;
diff --git a/test/ELF/Inputs/arm-plt-reloc.s b/test/ELF/Inputs/arm-plt-reloc.s
new file mode 100644
index 000000000..29f133e6e
--- /dev/null
+++ b/test/ELF/Inputs/arm-plt-reloc.s
@@ -0,0 +1,14 @@
+.text
+ .align 2
+ .globl func1
+ .type func1,%function
+func1:
+ bx lr
+ .globl func2
+ .type func2,%function
+func2:
+ bx lr
+ .globl func3
+ .type func3,%function
+func3:
+ bx lr
diff --git a/test/ELF/Inputs/far-arm-abs.s b/test/ELF/Inputs/far-arm-abs.s
new file mode 100644
index 000000000..68d6aabe0
--- /dev/null
+++ b/test/ELF/Inputs/far-arm-abs.s
@@ -0,0 +1,13 @@
+.global far
+.type far,%function
+far = 0x201001c
+
+.global too_far1
+.type too_far1,%function
+too_far1 = 0x2020008
+.global too_far2
+.type too_far2,%function
+too_far2 = 0x202000c
+.global too_far3
+.type too_far3,%function
+too_far3 = 0x2020010
diff --git a/test/ELF/Inputs/relocation-copy-arm.s b/test/ELF/Inputs/relocation-copy-arm.s
new file mode 100644
index 000000000..ba5ab7304
--- /dev/null
+++ b/test/ELF/Inputs/relocation-copy-arm.s
@@ -0,0 +1,22 @@
+.bss
+
+.type x,%object
+.globl x
+.balign 16
+x:
+.long 0
+.size x, 4
+
+.type y,%object
+.globl y
+.balign 16
+y:
+.long 0
+.size y, 4
+
+.type z,%object
+.globl z
+.balign 4
+z:
+.long 0
+.size z, 4
diff --git a/test/ELF/arm-abs32-dyn.s b/test/ELF/arm-abs32-dyn.s
new file mode 100644
index 000000000..68183fe6f
--- /dev/null
+++ b/test/ELF/arm-abs32-dyn.s
@@ -0,0 +1,32 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux %s -o %t.o
+
+// Creates a R_ARM_ABS32 relocation against foo and bar, bar has hidden
+// visibility so we expect a R_ARM_RELATIVE
+ .syntax unified
+ .globl foo
+foo:
+ .globl bar
+ .hidden bar
+bar:
+
+ .data
+ .word foo
+ .word bar
+
+// RUN: ld.lld -shared -o %t.so %t.o
+// RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s
+
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT: 0x2004 R_ARM_RELATIVE
+// CHECK-NEXT: 0x2000 R_ARM_ABS32 foo 0x0
+// CHECK-NEXT: }
+
+// CHECK: Symbols [
+// CHECK: Symbol {
+// CHECK: Name: bar
+// CHECK-NEXT: Value: 0x1000
+
+// CHECK: Symbol {
+// CHECK: Name: foo
+// CHECK-NEXT: Value: 0x1000
diff --git a/test/ELF/arm-attributes-remove.s b/test/ELF/arm-attributes-remove.s
new file mode 100644
index 000000000..04f3e829f
--- /dev/null
+++ b/test/ELF/arm-attributes-remove.s
@@ -0,0 +1,44 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+// RUN: ld.lld %t.o -shared -o %t2
+// RUN: llvm-readobj -s %t2 | FileCheck %s
+// RUN: ld.lld %t.o -r -o %t3
+// RUN: llvm-readobj -s %t3 | FileCheck %s
+
+// The .ARM.attributes section should be removed from executables and
+// shared objects.
+
+// At present we remove it from the -r object output as well which isn't ideal.
+// Unfortunately combining per-object attributes cannot be safely done by just
+// concatentation of input sections.
+
+// CHECK-NOT: Name: .ARM.attributes
+ .text
+ .syntax unified
+ .eabi_attribute 67, "2.09" @ Tag_conformance
+ .cpu cortex-a8
+ .eabi_attribute 6, 10 @ Tag_CPU_arch
+ .eabi_attribute 7, 65 @ Tag_CPU_arch_profile
+ .eabi_attribute 8, 1 @ Tag_ARM_ISA_use
+ .eabi_attribute 9, 2 @ Tag_THUMB_ISA_use
+ .fpu neon
+ .eabi_attribute 15, 1 @ Tag_ABI_PCS_RW_data
+ .eabi_attribute 16, 1 @ Tag_ABI_PCS_RO_data
+ .eabi_attribute 17, 2 @ Tag_ABI_PCS_GOT_use
+ .eabi_attribute 20, 1 @ Tag_ABI_FP_denormal
+ .eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions
+ .eabi_attribute 23, 3 @ Tag_ABI_FP_number_model
+ .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access
+ .eabi_attribute 24, 1 @ Tag_ABI_align_needed
+ .eabi_attribute 25, 1 @ Tag_ABI_align_preserved
+ .eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format
+ .eabi_attribute 18, 4 @ Tag_ABI_PCS_wchar_t
+ .eabi_attribute 26, 2 @ Tag_ABI_enum_size
+ .eabi_attribute 14, 0 @ Tag_ABI_PCS_R9_use
+ .eabi_attribute 68, 1 @ Tag_Virtualization_use
+ .globl _start
+ .p2align 2
+ .type _start,%function
+_start:
+ bx lr
diff --git a/test/ELF/arm-branch-error.s b/test/ELF/arm-branch-error.s
new file mode 100644
index 000000000..f1a855d73
--- /dev/null
+++ b/test/ELF/arm-branch-error.s
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar
+// RUN: not ld.lld %t %tfar -o %t2 2>&1 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ // address of too_far symbols are just out of range of ARM branch with
+ // 26-bit immediate field and an addend of -8
+ bl too_far1
+ b too_far2
+ beq too_far3
+
+// CHECK: R_ARM_CALL out of range
+// CHECK-NEXT: R_ARM_JUMP24 out of range
+// CHECK-NEXT: R_ARM_JUMP24 out of range
diff --git a/test/ELF/arm-branch.s b/test/ELF/arm-branch.s
new file mode 100644
index 000000000..38266fabf
--- /dev/null
+++ b/test/ELF/arm-branch.s
@@ -0,0 +1,59 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar
+// RUN: echo "SECTIONS { \
+// RUN: .callee1 : { *(.callee_low) } \
+// RUN: .caller : { *(.text) } \
+// RUN: .callee2 : { *(.callee_high) } } " > %t.script
+// RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .section .callee_low, "ax",%progbits
+ .align 2
+ .type callee_low,%function
+callee_low:
+ bx lr
+
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ bl callee_low
+ b callee_low
+ beq callee_low
+ bl callee_high
+ b callee_high
+ bne callee_high
+ bl far
+ b far
+ bgt far
+ bx lr
+
+ .section .callee_high, "ax",%progbits
+ .align 2
+ .type callee_high,%function
+callee_high:
+ bx lr
+
+// CHECK: Disassembly of section .caller:
+// CHECK-NEXT: _start:
+// S(callee_low) = 0xb4 P = 0x10000 A = -8 = -0xff54 = -65364
+// CHECK-NEXT: 10000: 2b c0 ff eb bl #-65364 <callee_low>
+// S(callee_low) = 0xb4 P = 0x10004 A = -8 = -0xff58 = -65368
+// CHECK-NEXT: 10004: 2a c0 ff ea b #-65368 <callee_low>
+// S(callee_low) = 0xb4 P = 0x10008 A = -8 = -0xff5c -65372
+// CHECK-NEXT: 10008: 29 c0 ff 0a beq #-65372 <callee_low>
+// S(callee_high) = 0x10028 P = 0x1000c A = -8 = 0x14 = 20
+// CHECK-NEXT: 1000c: 05 00 00 eb bl #20 <callee_high>
+// S(callee_high) = 0x10028 P = 0x10010 A = -8 = 0x10 = 16
+// CHECK-NEXT: 10010: 04 00 00 ea b #16 <callee_high>
+// S(callee_high) = 0x10028 P = 0x10014 A = -8 = 0x0c =12
+// CHECK-NEXT: 10014: 03 00 00 1a bne #12 <callee_high>
+// S(far) = 0x201001c P = 0x10018 A = -8 = 0x1fffffc = 33554428
+// CHECK-NEXT: 10018: ff ff 7f eb bl #33554428
+// S(far) = 0x201001c P = 0x1001c A = -8 = 0x1fffff8 = 33554424
+// CHECK-NEXT: 1001c: fe ff 7f ea b #33554424
+// S(far) = 0x201001c P = 0x10020 A = -8 = 0x1fffff4 = 33554420
+// CHECK-NEXT: 10020: fd ff 7f ca bgt #33554420
+// CHECK-NEXT: 10024: 1e ff 2f e1 bx lr
diff --git a/test/ELF/arm-copy.s b/test/ELF/arm-copy.s
new file mode 100644
index 000000000..e5ce1577b
--- /dev/null
+++ b/test/ELF/arm-copy.s
@@ -0,0 +1,81 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/relocation-copy-arm.s -o %t2.o
+// RUN: ld.lld -shared %t2.o -o %t2.so
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CODE %s
+// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi -section=.rodata %t3 | FileCheck -check-prefix=RODATA %s
+
+// Copy relocations R_ARM_COPY are required for y and z
+ .syntax unified
+ .text
+ .globl _start
+_start:
+ movw r2,:lower16: y
+ movt r2,:upper16: y
+ ldr r3,[pc,#4]
+ ldr r3,[r3,#0]
+ .rodata
+ .word z
+
+// CHECK: Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x13000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK: Relocations [
+// CHECK-NEXT: Section (5) .rel.dyn {
+// CHECK-NEXT: Relocation {
+// CHECK-NEXT: Offset: 0x13000
+// CHECK-NEXT: Type: R_ARM_COPY
+// CHECK-NEXT: Symbol: y
+// CHECK-NEXT: Addend: 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: Relocation {
+// CHECK-NEXT: Offset: 0x13004
+// CHECK-NEXT: Type: R_ARM_COPY
+// CHECK-NEXT: Symbol: z
+// CHECK-NEXT: Addend: 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+
+// CHECK: Symbols [
+// CHECK: Name: y
+// CHECK-NEXT: Value: 0x13000
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other:
+// CHECK-NEXT: Section: .bss
+// CHECK: Name: z
+// CHECK-NEXT: Value: 0x13004
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// S(y) = 0x13000, A = 0
+// (S + A) & 0x0000ffff = 0x3000 = #12288
+// CODE-NEXT: 11000: 00 20 03 e3 movw r2, #12288
+// S(y) = 0x13000, A = 0
+// ((S + A) & 0xffff0000) >> 16 = 0x1
+// CODE-NEXT: 11004: 01 20 40 e3 movt r2, #1
+// CODE-NEXT: 11008: 04 30 9f e5 ldr r3, [pc, #4]
+// CODE-NEXT: 1100c: 00 30 93 e5 ldr r3, [r3]
+
+
+// RODATA: Contents of section .rodata:
+// S(z) = 0x13004
+// RODATA-NEXT: 10114 04300100
diff --git a/test/ELF/arm-data-prel.s b/test/ELF/arm-data-prel.s
new file mode 100644
index 000000000..590d8118a
--- /dev/null
+++ b/test/ELF/arm-data-prel.s
@@ -0,0 +1,63 @@
+// RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o
+// RUN: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .ARM.exidx : { *(.ARM.exidx) } \
+// RUN: .ARM.exidx.TEST1 : { *(.ARM.exidx.TEST1) } \
+// RUN: .TEST1 : { *(.TEST1) } } " > %t.script
+// RUN: ld.lld --script %t.script %t.o -o %t
+// RUN: llvm-readobj -s -sd %t | FileCheck --check-prefix=CHECK %s
+// REQUIRES: arm
+
+// The R_ARM_PREL31 relocation is used in by the .ARM.exidx exception tables
+// bit31 of the place denotes whether the field is an inline table entry
+// (bit31=1) or relocation (bit31=0)
+// The linker must preserve the value of bit31
+
+// This test case is adapted from llvm/test/MC/ARM/eh-compact-pr0.s
+// We use a linker script to place the .ARM.exidx sections in between
+// the code sections so that we can test positive and negative offsets
+ .syntax unified
+
+ .section .TEST1, "ax",%progbits
+ .globl _start
+ .align 2
+ .type _start,%function
+_start:
+ .fnstart
+ .save {r11, lr}
+ push {r11, lr}
+ .setfp r11, sp
+ mov r11, sp
+ pop {r11, lr}
+ mov pc, lr
+ .fnend
+
+ .section .text, "ax",%progbits
+// The generated .ARM.exidx section will refer to the personality
+// routine __aeabi_unwind_cpp_pr0. Provide a dummy implementation
+// to stop an undefined symbol error
+ .globl __aeabi_unwind_cpp_pr0
+ .align 2
+ .type __aeabi_unwind_cpp_pr0,%function
+__aeabi_unwind_cpp_pr0:
+ .fnstart
+ bx lr
+ .fnend
+
+// The expected value of the exception table is
+// Word0 0 in bit 31, -4 encoded in 31-bit signed offset
+// Word1 Inline table entry EHT Inline Personality Routine #0
+// CHECK: Name: .ARM.exidx
+// CHECK: SectionData (
+// CHECK: 0000: FCFFFF7F B0B0B080
+// CHECK: )
+
+// The expected value of the exception table is
+// Word0 0 in bit 31, +8 encoded in 31-bit signed offset
+// Word1 Inline table entry EHT Inline Personality Routine #0
+// set vsp = r11
+// pop r11, r14
+// CHECK: Name: .ARM.exidx.TEST1
+// CHECK: SectionData (
+// CHECK: 0000: 08000000 80849B80
+// CHECK: )
diff --git a/test/ELF/arm-data-relocs.s b/test/ELF/arm-data-relocs.s
new file mode 100644
index 000000000..ed237850c
--- /dev/null
+++ b/test/ELF/arm-data-relocs.s
@@ -0,0 +1,20 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/abs256.s -o %t256.o
+// RUN: ld.lld %t %t256.o -o %t2
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .globl _start
+_start:
+ .section .R_ARM_ABS32POS, "ax",%progbits
+ .word foo + 0x24
+
+// S = 0x100, A = 0x24
+// S + A = 0x124
+// CHECK: Disassembly of section .R_ARM_ABS32POS:
+// CHECK: 11000: 24 01 00 00
+ .section .R_ARM_ABS32NEG, "ax",%progbits
+ .word foo - 0x24
+// S = 0x100, A = -0x24
+// CHECK: Disassembly of section .R_ARM_ABS32NEG:
+// CHECK: 11004: dc 00 00 00
diff --git a/test/ELF/arm-fpic-got.s b/test/ELF/arm-fpic-got.s
new file mode 100644
index 000000000..4b6002d3c
--- /dev/null
+++ b/test/ELF/arm-fpic-got.s
@@ -0,0 +1,63 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+// RUN: llvm-readobj -s -symbols %t | FileCheck -check-prefix=SYMBOLS %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s
+
+// Test the R_ARM_GOT_PREL relocation
+ .syntax unified
+ .text
+ .globl _start
+ .align 2
+_start:
+ ldr r0, .LCPI0_0
+.LPC0_0:
+ ldr r0, [pc, r0]
+ ldr r0, [r0]
+ bx lr
+.LCPI0_0:
+.Ltmp0:
+ // Generate R_ARM_GOT_PREL
+ .long val(GOT_PREL)-((.LPC0_0+8)-.Ltmp0)
+
+ .data
+ .type val,%object
+ .globl val
+ .align 2
+val:
+ .long 10
+ .size val, 4
+
+// CHECK: Section {
+// CHECK: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 4
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize:
+
+// SYMBOLS: Name: val
+// SYMBOLS-NEXT: Value: 0x13000
+// SYMBOLS-NEXT: Size: 4
+// SYMBOLS-NEXT: Binding: Global
+// SYMBOLS-NEXT: Type: Object
+// SYMBOLS-NEXT: Other:
+// SYMBOLS-NEXT: Section: .data
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT: 11000: 08 00 9f e5 ldr r0, [pc, #8]
+// CODE-NEXT: 11004: 00 00 9f e7 ldr r0, [pc, r0]
+// CODE-NEXT: 11008: 00 00 90 e5 ldr r0, [r0]
+// CODE-NEXT: 1100c: 1e ff 2f e1 bx lr
+// CODE: $d.1:
+// 0x11004 + 0x0ff4 + 8 = 0x12000 = .got
+// CODE-NEXT: 11010: f4 0f 00 00
diff --git a/test/ELF/arm-gnu-ifunc-nosym.s b/test/ELF/arm-gnu-ifunc-nosym.s
new file mode 100644
index 000000000..fa79aef7c
--- /dev/null
+++ b/test/ELF/arm-gnu-ifunc-nosym.s
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-readobj -symbols %tout | FileCheck %s
+// REQUIRES: arm
+
+// Check that no __rel_iplt_end/__rel_iplt_start
+// appear in symtab if there are no references to them.
+// CHECK: Symbols [
+// CHECK-NOT: __rel_iplt_end
+// CHECK-NOT: __rel_iplt_start
+// CHECK: ]
+ .syntax unified
+ .text
+ .type foo STT_GNU_IFUNC
+ .globl foo
+foo:
+ bx lr
+
+ .type bar STT_GNU_IFUNC
+ .globl bar
+bar:
+ bx lr
+
+ .globl _start
+_start:
+ bl foo
+ bl bar
diff --git a/test/ELF/arm-gnu-ifunc.s b/test/ELF/arm-gnu-ifunc.s
new file mode 100644
index 000000000..c1e8a7183
--- /dev/null
+++ b/test/ELF/arm-gnu-ifunc.s
@@ -0,0 +1,131 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld -static %t.o -o %tout
+// RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .text
+ .type foo STT_GNU_IFUNC
+ .globl foo
+foo:
+ bx lr
+
+ .type bar STT_GNU_IFUNC
+ .globl bar
+bar:
+ bx lr
+
+ .globl _start
+_start:
+ bl foo
+ bl bar
+ movw r0,:lower16:__rel_iplt_start
+ movt r0,:upper16:__rel_iplt_start
+ movw r0,:lower16:__rel_iplt_end
+ movt r0,:upper16:__rel_iplt_end
+
+// CHECK: Sections [
+// CHECK: Section {
+// CHECK: Index: 1
+// CHECK-NEXT: Name: .rel.plt
+// CHECK-NEXT: Type: SHT_REL
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[REL:.*]]
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 8
+// CHECK-NEXT: }
+// CHECK: Relocations [
+// CHECK-NEXT: Section (1) .rel.plt {
+// CHECK-NEXT: 0x1200C R_ARM_IRELATIVE
+// CHECK-NEXT: 0x12010 R_ARM_IRELATIVE
+// CHECK-NEXT: }
+// CHECK-NEXT:]
+// CHECK: Symbols [
+// CHECK: Symbol {
+// CHECK: Name: __rel_iplt_end
+// CHECK-NEXT: Value: 0x100E4
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
+// CHECK-NEXT: Section: .rel.plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: __rel_iplt_start
+// CHECK-NEXT: Value: 0x100D4
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
+// CHECK-NEXT: Section: .rel.plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: _start (6)
+// CHECK-NEXT: Value: 0x11008
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other:
+// CHECK-NEXT: Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: bar
+// CHECK-NEXT: Value: 0x11004
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: GNU_IFunc
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: foo
+// CHECK-NEXT: Value: 0x11000
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: GNU_IFunc
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .text
+// CHECK-NEXT: }
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT: 11000: 1e ff 2f e1 bx lr
+// DISASM: bar:
+// DISASM-NEXT: 11004: 1e ff 2f e1 bx lr
+// DISASM: _start:
+// DISASM-NEXT: 11008: 09 00 00 eb bl #36
+// DISASM-NEXT: 1100c: 0c 00 00 eb bl #48
+// DISASM-NEXT: 11010: d4 00 00 e3 movw r0, #212
+// DISASM-NEXT: 11014: 01 00 40 e3 movt r0, #1
+// r0 = 212 + 1 * 65536 = 100D4 = __rel_iplt_start
+// DISASM-NEXT: 11018: e4 00 00 e3 movw r0, #228
+// DISASM-NEXT: 1101c: 01 00 40 e3 movt r0, #1
+// r1 = 228 + 1 * 65536 = 100E4 = __rel_iplt_end
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT: 11020: 04 e0 2d e5 str lr, [sp, #-4]!
+// DISASM-NEXT: 11024: 04 e0 9f e5 ldr lr, [pc, #4]
+// DISASM-NEXT: 11028: 0e e0 8f e0 add lr, pc, lr
+// DISASM-NEXT: 1102c: 08 f0 be e5 ldr pc, [lr, #8]!
+// 0x0fd0 + 0x11028 + 0x8 = 0x12000
+// DISASM-NEXT: 11030: d0 0f 00 00
+// DISASM-NEXT: 11034: 04 c0 9f e5 ldr r12, [pc, #4]
+// DISASM-NEXT: 11038: 0f c0 8c e0 add r12, r12, pc
+// DISASM-NEXT: 1103c: 00 f0 9c e5 ldr pc, [r12]
+// 0x0fcc + 0x11038 + 0x8 = 0x1200C
+// DISASM-NEXT: 11040: cc 0f 00 00
+// DISASM-NEXT: 11044: 04 c0 9f e5 ldr r12, [pc, #4]
+// DISASM-NEXT: 11048: 0f c0 8c e0 add r12, r12, pc
+// DISASM-NEXT: 1104c: 00 f0 9c e5 ldr pc, [r12]
+// 0x0fc0 + 0x11048 + 0x8 = 0x12010
+// DISASM-NEXT: 11050: c0 0f 00 00
diff --git a/test/ELF/arm-got-relative.s b/test/ELF/arm-got-relative.s
new file mode 100644
index 000000000..22ccb16a2
--- /dev/null
+++ b/test/ELF/arm-got-relative.s
@@ -0,0 +1,53 @@
+// REQUIRES: arm
+// RUN: llvm-mc -position-independent -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -shared -o %t
+// RUN: llvm-readobj -s -symbols -dyn-relocations %t | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s
+ .syntax unified
+ .text
+ .globl _start
+ .align 2
+_start:
+ .type _start, %function
+ ldr r3, .LGOT
+ ldr r2, .LGOT+4
+.LPIC:
+ add r0, pc, r3
+ bx lr
+ .align 2
+.LGOT:
+ // gas implicitly uses (GOT_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC
+ // llvm-mc needs the (GOT_PREL) suffix or it generates R_ARM_REL32
+ .word _GLOBAL_OFFSET_TABLE_(GOT_PREL) - (.LPIC+8)
+ .word function(GOT)
+
+ .globl function
+ .align 2
+function:
+ .type function, %function
+ bx lr
+
+// CHECK: Dynamic Relocations {
+// CHECK-NEXT: 0x204C R_ARM_GLOB_DAT function 0x0
+
+// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (16)
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
+// CHECK-NEXT: Section: Absolute
+
+// CODE: Disassembly of section .text:
+// CODE-NEXT: _start:
+// CODE-NEXT: 1000: 08 30 9f e5 ldr r3, [pc, #8]
+// CODE-NEXT: 1004: 08 20 9f e5 ldr r2, [pc, #8]
+// CODE-NEXT: 1008: 03 00 8f e0 add r0, pc, r3
+// CODE-NEXT: 100c: 1e ff 2f e1 bx lr
+// CODE:$d.1:
+// (_GLOBAL_OFFSET_TABLE_ = 0x2048) - (0x1008 + 8) 0x1038
+// CODE-NEXT: 1010: 38 10 00 00
+// (Got(function) - GotBase = 0x4
+// CODE-NEXT: 1014: 04 00 00 00
diff --git a/test/ELF/arm-gotoff.s b/test/ELF/arm-gotoff.s
new file mode 100644
index 000000000..5169f84e6
--- /dev/null
+++ b/test/ELF/arm-gotoff.s
@@ -0,0 +1,74 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabi %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -s -r -t %t | FileCheck %s
+// RUN: llvm-objdump -triple=armv7a-linux-gnueabi -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: arm
+
+// Test the R_ARM_GOTOFF32 relocation
+
+// CHECK: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset: 0x2000
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+
+// CHECK: Name: .bss
+// CHECK-NEXT: Type: SHT_NOBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 20
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment: 1
+
+// CHECK-NEXT: EntrySize: 0
+
+// CHECK: Symbol {
+// CHECK: Name: bar
+// CHECK-NEXT: Value: 0x12000
+// CHECK-NEXT: Size: 10
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: obj
+// CHECK-NEXT: Value: 0x1200A
+// CHECK-NEXT: Size: 10
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .bss
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT :_start:
+// DISASM-NEXT 11000: 1e ff 2f e1 bx lr
+// Offset 0 from .got = bar
+// DISASM 11004: 00 00 00 00
+// Offset 10 from .got = obj
+// DISASM-NEXT 11008: 0a 00 00 00
+// Offset 15 from .got = obj +5
+// DISASM-NEXT 1100c: 0f 00 00 00
+ .syntax unified
+ .globl _start
+_start:
+ bx lr
+ .word bar(GOTOFF)
+ .word obj(GOTOFF)
+ .word obj(GOTOFF)+5
+ .type bar, %object
+ .comm bar, 10
+ .type obj, %object
+ .comm obj, 10
diff --git a/test/ELF/arm-mov-relocs.s b/test/ELF/arm-mov-relocs.s
new file mode 100644
index 000000000..15a037893
--- /dev/null
+++ b/test/ELF/arm-mov-relocs.s
@@ -0,0 +1,53 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-unknown-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -d %t2 -triple=armv7a-unknown-linux-gnueabi | FileCheck %s
+// REQUIRES: arm
+
+// Test the R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocations
+ .syntax unified
+ .globl _start
+_start:
+ .section .R_ARM_MOVW_ABS_NC, "ax",%progbits
+ movw r0, :lower16:label
+ movw r1, :lower16:label1
+ movw r2, :lower16:label2 + 4
+ movw r3, :lower16:label3
+ movw r4, :lower16:label3 + 4
+// CHECK: Disassembly of section .R_ARM_MOVW_ABS_NC
+// CHECK: movw r0, #0
+// CHECK: movw r1, #4
+// CHECK: movw r2, #12
+// CHECK: movw r3, #65532
+// CHECK: movw r4, #0
+ .section .R_ARM_MOVT_ABS, "ax",%progbits
+ movt r0, :upper16:label
+ movt r1, :upper16:label1
+// FIXME: We shouldn't need to multiply by 65536.
+// arguably llvm-mc incorrectly assembles addends for
+// SHT_REL relocated movt instructions. When there is a relocation
+// the interpretation of the addend for SHT_REL is not shifted
+ movt r2, :upper16:label2 + (4 * 65536)
+ movt r3, :upper16:label3
+// FIXME: We shouldn't need to multiply by 65536 see comment above.
+ movt r4, :upper16:label3 + (4 * 65536)
+// CHECK: Disassembly of section .R_ARM_MOVT_ABS
+// CHECK: movt r0, #2
+// CHECK: movt r1, #2
+// CHECK: movt r2, #2
+// CHECK: movt r3, #2
+// CHECK: movt r4, #3
+
+ .section .destination, "aw",%progbits
+ .balign 65536
+label:
+ .word 0
+label1:
+ .word 1
+label2:
+ .word 2
+// Test label3 is immediately below 2^16 alignment boundary
+ .space 65536 - 16
+label3:
+ .word 3
+// label3 + 4 is on a 2^16 alignment boundary
+ .word 4
diff --git a/test/ELF/arm-plt-reloc.s b/test/ELF/arm-plt-reloc.s
new file mode 100644
index 000000000..0616aa796
--- /dev/null
+++ b/test/ELF/arm-plt-reloc.s
@@ -0,0 +1,90 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2
+// RUN: ld.lld %t1 %t2 -o %t
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t | FileCheck %s
+// RUN: ld.lld -shared %t1 %t2 -o %t3
+// RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSO %s
+// RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s
+// REQUIRES: arm
+//
+// Test PLT entry generation
+ .syntax unified
+ .text
+ .align 2
+ .globl _start
+ .type _start,%function
+_start:
+ b func1
+ bl func2
+ beq func3
+
+// Executable, expect no PLT
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: func1:
+// CHECK-NEXT: 11000: 1e ff 2f e1 bx lr
+// CHECK: func2:
+// CHECK-NEXT: 11004: 1e ff 2f e1 bx lr
+// CHECK: func3:
+// CHECK-NEXT: 11008: 1e ff 2f e1 bx lr
+// CHECK: _start:
+// CHECK-NEXT: 1100c: fb ff ff ea b #-20 <func1>
+// CHECK-NEXT: 11010: fb ff ff eb bl #-20 <func2>
+// CHECK-NEXT: 11014: fb ff ff 0a beq #-20 <func3>
+
+// Expect PLT entries as symbols can be preempted
+// DSO: Disassembly of section .text:
+// DSO-NEXT: func1:
+// DSO-NEXT: 1000: 1e ff 2f e1 bx lr
+// DSO: func2:
+// DSO-NEXT: 1004: 1e ff 2f e1 bx lr
+// DSO: func3:
+// DSO-NEXT: 1008: 1e ff 2f e1 bx lr
+// DSO: _start:
+// S(0x1034) - P(0x100c) + A(-8) = 0x20 = 32
+// DSO-NEXT: 100c: 08 00 00 ea b #32
+// S(0x1044) - P(0x1010) + A(-8) = 0x2c = 44
+// DSO-NEXT: 1010: 0b 00 00 eb bl #44
+// S(0x1054) - P(0x1014) + A(-8) = 0x38 = 56
+// DSO-NEXT: 1014: 0e 00 00 0a beq #56
+// DSO: Disassembly of section .plt:
+// DSO-NEXT:.plt:
+// DSO-NEXT: 1020: 04 e0 2d e5 str lr, [sp, #-4]!
+// DSO-NEXT: 1024: 04 e0 9f e5 ldr lr, [pc, #4]
+// DSO-NEXT: 1028: 0e e0 8f e0 add lr, pc, lr
+// DSO-NEXT: 102c: 08 f0 be e5 ldr pc, [lr, #8]!
+// 0x1028 + 8 + 1fd0 = 0x3000
+// DSO-NEXT: 1030: d0 1f 00 00
+// DSO-NEXT: 1034: 04 c0 9f e5 ldr r12, [pc, #4]
+// DSO-NEXT: 1038: 0f c0 8c e0 add r12, r12, pc
+// DSO-NEXT: 103c: 00 f0 9c e5 ldr pc, [r12]
+// 0x1038 + 8 + 1fcc = 0x300c
+// DSO-NEXT: 1040: cc 1f 00 00
+// DSO-NEXT: 1044: 04 c0 9f e5 ldr r12, [pc, #4]
+// DSO-NEXT: 1048: 0f c0 8c e0 add r12, r12, pc
+// DSO-NEXT: 104c: 00 f0 9c e5 ldr pc, [r12]
+// 0x1048 + 8 + 1fc0 = 0x3010
+// DSO-NEXT: 1050: c0 1f 00 00
+// DSO-NEXT: 1054: 04 c0 9f e5 ldr r12, [pc, #4]
+// DSO-NEXT: 1058: 0f c0 8c e0 add r12, r12, pc
+// DSO-NEXT: 105c: 00 f0 9c e5 ldr pc, [r12]
+// 0x1058 + 8 + 1fb4 = 0x3014
+// DSO-NEXT: 1060: b4 1f 00 00
+
+// DSOREL: Name: .got.plt
+// DSOREL-NEXT: Type: SHT_PROGBITS
+// DSOREL-NEXT: Flags [
+// DSOREL-NEXT: SHF_ALLOC
+// DSOREL-NEXT: SHF_WRITE
+// DSOREL-NEXT: ]
+// DSOREL-NEXT: Address: 0x3000
+// DSOREL-NEXT: Offset:
+// DSOREL-NEXT: Size: 24
+// DSOREL-NEXT: Link:
+// DSOREL-NEXT: Info:
+// DSOREL-NEXT: AddressAlignment: 4
+// DSOREL-NEXT: EntrySize:
+// DSOREL: Relocations [
+// DSOREL-NEXT: Section (4) .rel.plt {
+// DSOREL-NEXT: 0x300C R_ARM_JUMP_SLOT func1 0x0
+// DSOREL-NEXT: 0x3010 R_ARM_JUMP_SLOT func2 0x0
+// DSOREL-NEXT: 0x3014 R_ARM_JUMP_SLOT func3 0x0