| commit c2ccf4ccba295b1300018e65c658ff305992aa29 |
| Author: Peter Collingbourne <peter@pcc.me.uk> |
| Date: Thu Jul 18 17:12:50 2019 +0000 |
| |
| ELF: Add support for remaining R_AARCH64_MOVW* relocations. |
| |
| Differential Revision: https://reviews.llvm.org/D64685 |
| |
| llvm-svn: 366466 |
| |
| diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp |
| index 4d4789702f0..f864c36880e 100644 |
| --- a/lld/ELF/Arch/AArch64.cpp |
| +++ b/lld/ELF/Arch/AArch64.cpp |
| @@ -104,5 +104,12 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, |
| case R_AARCH64_PREL64: |
| case R_AARCH64_ADR_PREL_LO21: |
| case R_AARCH64_LD_PREL_LO19: |
| + case R_AARCH64_MOVW_PREL_G0: |
| + case R_AARCH64_MOVW_PREL_G0_NC: |
| + case R_AARCH64_MOVW_PREL_G1: |
| + case R_AARCH64_MOVW_PREL_G1_NC: |
| + case R_AARCH64_MOVW_PREL_G2: |
| + case R_AARCH64_MOVW_PREL_G2_NC: |
| + case R_AARCH64_MOVW_PREL_G3: |
| return R_PC; |
| case R_AARCH64_ADR_PREL_PG_HI21: |
| @@ -247,6 +254,26 @@ static void or32AArch64Imm(uint8_t *l, uint64_t imm) { |
| or32le(l, (imm & 0xFFF) << 10); |
| } |
| |
| +// Update the immediate field in an AArch64 movk, movn or movz instruction |
| +// for a signed relocation, and update the opcode of a movn or movz instruction |
| +// to match the sign of the operand. |
| +static void writeSMovWImm(uint8_t *loc, uint32_t imm) { |
| + uint32_t inst = read32le(loc); |
| + // Opcode field is bits 30, 29, with 10 = movz, 00 = movn and 11 = movk. |
| + if (!(inst & (1 << 29))) { |
| + // movn or movz. |
| + if (imm & 0x10000) { |
| + // Change opcode to movn, which takes an inverted operand. |
| + imm ^= 0xFFFF; |
| + inst &= ~(1 << 30); |
| + } else { |
| + // Change opcode to movz. |
| + inst |= 1 << 30; |
| + } |
| + } |
| + write32le(loc, inst | ((imm & 0xFFFF) << 5)); |
| +} |
| + |
| void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { |
| switch (type) { |
| case R_AARCH64_ABS16: |
| @@ -326,18 +353,51 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { |
| checkAlignment(loc, val, 16, type); |
| or32AArch64Imm(loc, getBits(val, 4, 11)); |
| break; |
| + case R_AARCH64_MOVW_UABS_G0: |
| + checkUInt(loc, val, 16, type); |
| + LLVM_FALLTHROUGH; |
| case R_AARCH64_MOVW_UABS_G0_NC: |
| or32le(loc, (val & 0xFFFF) << 5); |
| break; |
| + case R_AARCH64_MOVW_UABS_G1: |
| + checkUInt(loc, val, 32, type); |
| + LLVM_FALLTHROUGH; |
| case R_AARCH64_MOVW_UABS_G1_NC: |
| or32le(loc, (val & 0xFFFF0000) >> 11); |
| break; |
| + case R_AARCH64_MOVW_UABS_G2: |
| + checkUInt(loc, val, 48, type); |
| + LLVM_FALLTHROUGH; |
| case R_AARCH64_MOVW_UABS_G2_NC: |
| or32le(loc, (val & 0xFFFF00000000) >> 27); |
| break; |
| case R_AARCH64_MOVW_UABS_G3: |
| or32le(loc, (val & 0xFFFF000000000000) >> 43); |
| break; |
| + case R_AARCH64_MOVW_PREL_G0: |
| + case R_AARCH64_MOVW_SABS_G0: |
| + checkInt(loc, val, 17, type); |
| + LLVM_FALLTHROUGH; |
| + case R_AARCH64_MOVW_PREL_G0_NC: |
| + writeSMovWImm(loc, val); |
| + break; |
| + case R_AARCH64_MOVW_PREL_G1: |
| + case R_AARCH64_MOVW_SABS_G1: |
| + checkInt(loc, val, 33, type); |
| + LLVM_FALLTHROUGH; |
| + case R_AARCH64_MOVW_PREL_G1_NC: |
| + writeSMovWImm(loc, val >> 16); |
| + break; |
| + case R_AARCH64_MOVW_PREL_G2: |
| + case R_AARCH64_MOVW_SABS_G2: |
| + checkInt(loc, val, 49, type); |
| + LLVM_FALLTHROUGH; |
| + case R_AARCH64_MOVW_PREL_G2_NC: |
| + writeSMovWImm(loc, val >> 32); |
| + break; |
| + case R_AARCH64_MOVW_PREL_G3: |
| + writeSMovWImm(loc, val >> 48); |
| + break; |
| case R_AARCH64_TSTBR14: |
| checkInt(loc, val, 16, type); |
| or32le(loc, (val & 0xFFFC) << 3); |
| diff --git a/lld/test/ELF/aarch64-movw-error.s b/lld/test/ELF/aarch64-movw-error.s |
| new file mode 100644 |
| index 00000000000..9974ed43469 |
| --- /dev/null |
| +++ b/lld/test/ELF/aarch64-movw-error.s |
| @@ -0,0 +1,36 @@ |
| +# REQUIRES: aarch64 |
| +# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t |
| +# RUN: echo '.globl zero; zero = 0' | llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd -o %t2.o |
| +# RUN: not ld.lld %t %t2.o -o /dev/null 2>&1 | FileCheck %s |
| + |
| +# CHECK: relocation R_AARCH64_MOVW_UABS_G0 out of range: 65536 is not in [0, 65535] |
| +movn x0, #:abs_g0:zero+0x10000 |
| +# CHECK: relocation R_AARCH64_MOVW_UABS_G1 out of range: 4294967296 is not in [0, 4294967295] |
| +movn x0, #:abs_g1:zero+0x100000000 |
| +# CHECK: relocation R_AARCH64_MOVW_UABS_G2 out of range: 281474976710656 is not in [0, 281474976710655] |
| +movn x0, #:abs_g2:zero+0x1000000000000 |
| +# CHECK: relocation R_AARCH64_MOVW_SABS_G0 out of range: 65536 is not in [-65536, 65535] |
| +movn x0, #:abs_g0_s:zero+0x10000 |
| +# CHECK: relocation R_AARCH64_MOVW_SABS_G1 out of range: 4294967296 is not in [-4294967296, 4294967295] |
| +movn x0, #:abs_g1_s:zero+0x100000000 |
| +# CHECK: relocation R_AARCH64_MOVW_SABS_G2 out of range: 281474976710656 is not in [-281474976710656, 281474976710655] |
| +movn x0, #:abs_g2_s:zero+0x1000000000000 |
| +# CHECK: relocation R_AARCH64_MOVW_SABS_G0 out of range: -65537 is not in [-65536, 65535] |
| +movn x0, #:abs_g0_s:zero-0x10001 |
| +# CHECK: relocation R_AARCH64_MOVW_SABS_G1 out of range: -4295032832 is not in [-4294967296, 4294967295] |
| +movn x0, #:abs_g1_s:zero-0x100010000 |
| +# CHECK: relocation R_AARCH64_MOVW_SABS_G2 out of range: -281479271677952 is not in [-281474976710656, 281474976710655] |
| +movn x0, #:abs_g2_s:zero-0x1000100000000 |
| + |
| +# CHECK: relocation R_AARCH64_MOVW_PREL_G0 out of range: 65536 is not in [-65536, 65535] |
| +movn x0, #:prel_g0:.+0x10000 |
| +# CHECK: relocation R_AARCH64_MOVW_PREL_G1 out of range: 4294967296 is not in [-4294967296, 4294967295] |
| +movn x0, #:prel_g1:.+0x100000000 |
| +# CHECK: relocation R_AARCH64_MOVW_PREL_G2 out of range: 281474976710656 is not in [-281474976710656, 281474976710655] |
| +movn x0, #:prel_g2:.+0x1000000000000 |
| +# CHECK: relocation R_AARCH64_MOVW_PREL_G0 out of range: -65537 is not in [-65536, 65535] |
| +movn x0, #:prel_g0:.-0x10001 |
| +# CHECK: relocation R_AARCH64_MOVW_PREL_G1 out of range: -4295032832 is not in [-4294967296, 4294967295] |
| +movn x0, #:prel_g1:.-0x100010000 |
| +# CHECK: relocation R_AARCH64_MOVW_PREL_G2 out of range: -281479271677952 is not in [-281474976710656, 281474976710655] |
| +movn x0, #:prel_g2:.-0x1000100000000 |
| diff --git a/lld/test/ELF/aarch64-relocs.s b/lld/test/ELF/aarch64-relocs.s |
| index efa9b732933..a890d253896 100644 |
| --- a/lld/test/ELF/aarch64-relocs.s |
| +++ b/lld/test/ELF/aarch64-relocs.s |
| @@ -169,8 +169,11 @@ foo16: |
| |
| .section .R_AARCH64_MOVW_UABS,"ax",@progbits |
| movz1: |
| + movk x12, #:abs_g0:zero+0xC |
| movk x12, #:abs_g0_nc:zero+0xF000E000D000C |
| + movk x13, #:abs_g1:zero+0xD000C |
| movk x13, #:abs_g1_nc:zero+0xF000E000D000C |
| + movk x14, #:abs_g2:zero+0xE000D000C |
| movk x14, #:abs_g2_nc:zero+0xF000E000D000C |
| movz x15, #:abs_g3:zero+0xF000E000D000C |
| movk x16, #:abs_g3:zero+0xF000E000D000C |
| @@ -180,7 +183,75 @@ movz1: |
| # CHECK-EMPTY: |
| # CHECK-NEXT: movz1: |
| # CHECK-NEXT: 8c 01 80 f2 movk x12, #12 |
| +# CHECK-NEXT: 8c 01 80 f2 movk x12, #12 |
| +# CHECK-NEXT: ad 01 a0 f2 movk x13, #13, lsl #16 |
| # CHECK-NEXT: ad 01 a0 f2 movk x13, #13, lsl #16 |
| # CHECK-NEXT: ce 01 c0 f2 movk x14, #14, lsl #32 |
| +# CHECK-NEXT: ce 01 c0 f2 movk x14, #14, lsl #32 |
| # CHECK-NEXT: ef 01 e0 d2 mov x15, #4222124650659840 |
| # CHECK-NEXT: f0 01 e0 f2 movk x16, #15, lsl #48 |
| + |
| +.section .R_AARCH64_MOVW_SABS,"ax",@progbits |
| + movz x1, #:abs_g0_s:zero+1 |
| + movz x1, #:abs_g0_s:zero-1 |
| + movz x2, #:abs_g1_s:zero+0x20000 |
| + movz x2, #:abs_g1_s:zero-0x20000 |
| + movz x3, #:abs_g2_s:zero+0x300000000 |
| + movz x3, #:abs_g2_s:zero-0x300000000 |
| + |
| +# CHECK: Disassembly of section .R_AARCH64_MOVW_SABS: |
| +# CHECK-EMPTY: |
| +# CHECK-NEXT: : |
| +# CHECK-NEXT: 21 00 80 d2 mov x1, #1 |
| +# CHECK-NEXT: 01 00 80 92 mov x1, #-1 |
| +# CHECK-NEXT: 42 00 a0 d2 mov x2, #131072 |
| +## -65537 = 0xfffffffffffeffff |
| +# CHECK-NEXT: 22 00 a0 92 mov x2, #-65537 |
| +## 12884901888 = 0x300000000 |
| +# CHECK-NEXT: 63 00 c0 d2 mov x3, #12884901888 |
| +## -8589934593 = #0xfffffffdffffffff |
| +# CHECK-NEXT: 43 00 c0 92 mov x3, #-8589934593 |
| + |
| +.section .R_AARCH64_MOVW_PREL,"ax",@progbits |
| + movz x1, #:prel_g0:.+1 |
| + movz x1, #:prel_g0_nc:.-1 |
| + movk x1, #:prel_g0:.+1 |
| + movk x1, #:prel_g0_nc:.-1 |
| + movz x2, #:prel_g1:.+0x20000 |
| + movz x2, #:prel_g1_nc:.-0x20000 |
| + movk x2, #:prel_g1:.+0x20000 |
| + movk x2, #:prel_g1_nc:.-0x20000 |
| + movz x3, #:prel_g2:.+0x300000000 |
| + movz x3, #:prel_g2_nc:.-0x300000000 |
| + movk x3, #:prel_g2:.+0x300000000 |
| + movk x3, #:prel_g2_nc:.-0x300000000 |
| + movz x3, #:prel_g2:.+0x300000000 |
| + movz x4, #:prel_g3:.+0x4000000000000 |
| + movz x4, #:prel_g3:.-0x4000000000000 |
| + movk x4, #:prel_g3:.+0x4000000000000 |
| + movk x4, #:prel_g3:.-0x4000000000000 |
| + |
| +# CHECK: Disassembly of section .R_AARCH64_MOVW_PREL: |
| +# CHECK-EMPTY: |
| +# CHECK-NEXT: : |
| +# CHECK-NEXT: 21009c: 21 00 80 d2 mov x1, #1 |
| +# CHECK-NEXT: 2100a0: 01 00 80 92 mov x1, #-1 |
| +# CHECK-NEXT: 2100a4: 21 00 80 f2 movk x1, #1 |
| +# CHECK-NEXT: 2100a8: e1 ff 9f f2 movk x1, #65535 |
| +# CHECK-NEXT: 2100ac: 42 00 a0 d2 mov x2, #131072 |
| +## -65537 = 0xfffffffffffeffff |
| +# CHECK-NEXT: 2100b0: 22 00 a0 92 mov x2, #-65537 |
| +# CHECK-NEXT: 2100b4: 42 00 a0 f2 movk x2, #2, lsl #16 |
| +# CHECK-NEXT: 2100b8: c2 ff bf f2 movk x2, #65534, lsl #16 |
| +## 12884901888 = 0x300000000 |
| +# CHECK-NEXT: 2100bc: 63 00 c0 d2 mov x3, #12884901888 |
| +## -8589934593 = #0xfffffffdffffffff |
| +# CHECK-NEXT: 2100c0: 43 00 c0 92 mov x3, #-8589934593 |
| +# CHECK-NEXT: 2100c4: 63 00 c0 f2 movk x3, #3, lsl #32 |
| +# CHECK-NEXT: 2100c8: a3 ff df f2 movk x3, #65533, lsl #32 |
| +# CHECK-NEXT: 2100cc: 63 00 c0 d2 mov x3, #12884901888 |
| +## 1125899906842624 = 0x4000000000000 |
| +# CHECK-NEXT: 2100d0: 84 00 e0 d2 mov x4, #1125899906842624 |
| +# CHECK-NEXT: 2100d4: 84 ff ff d2 mov x4, #-1125899906842624 |
| +# CHECK-NEXT: 2100d8: 84 00 e0 f2 movk x4, #4, lsl #48 |
| +# CHECK-NEXT: 2100dc: 84 ff ff f2 movk x4, #65532, lsl #48 |