1 //===- AVR.cpp ------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // AVR is a Harvard-architecture 8-bit microcontroller designed for small 10 // baremetal programs. All AVR-family processors have 32 8-bit registers. 11 // The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest 12 // one supports up to 2^24 data address space and 2^22 code address space. 13 // 14 // Since it is a baremetal programming, there's usually no loader to load 15 // ELF files on AVRs. You are expected to link your program against address 16 // 0 and pull out a .text section from the result using objcopy, so that you 17 // can write the linked code to on-chip flush memory. You can do that with 18 // the following commands: 19 // 20 // ld.lld -Ttext=0 -o foo foo.o 21 // objcopy -O binary --only-section=.text foo output.bin 22 // 23 // Note that the current AVR support is very preliminary so you can't 24 // link any useful program yet, though. 25 // 26 //===----------------------------------------------------------------------===// 27 28 #include "Symbols.h" 29 #include "Target.h" 30 #include "lld/Common/ErrorHandler.h" 31 #include "llvm/BinaryFormat/ELF.h" 32 #include "llvm/Support/Endian.h" 33 34 using namespace llvm; 35 using namespace llvm::object; 36 using namespace llvm::support::endian; 37 using namespace llvm::ELF; 38 using namespace lld; 39 using namespace lld::elf; 40 41 namespace { 42 class AVR final : public TargetInfo { 43 public: 44 uint32_t calcEFlags() const override; 45 RelExpr getRelExpr(RelType type, const Symbol &s, 46 const uint8_t *loc) const override; 47 void relocate(uint8_t *loc, const Relocation &rel, 48 uint64_t val) const override; 49 }; 50 } // namespace 51 52 RelExpr AVR::getRelExpr(RelType type, const Symbol &s, 53 const uint8_t *loc) const { 54 switch (type) { 55 case R_AVR_6: 56 case R_AVR_6_ADIW: 57 case R_AVR_8: 58 case R_AVR_16: 59 case R_AVR_16_PM: 60 case R_AVR_32: 61 case R_AVR_LDI: 62 case R_AVR_LO8_LDI: 63 case R_AVR_LO8_LDI_NEG: 64 case R_AVR_HI8_LDI: 65 case R_AVR_HI8_LDI_NEG: 66 case R_AVR_HH8_LDI_NEG: 67 case R_AVR_HH8_LDI: 68 case R_AVR_MS8_LDI_NEG: 69 case R_AVR_MS8_LDI: 70 case R_AVR_LO8_LDI_PM: 71 case R_AVR_LO8_LDI_PM_NEG: 72 case R_AVR_HI8_LDI_PM: 73 case R_AVR_HI8_LDI_PM_NEG: 74 case R_AVR_HH8_LDI_PM: 75 case R_AVR_HH8_LDI_PM_NEG: 76 case R_AVR_PORT5: 77 case R_AVR_PORT6: 78 case R_AVR_CALL: 79 return R_ABS; 80 case R_AVR_7_PCREL: 81 case R_AVR_13_PCREL: 82 return R_PC; 83 default: 84 error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 85 ") against symbol " + toString(s)); 86 return R_NONE; 87 } 88 } 89 90 static void writeLDI(uint8_t *loc, uint64_t val) { 91 write16le(loc, (read16le(loc) & 0xf0f0) | (val & 0xf0) << 4 | (val & 0x0f)); 92 } 93 94 void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 95 switch (rel.type) { 96 case R_AVR_8: 97 checkUInt(loc, val, 8, rel); 98 *loc = val; 99 break; 100 case R_AVR_16: 101 // Note: this relocation is often used between code and data space, which 102 // are 0x800000 apart in the output ELF file. The bitmask cuts off the high 103 // bit. 104 write16le(loc, val & 0xffff); 105 break; 106 case R_AVR_16_PM: 107 checkAlignment(loc, val, 2, rel); 108 checkUInt(loc, val >> 1, 16, rel); 109 write16le(loc, val >> 1); 110 break; 111 case R_AVR_32: 112 checkUInt(loc, val, 32, rel); 113 write32le(loc, val); 114 break; 115 116 case R_AVR_LDI: 117 checkUInt(loc, val, 8, rel); 118 writeLDI(loc, val & 0xff); 119 break; 120 121 case R_AVR_LO8_LDI_NEG: 122 writeLDI(loc, -val & 0xff); 123 break; 124 case R_AVR_LO8_LDI: 125 writeLDI(loc, val & 0xff); 126 break; 127 case R_AVR_HI8_LDI_NEG: 128 writeLDI(loc, (-val >> 8) & 0xff); 129 break; 130 case R_AVR_HI8_LDI: 131 writeLDI(loc, (val >> 8) & 0xff); 132 break; 133 case R_AVR_HH8_LDI_NEG: 134 writeLDI(loc, (-val >> 16) & 0xff); 135 break; 136 case R_AVR_HH8_LDI: 137 writeLDI(loc, (val >> 16) & 0xff); 138 break; 139 case R_AVR_MS8_LDI_NEG: 140 writeLDI(loc, (-val >> 24) & 0xff); 141 break; 142 case R_AVR_MS8_LDI: 143 writeLDI(loc, (val >> 24) & 0xff); 144 break; 145 146 case R_AVR_LO8_LDI_PM: 147 checkAlignment(loc, val, 2, rel); 148 writeLDI(loc, (val >> 1) & 0xff); 149 break; 150 case R_AVR_HI8_LDI_PM: 151 checkAlignment(loc, val, 2, rel); 152 writeLDI(loc, (val >> 9) & 0xff); 153 break; 154 case R_AVR_HH8_LDI_PM: 155 checkAlignment(loc, val, 2, rel); 156 writeLDI(loc, (val >> 17) & 0xff); 157 break; 158 159 case R_AVR_LO8_LDI_PM_NEG: 160 checkAlignment(loc, val, 2, rel); 161 writeLDI(loc, (-val >> 1) & 0xff); 162 break; 163 case R_AVR_HI8_LDI_PM_NEG: 164 checkAlignment(loc, val, 2, rel); 165 writeLDI(loc, (-val >> 9) & 0xff); 166 break; 167 case R_AVR_HH8_LDI_PM_NEG: 168 checkAlignment(loc, val, 2, rel); 169 writeLDI(loc, (-val >> 17) & 0xff); 170 break; 171 172 case R_AVR_PORT5: 173 checkUInt(loc, val, 5, rel); 174 write16le(loc, (read16le(loc) & 0xff07) | (val << 3)); 175 break; 176 case R_AVR_PORT6: 177 checkUInt(loc, val, 6, rel); 178 write16le(loc, (read16le(loc) & 0xf9f0) | (val & 0x30) << 5 | (val & 0x0f)); 179 break; 180 181 // Since every jump destination is word aligned we gain an extra bit 182 case R_AVR_7_PCREL: { 183 checkInt(loc, val, 7, rel); 184 checkAlignment(loc, val, 2, rel); 185 const uint16_t target = (val - 2) >> 1; 186 write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3)); 187 break; 188 } 189 case R_AVR_13_PCREL: { 190 checkAlignment(loc, val, 2, rel); 191 const uint16_t target = (val - 2) >> 1; 192 write16le(loc, (read16le(loc) & 0xf000) | (target & 0xfff)); 193 break; 194 } 195 196 case R_AVR_6: 197 checkInt(loc, val, 6, rel); 198 write16le(loc, (read16le(loc) & 0xd3f8) | (val & 0x20) << 8 | 199 (val & 0x18) << 7 | (val & 0x07)); 200 break; 201 case R_AVR_6_ADIW: 202 checkInt(loc, val, 6, rel); 203 write16le(loc, (read16le(loc) & 0xff30) | (val & 0x30) << 2 | (val & 0x0F)); 204 break; 205 206 case R_AVR_CALL: { 207 uint16_t hi = val >> 17; 208 uint16_t lo = val >> 1; 209 write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1)); 210 write16le(loc + 2, lo); 211 break; 212 } 213 default: 214 llvm_unreachable("unknown relocation"); 215 } 216 } 217 218 TargetInfo *elf::getAVRTargetInfo() { 219 static AVR target; 220 return ⌖ 221 } 222 223 static uint32_t getEFlags(InputFile *file) { 224 return cast<ObjFile<ELF32LE>>(file)->getObj().getHeader().e_flags; 225 } 226 227 uint32_t AVR::calcEFlags() const { 228 assert(!objectFiles.empty()); 229 230 uint32_t flags = getEFlags(objectFiles[0]); 231 bool hasLinkRelaxFlag = flags & EF_AVR_LINKRELAX_PREPARED; 232 233 for (InputFile *f : makeArrayRef(objectFiles).slice(1)) { 234 uint32_t objFlags = getEFlags(f); 235 if ((objFlags & EF_AVR_ARCH_MASK) != (flags & EF_AVR_ARCH_MASK)) 236 error(toString(f) + 237 ": cannot link object files with incompatible target ISA"); 238 if (!(objFlags & EF_AVR_LINKRELAX_PREPARED)) 239 hasLinkRelaxFlag = false; 240 } 241 242 if (!hasLinkRelaxFlag) 243 flags &= ~EF_AVR_LINKRELAX_PREPARED; 244 245 return flags; 246 } 247