Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -71,6 +71,8 @@ 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 Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -244,6 +244,11 @@ } 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::Discarded; + break; default: Sections[I] = createInputSection(Sec); } Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -170,6 +170,19 @@ 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 MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); @@ -196,6 +209,8 @@ 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,163 @@ 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_PC24: + case R_ARM_PLT32: + case R_ARM_CALL: + case R_ARM_JUMP24: + 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::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::GotPlt->getVA(); + uint64_t L1 = Out::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: + return SignExtend64<32>(read32le(Buf)); + break; + case R_ARM_PREL31: + return SignExtend64<31>(read32le(Buf)); + break; + case R_ARM_REL32: + return SignExtend64<32>(read32le(Buf)); + 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 MipsTargetInfo::MipsTargetInfo() { GotPltHeaderEntriesNum = 2; PageSize = 65536; Index: test/ELF/Inputs/arm-plt-reloc.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/Inputs/far-arm-abs.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/Inputs/relocation-copy-arm.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-abs32-dyn.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-attributes-remove.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-branch-error.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-branch.s =================================================================== --- /dev/null +++ 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 +// S(callee_low) = 0xb4 P = 0x10004 A = -8 = -0xff58 = -65368 +// CHECK-NEXT: 10004: 2a c0 ff ea b #-65368 +// S(callee_low) = 0xb4 P = 0x10008 A = -8 = -0xff5c -65372 +// CHECK-NEXT: 10008: 29 c0 ff 0a beq #-65372 +// S(callee_high) = 0x10028 P = 0x1000c A = -8 = 0x14 = 20 +// CHECK-NEXT: 1000c: 05 00 00 eb bl #20 +// S(callee_high) = 0x10028 P = 0x10010 A = -8 = 0x10 = 16 +// CHECK-NEXT: 10010: 04 00 00 ea b #16 +// S(callee_high) = 0x10028 P = 0x10014 A = -8 = 0x0c =12 +// CHECK-NEXT: 10014: 03 00 00 1a bne #12 +// 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 Index: test/ELF/arm-copy.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-data-prel.s =================================================================== --- /dev/null +++ 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: ) Index: test/ELF/arm-data-relocs.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-fpic-got.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-gnu-ifunc-nosym.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-gnu-ifunc.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-got-relative.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-gotoff.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-mov-relocs.s =================================================================== --- /dev/null +++ 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 Index: test/ELF/arm-plt-reloc.s =================================================================== --- /dev/null +++ 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 +// CHECK-NEXT: 11010: fb ff ff eb bl #-20 +// CHECK-NEXT: 11014: fb ff ff 0a beq #-20 + +// 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