[lld] 69e60c9 - [LLD][ELF][AVR] Implement the missing relocation types

Ayke van Laethem via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 12 09:20:48 PDT 2020


Author: Ayke van Laethem
Date: 2020-07-12T18:18:54+02:00
New Revision: 69e60c9dc76653c10c4e8f7af1743307532102eb

URL: https://github.com/llvm/llvm-project/commit/69e60c9dc76653c10c4e8f7af1743307532102eb
DIFF: https://github.com/llvm/llvm-project/commit/69e60c9dc76653c10c4e8f7af1743307532102eb.diff

LOG: [LLD][ELF][AVR] Implement the missing relocation types

Implements the missing relocation types for AVR target.
The results have been cross-checked with binutils.

Original patch by LemonBoy. Some changes by me.

Differential Revision: https://reviews.llvm.org/D78741

Added: 
    lld/test/ELF/avr-reloc.s

Modified: 
    lld/ELF/Arch/AVR.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/AVR.cpp b/lld/ELF/Arch/AVR.cpp
index 9b733837dd5d..4513a970b32d 100644
--- a/lld/ELF/Arch/AVR.cpp
+++ b/lld/ELF/Arch/AVR.cpp
@@ -54,11 +54,131 @@ AVR::AVR() { noneRel = R_AVR_NONE; }
 
 RelExpr AVR::getRelExpr(RelType type, const Symbol &s,
                         const uint8_t *loc) const {
-  return R_ABS;
+  switch (type) {
+  case R_AVR_7_PCREL:
+  case R_AVR_13_PCREL:
+    return R_PC;
+  default:
+    return R_ABS;
+  }
+}
+
+static void writeLDI(uint8_t *loc, uint64_t val) {
+  write16le(loc, (read16le(loc) & 0xf0f0) | (val & 0xf0) << 4 | (val & 0x0f));
 }
 
 void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
   switch (rel.type) {
+  case R_AVR_8:
+    checkUInt(loc, val, 8, rel);
+    *loc = val;
+    break;
+  case R_AVR_16:
+    // Note: this relocation is often used between code and data space, which
+    // are 0x800000 apart in the output ELF file. The bitmask cuts off the high
+    // bit.
+    write16le(loc, val & 0xffff);
+    break;
+  case R_AVR_16_PM:
+    checkAlignment(loc, val, 2, rel);
+    checkUInt(loc, val >> 1, 16, rel);
+    write16le(loc, val >> 1);
+    break;
+  case R_AVR_32:
+    checkUInt(loc, val, 32, rel);
+    write32le(loc, val);
+    break;
+
+  case R_AVR_LDI:
+    checkUInt(loc, val, 8, rel);
+    writeLDI(loc, val & 0xff);
+    break;
+
+  case R_AVR_LO8_LDI_NEG:
+    writeLDI(loc, -val & 0xff);
+    break;
+  case R_AVR_LO8_LDI:
+    writeLDI(loc, val & 0xff);
+    break;
+  case R_AVR_HI8_LDI_NEG:
+    writeLDI(loc, (-val >> 8) & 0xff);
+    break;
+  case R_AVR_HI8_LDI:
+    writeLDI(loc, (val >> 8) & 0xff);
+    break;
+  case R_AVR_HH8_LDI_NEG:
+    writeLDI(loc, (-val >> 16) & 0xff);
+    break;
+  case R_AVR_HH8_LDI:
+    writeLDI(loc, (val >> 16) & 0xff);
+    break;
+  case R_AVR_MS8_LDI_NEG:
+    writeLDI(loc, (-val >> 24) & 0xff);
+    break;
+  case R_AVR_MS8_LDI:
+    writeLDI(loc, (val >> 24) & 0xff);
+    break;
+
+  case R_AVR_LO8_LDI_PM:
+    checkAlignment(loc, val, 2, rel);
+    writeLDI(loc, (val >> 1) & 0xff);
+    break;
+  case R_AVR_HI8_LDI_PM:
+    checkAlignment(loc, val, 2, rel);
+    writeLDI(loc, (val >> 9) & 0xff);
+    break;
+  case R_AVR_HH8_LDI_PM:
+    checkAlignment(loc, val, 2, rel);
+    writeLDI(loc, (val >> 17) & 0xff);
+    break;
+
+  case R_AVR_LO8_LDI_PM_NEG:
+    checkAlignment(loc, val, 2, rel);
+    writeLDI(loc, (-val >> 1) & 0xff);
+    break;
+  case R_AVR_HI8_LDI_PM_NEG:
+    checkAlignment(loc, val, 2, rel);
+    writeLDI(loc, (-val >> 9) & 0xff);
+    break;
+  case R_AVR_HH8_LDI_PM_NEG:
+    checkAlignment(loc, val, 2, rel);
+    writeLDI(loc, (-val >> 17) & 0xff);
+    break;
+
+  case R_AVR_PORT5:
+    checkUInt(loc, val, 5, rel);
+    write16le(loc, (read16le(loc) & 0xff07) | (val << 3));
+    break;
+  case R_AVR_PORT6:
+    checkUInt(loc, val, 6, rel);
+    write16le(loc, (read16le(loc) & 0xf9f0) | (val & 0x30) << 5 | (val & 0x0f));
+    break;
+
+  // Since every jump destination is word aligned we gain an extra bit
+  case R_AVR_7_PCREL: {
+    checkInt(loc, val, 7, rel);
+    checkAlignment(loc, val, 2, rel);
+    const uint16_t target = (val - 2) >> 1;
+    write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3));
+    break;
+  }
+  case R_AVR_13_PCREL: {
+    checkAlignment(loc, val, 2, rel);
+    const uint16_t target = (val - 2) >> 1;
+    write16le(loc, (read16le(loc) & 0xf000) | (target & 0xfff));
+    break;
+  }
+
+  case R_AVR_6:
+    checkInt(loc, val, 6, rel);
+    write16le(loc, (read16le(loc) & 0xd3f8) | (val & 0x20) << 8 |
+                       (val & 0x18) << 7 | (val & 0x07));
+    break;
+  case R_AVR_6_ADIW:
+    checkInt(loc, val, 6, rel);
+    write16le(loc, (read16le(loc) & 0xff30) | (val & 0x30) << 2 | (val & 0x0F));
+    break;
+
   case R_AVR_CALL: {
     uint16_t hi = val >> 17;
     uint16_t lo = val >> 1;

diff  --git a/lld/test/ELF/avr-reloc.s b/lld/test/ELF/avr-reloc.s
new file mode 100644
index 000000000000..49f78044068b
--- /dev/null
+++ b/lld/test/ELF/avr-reloc.s
@@ -0,0 +1,84 @@
+; REQUIRES: avr
+; RUN: llvm-mc -filetype=obj -triple=avr -mcpu=atmega328p %s -o %t.o
+; RUN: ld.lld %t.o --defsym=a=0x12345678 --defsym=b=30 -o %t
+; RUN: llvm-objdump -d --print-imm-hex %t | FileCheck %s
+; RUN: llvm-objdump -s %t | FileCheck --check-prefix=HEX %s
+
+.section .LDI,"ax", at progbits
+; CHECK-LABEL: section .LDI:
+; CHECK:       ldi     r20, 0x78
+; CHECK-NEXT:  ldi     r20, 0x56
+; CHECK-NEXT:  ldi     r20, 0x34
+; CHECK-NEXT:  ldi     r20, 0x12
+; CHECK-NEXT:  ldi     r20, 0x3c
+; CHECK-NEXT:  ldi     r20, 0x2b
+; CHECK-NEXT:  ldi     r20, 0x1a
+; CHECK-NEXT:  ldi     r20, 0xff
+ldi r20, lo8(a)     ; R_AVR_LO8_LDI
+ldi r20, hi8(a)     ; R_AVR_HI8_LDI
+ldi r20, hh8(a)     ; R_AVR_HH8_LDI
+ldi r20, hhi8(a)    ; R_AVR_MS8_LDI
+
+ldi r20, pm_lo8(a)  ; R_AVR_LO8_LDI_PM
+ldi r20, pm_hi8(a)  ; R_AVR_HI8_LDI_PM
+ldi r20, pm_hh8(a)  ; R_AVR_HH8_LDI_PM
+
+ldi r20, b+225
+
+.section .LDI_NEG,"ax", at progbits
+; CHECK-LABEL: section .LDI_NEG:
+; CHECK:       ldi     r20, 0x88
+; CHECK-NEXT:  ldi     r20, 0xa9
+; CHECK-NEXT:  ldi     r20, 0xcb
+; CHECK-NEXT:  ldi     r20, 0xed
+; CHECK-NEXT:  ldi     r20, 0xc4
+; CHECK-NEXT:  ldi     r20, 0xd4
+; CHECK-NEXT:  ldi     r20, 0xe5
+ldi r20, lo8(-(a))     ; R_AVR_LO8_LDI_NEG
+ldi r20, hi8(-(a))     ; R_AVR_HI8_LDI_NEG
+ldi r20, hh8(-(a))     ; R_AVR_HH8_LDI_NEG
+ldi r20, hhi8(-(a))    ; R_AVR_MS8_LDI_NEG
+
+ldi r20, pm_lo8(-(a))  ; R_AVR_LO8_LDI_PM_NEG
+ldi r20, pm_hi8(-(a))  ; R_AVR_HI8_LDI_PM_NEG
+ldi r20, pm_hh8(-(a))  ; R_AVR_HH8_LDI_PM_NEG
+
+;; The disassembler is not yet able to decode those opcodes
+;; 9e 8e    std    Y+30, r9
+;; 9e 8c    ldd    r9, Y+30
+;; 4e 96    adiw   r24, 0x1e
+.section .SIX,"ax", at progbits
+; HEX-LABEL: section .SIX:
+; HEX-NEXT:  9e8e9e8c 4e96
+std Y+b, r9   ; R_AVR_6
+ldd r9, Y+b   ; R_AVR_6
+adiw r24, b   ; R_AVR_6_ADIW
+
+.section .PORT,"ax", at progbits
+; CHECK-LABEL: section .PORT:
+; CHECK:       in     r20, 0x1e
+; CHECK-NEXT:  sbic   0x1e, 0x1
+in    r20, b  ; R_AVR_PORT6
+sbic  b, 1    ; R_AVR_PORT5
+
+;; The disassembler is not yet able to decode those opcodes
+;; 0f c0    rjmp   .+30
+;; ee cf    rjmp   .-36
+;; 69 f0    breq   .+26
+;; 61 f3    breq   .-40
+.section .PCREL,"ax", at progbits
+; HEX-LABEL: section .PCREL:
+; HEX-NEXT:  0fc0eecf 69f061f3
+foo:
+rjmp foo + 32  ; R_AVR_13_PCREL
+rjmp foo - 32  ; R_AVR_13_PCREL
+breq foo + 32  ; R_AVR_7_PCREL
+breq foo - 32  ; R_AVR_7_PCREL
+
+.section .DATA,"ax", at progbits
+; HEX-LABEL: section .DATA:
+; HEX-NEXT:  {{.*}} 1e1e000f 00785634 12
+.byte b        ; R_AVR_8
+.short b       ; R_AVR_16
+.short gs(b)   ; R_AVR_16_PM
+.long a        ; R_AVR_32


        


More information about the llvm-commits mailing list