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 "InputFiles.h" 29 #include "Symbols.h" 30 #include "Target.h" 31 #include "Thunks.h" 32 #include "llvm/BinaryFormat/ELF.h" 33 #include "llvm/Support/Endian.h" 34 35 using namespace llvm; 36 using namespace llvm::object; 37 using namespace llvm::support::endian; 38 using namespace llvm::ELF; 39 using namespace lld; 40 using namespace lld::elf; 41 42 namespace { 43 class AVR final : public TargetInfo { 44 public: 45 AVR(Ctx &ctx) : TargetInfo(ctx) { needsThunks = true; } 46 uint32_t calcEFlags() const override; 47 RelExpr getRelExpr(RelType type, const Symbol &s, 48 const uint8_t *loc) const override; 49 bool needsThunk(RelExpr expr, RelType type, const InputFile *file, 50 uint64_t branchAddr, const Symbol &s, 51 int64_t a) const override; 52 void relocate(uint8_t *loc, const Relocation &rel, 53 uint64_t val) const override; 54 }; 55 } // namespace 56 57 RelExpr AVR::getRelExpr(RelType type, const Symbol &s, 58 const uint8_t *loc) const { 59 switch (type) { 60 case R_AVR_6: 61 case R_AVR_6_ADIW: 62 case R_AVR_8: 63 case R_AVR_8_LO8: 64 case R_AVR_8_HI8: 65 case R_AVR_8_HLO8: 66 case R_AVR_16: 67 case R_AVR_16_PM: 68 case R_AVR_32: 69 case R_AVR_LDI: 70 case R_AVR_LO8_LDI: 71 case R_AVR_LO8_LDI_NEG: 72 case R_AVR_HI8_LDI: 73 case R_AVR_HI8_LDI_NEG: 74 case R_AVR_HH8_LDI_NEG: 75 case R_AVR_HH8_LDI: 76 case R_AVR_MS8_LDI_NEG: 77 case R_AVR_MS8_LDI: 78 case R_AVR_LO8_LDI_GS: 79 case R_AVR_LO8_LDI_PM: 80 case R_AVR_LO8_LDI_PM_NEG: 81 case R_AVR_HI8_LDI_GS: 82 case R_AVR_HI8_LDI_PM: 83 case R_AVR_HI8_LDI_PM_NEG: 84 case R_AVR_HH8_LDI_PM: 85 case R_AVR_HH8_LDI_PM_NEG: 86 case R_AVR_LDS_STS_16: 87 case R_AVR_PORT5: 88 case R_AVR_PORT6: 89 case R_AVR_CALL: 90 return R_ABS; 91 case R_AVR_7_PCREL: 92 case R_AVR_13_PCREL: 93 return R_PC; 94 default: 95 Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v 96 << ") against symbol " << &s; 97 return R_NONE; 98 } 99 } 100 101 static void writeLDI(uint8_t *loc, uint64_t val) { 102 write16le(loc, (read16le(loc) & 0xf0f0) | (val & 0xf0) << 4 | (val & 0x0f)); 103 } 104 105 bool AVR::needsThunk(RelExpr expr, RelType type, const InputFile *file, 106 uint64_t branchAddr, const Symbol &s, int64_t a) const { 107 switch (type) { 108 case R_AVR_LO8_LDI_GS: 109 case R_AVR_HI8_LDI_GS: 110 // A thunk is needed if the symbol's virtual address is out of range 111 // [0, 0x1ffff]. 112 return s.getVA(ctx) >= 0x20000; 113 default: 114 return false; 115 } 116 } 117 118 void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 119 switch (rel.type) { 120 case R_AVR_8: 121 checkUInt(ctx, loc, val, 8, rel); 122 *loc = val; 123 break; 124 case R_AVR_8_LO8: 125 checkUInt(ctx, loc, val, 32, rel); 126 *loc = val & 0xff; 127 break; 128 case R_AVR_8_HI8: 129 checkUInt(ctx, loc, val, 32, rel); 130 *loc = (val >> 8) & 0xff; 131 break; 132 case R_AVR_8_HLO8: 133 checkUInt(ctx, loc, val, 32, rel); 134 *loc = (val >> 16) & 0xff; 135 break; 136 case R_AVR_16: 137 // Note: this relocation is often used between code and data space, which 138 // are 0x800000 apart in the output ELF file. The bitmask cuts off the high 139 // bit. 140 write16le(loc, val & 0xffff); 141 break; 142 case R_AVR_16_PM: 143 checkAlignment(ctx, loc, val, 2, rel); 144 checkUInt(ctx, loc, val >> 1, 16, rel); 145 write16le(loc, val >> 1); 146 break; 147 case R_AVR_32: 148 checkUInt(ctx, loc, val, 32, rel); 149 write32le(loc, val); 150 break; 151 152 case R_AVR_LDI: 153 checkUInt(ctx, loc, val, 8, rel); 154 writeLDI(loc, val & 0xff); 155 break; 156 157 case R_AVR_LO8_LDI_NEG: 158 writeLDI(loc, -val & 0xff); 159 break; 160 case R_AVR_LO8_LDI: 161 writeLDI(loc, val & 0xff); 162 break; 163 case R_AVR_HI8_LDI_NEG: 164 writeLDI(loc, (-val >> 8) & 0xff); 165 break; 166 case R_AVR_HI8_LDI: 167 writeLDI(loc, (val >> 8) & 0xff); 168 break; 169 case R_AVR_HH8_LDI_NEG: 170 writeLDI(loc, (-val >> 16) & 0xff); 171 break; 172 case R_AVR_HH8_LDI: 173 writeLDI(loc, (val >> 16) & 0xff); 174 break; 175 case R_AVR_MS8_LDI_NEG: 176 writeLDI(loc, (-val >> 24) & 0xff); 177 break; 178 case R_AVR_MS8_LDI: 179 writeLDI(loc, (val >> 24) & 0xff); 180 break; 181 182 case R_AVR_LO8_LDI_GS: 183 checkUInt(ctx, loc, val, 17, rel); 184 [[fallthrough]]; 185 case R_AVR_LO8_LDI_PM: 186 checkAlignment(ctx, loc, val, 2, rel); 187 writeLDI(loc, (val >> 1) & 0xff); 188 break; 189 case R_AVR_HI8_LDI_GS: 190 checkUInt(ctx, loc, val, 17, rel); 191 [[fallthrough]]; 192 case R_AVR_HI8_LDI_PM: 193 checkAlignment(ctx, loc, val, 2, rel); 194 writeLDI(loc, (val >> 9) & 0xff); 195 break; 196 case R_AVR_HH8_LDI_PM: 197 checkAlignment(ctx, loc, val, 2, rel); 198 writeLDI(loc, (val >> 17) & 0xff); 199 break; 200 201 case R_AVR_LO8_LDI_PM_NEG: 202 checkAlignment(ctx, loc, val, 2, rel); 203 writeLDI(loc, (-val >> 1) & 0xff); 204 break; 205 case R_AVR_HI8_LDI_PM_NEG: 206 checkAlignment(ctx, loc, val, 2, rel); 207 writeLDI(loc, (-val >> 9) & 0xff); 208 break; 209 case R_AVR_HH8_LDI_PM_NEG: 210 checkAlignment(ctx, loc, val, 2, rel); 211 writeLDI(loc, (-val >> 17) & 0xff); 212 break; 213 214 case R_AVR_LDS_STS_16: { 215 checkUInt(ctx, loc, val, 7, rel); 216 const uint16_t hi = val >> 4; 217 const uint16_t lo = val & 0xf; 218 write16le(loc, (read16le(loc) & 0xf8f0) | ((hi << 8) | lo)); 219 break; 220 } 221 222 case R_AVR_PORT5: 223 checkUInt(ctx, loc, val, 5, rel); 224 write16le(loc, (read16le(loc) & 0xff07) | (val << 3)); 225 break; 226 case R_AVR_PORT6: 227 checkUInt(ctx, loc, val, 6, rel); 228 write16le(loc, (read16le(loc) & 0xf9f0) | (val & 0x30) << 5 | (val & 0x0f)); 229 break; 230 231 // Since every jump destination is word aligned we gain an extra bit 232 case R_AVR_7_PCREL: { 233 checkInt(ctx, loc, val - 2, 8, rel); 234 checkAlignment(ctx, loc, val, 2, rel); 235 const uint16_t target = (val - 2) >> 1; 236 write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3)); 237 break; 238 } 239 case R_AVR_13_PCREL: { 240 checkAlignment(ctx, loc, val, 2, rel); 241 const uint16_t target = (val - 2) >> 1; 242 write16le(loc, (read16le(loc) & 0xf000) | (target & 0xfff)); 243 break; 244 } 245 246 case R_AVR_6: 247 checkInt(ctx, loc, val, 6, rel); 248 write16le(loc, (read16le(loc) & 0xd3f8) | (val & 0x20) << 8 | 249 (val & 0x18) << 7 | (val & 0x07)); 250 break; 251 case R_AVR_6_ADIW: 252 checkInt(ctx, loc, val, 6, rel); 253 write16le(loc, (read16le(loc) & 0xff30) | (val & 0x30) << 2 | (val & 0x0F)); 254 break; 255 256 case R_AVR_CALL: { 257 checkAlignment(ctx, loc, val, 2, rel); 258 uint16_t hi = val >> 17; 259 uint16_t lo = val >> 1; 260 write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1)); 261 write16le(loc + 2, lo); 262 break; 263 } 264 default: 265 llvm_unreachable("unknown relocation"); 266 } 267 } 268 269 void elf::setAVRTargetInfo(Ctx &ctx) { ctx.target.reset(new AVR(ctx)); } 270 271 static uint32_t getEFlags(InputFile *file) { 272 return cast<ObjFile<ELF32LE>>(file)->getObj().getHeader().e_flags; 273 } 274 275 uint32_t AVR::calcEFlags() const { 276 assert(!ctx.objectFiles.empty()); 277 278 uint32_t flags = getEFlags(ctx.objectFiles[0]); 279 bool hasLinkRelaxFlag = flags & EF_AVR_LINKRELAX_PREPARED; 280 281 for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) { 282 uint32_t objFlags = getEFlags(f); 283 if ((objFlags & EF_AVR_ARCH_MASK) != (flags & EF_AVR_ARCH_MASK)) 284 ErrAlways(ctx) 285 << f << ": cannot link object files with incompatible target ISA"; 286 if (!(objFlags & EF_AVR_LINKRELAX_PREPARED)) 287 hasLinkRelaxFlag = false; 288 } 289 290 if (!hasLinkRelaxFlag) 291 flags &= ~EF_AVR_LINKRELAX_PREPARED; 292 293 return flags; 294 } 295