Index: ELF/Arch/AVR.cpp =================================================================== --- ELF/Arch/AVR.cpp +++ ELF/Arch/AVR.cpp @@ -35,12 +35,17 @@ using namespace llvm; using namespace llvm::object; +using namespace llvm::support; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { +uint16_t caculateForLDI(uint16_t X, uint16_t SRel) { + return (X & 0xf0f0) | (SRel & 0xf) | ((SRel << 4) & 0xf00); +} + class AVR final : public TargetInfo { public: RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const InputFile &File, @@ -52,7 +57,32 @@ RelExpr AVR::getRelExpr(uint32_t Type, const SymbolBody &S, const InputFile &File, const uint8_t *Loc) const { switch (Type) { + case R_AVR_7_PCREL: + case R_AVR_13_PCREL: + return R_PC; + case R_AVR_LO8_LDI: + case R_AVR_LDI: + case R_AVR_6: + case R_AVR_6_ADIW: + case R_AVR_HI8_LDI: + case R_AVR_HH8_LDI: + case R_AVR_MS8_LDI: + case R_AVR_LO8_LDI_NEG: + case R_AVR_HI8_LDI_NEG: + case R_AVR_HH8_LDI_NEG: + case R_AVR_MS8_LDI_NEG: + case R_AVR_LO8_LDI_GS: + case R_AVR_LO8_LDI_PM: + case R_AVR_HH8_LDI_PM: + case R_AVR_LO8_LDI_PM_NEG: + case R_AVR_HI8_LDI_PM_NEG: + case R_AVR_HH8_LDI_PM_NEG: case R_AVR_CALL: + case R_AVR_16: + case R_AVR_16_PM: + case R_AVR_LDS_STS_16: + case R_AVR_PORT6: + case R_AVR_PORT5: return R_ABS; default: error(toString(&File) + ": unknown relocation type: " + toString(Type)); @@ -61,14 +91,104 @@ } void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + uint16_t SRel = Val; + uint16_t X = read16le(Loc); switch (Type) { - case R_AVR_CALL: { - uint16_t Hi = Val >> 17; - uint16_t Lo = Val >> 1; - write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1)); - write16le(Loc + 2, Lo); + case R_AVR_7_PCREL: + SRel -= 2; + X = (X & 0xfc07) | (((SRel >> 1) << 3) & 0x3f8); + write16le(Loc, X); + break; + case R_AVR_13_PCREL: + SRel -= 2; + SRel >>= 1; + X = (X & 0xf000) | (SRel & 0xfff); + write16le(Loc, X); + break; + case R_AVR_LO8_LDI: + case R_AVR_LDI: + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_6: + X = (X & 0xd3f8) | ((SRel & 7) | ((SRel & (3 << 3)) << 7) + | ((SRel & (1 << 5)) << 8)); + write16le(Loc, X); + break; + case R_AVR_6_ADIW: + X = (X & 0xff30) | (SRel & 0xf) | ((SRel & 0x30) << 2); + write16le(Loc, X); + break; + case R_AVR_HI8_LDI: + SRel = (SRel >> 8) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_HH8_LDI: + SRel = (SRel >> 16) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_MS8_LDI: + SRel = (SRel >> 24) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_LO8_LDI_NEG: + write16le(Loc, caculateForLDI(X, -SRel)); + break; + case R_AVR_HI8_LDI_NEG: + SRel = ((-SRel) >> 8) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_HH8_LDI_NEG: + SRel = ((-SRel) >> 16) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_MS8_LDI_NEG: + SRel = ((-SRel) >> 24) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_LO8_LDI_GS: + case R_AVR_LO8_LDI_PM: + SRel = (SRel >> 9) & 0xff;; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_HH8_LDI_PM: + SRel = (SRel >> 17) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_LO8_LDI_PM_NEG: + SRel = (-SRel) >> 1; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_HI8_LDI_PM_NEG: + SRel = ((-SRel) >> 9) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_HH8_LDI_PM_NEG: + SRel = ((-SRel) >> 17) & 0xff; + write16le(Loc, caculateForLDI(X, SRel)); + break; + case R_AVR_CALL: + SRel = SRel >> 1; + X |= ((SRel & 0x10000) | ((SRel << 3) & 0x1f00000)) >> 16; + write16le(Loc, X); + write16le(Loc + 2, SRel & 0xffff); + break; + case R_AVR_16: + case R_AVR_16_PM: + write16le(Loc, (SRel >> 1) & 0x00ffff); + break; + case R_AVR_LDS_STS_16: + SRel = SRel & 0x7f; + X |= (SRel & 0x0f) | ((SRel & 0x30) << 5) | ((SRel & 0x40) << 2); + write16le(Loc, X); + break; + case R_AVR_PORT6: + X = (X & 0xf9f0) | ((SRel & 0x30) << 5) | (SRel & 0x0f); + write16le(Loc, X); + break; + case R_AVR_PORT5: + X = (X & 0xff07) | ((SRel & 0x1f) << 3); + write16le(Loc, X); break; - } default: error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); } Index: test/ELF/basic-avr.s =================================================================== --- test/ELF/basic-avr.s +++ test/ELF/basic-avr.s @@ -4,11 +4,31 @@ # RUN: llvm-objdump -d %t.exe | FileCheck %s main: - call foo + ldi r17, lo8(foo) + ldi r18, hi8(bar) + ldi r19, hh8(foo) + ldi r20, foo + brne next + rjmp next + adiw r24, bar +next: + jmp next foo: jmp foo +bar: + jmp bar # CHECK: main: -# CHECK-NEXT: 0: 0e 94 02 00 +# CHECK-NEXT: 0: 12 e1 +# CHECK-NEXT: 2: 20 e0 +# CHECK-NEXT: 4: 30 e0 +# CHECK-NEXT: 6: 42 e1 +# CHECK-NEXT: 8: 11 f4 +# CHECK-NEXT: a: 01 c0 +# CHECK-NEXT: c: 46 96 +# CHECK: next: +# CHECK-NEXT: e: 0c 94 07 00 # CHECK: foo: -# CHECK-NEXT: 4: 0c 94 02 00 +# CHECK-NEXT: 12: 0c 94 09 00 +# CHECK: bar: +# CHECK-NEXT: 16: 0c 94 0b 00