brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 5276ff9 Raw
295 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// AVR is a Harvard-architecture 8-bit microcontroller designed for small10// 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 largest12// 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 load15// ELF files on AVRs. You are expected to link your program against address16// 0 and pull out a .text section from the result using objcopy, so that you17// can write the linked code to on-chip flush memory. You can do that with18// the following commands:19//20//   ld.lld -Ttext=0 -o foo foo.o21//   objcopy -O binary --only-section=.text foo output.bin22//23// Note that the current AVR support is very preliminary so you can't24// 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 35using namespace llvm;36using namespace llvm::object;37using namespace llvm::support::endian;38using namespace llvm::ELF;39using namespace lld;40using namespace lld::elf;41 42namespace {43class AVR final : public TargetInfo {44public: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} // namespace56 57RelExpr 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.v96             << ") against symbol " << &s;97    return R_NONE;98  }99}100 101static void writeLDI(uint8_t *loc, uint64_t val) {102  write16le(loc, (read16le(loc) & 0xf0f0) | (val & 0xf0) << 4 | (val & 0x0f));103}104 105bool 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 range111    // [0, 0x1ffff].112    return s.getVA(ctx) >= 0x20000;113  default:114    return false;115  }116}117 118void 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, which138    // are 0x800000 apart in the output ELF file. The bitmask cuts off the high139    // 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 bit232  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 269void elf::setAVRTargetInfo(Ctx &ctx) { ctx.target.reset(new AVR(ctx)); }270 271static uint32_t getEFlags(InputFile *file) {272  return cast<ObjFile<ELF32LE>>(file)->getObj().getHeader().e_flags;273}274 275uint32_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