Path: blob/main/contrib/llvm-project/lld/ELF/Arch/AVR.cpp
34878 views
//===- AVR.cpp ------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// AVR is a Harvard-architecture 8-bit microcontroller designed for small9// baremetal programs. All AVR-family processors have 32 8-bit registers.10// The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest11// one supports up to 2^24 data address space and 2^22 code address space.12//13// Since it is a baremetal programming, there's usually no loader to load14// ELF files on AVRs. You are expected to link your program against address15// 0 and pull out a .text section from the result using objcopy, so that you16// can write the linked code to on-chip flush memory. You can do that with17// the following commands:18//19// ld.lld -Ttext=0 -o foo foo.o20// objcopy -O binary --only-section=.text foo output.bin21//22// Note that the current AVR support is very preliminary so you can't23// link any useful program yet, though.24//25//===----------------------------------------------------------------------===//2627#include "InputFiles.h"28#include "Symbols.h"29#include "Target.h"30#include "Thunks.h"31#include "lld/Common/ErrorHandler.h"32#include "llvm/BinaryFormat/ELF.h"33#include "llvm/Support/Endian.h"3435using namespace llvm;36using namespace llvm::object;37using namespace llvm::support::endian;38using namespace llvm::ELF;39using namespace lld;40using namespace lld::elf;4142namespace {43class AVR final : public TargetInfo {44public:45AVR() { needsThunks = true; }46uint32_t calcEFlags() const override;47RelExpr getRelExpr(RelType type, const Symbol &s,48const uint8_t *loc) const override;49bool needsThunk(RelExpr expr, RelType type, const InputFile *file,50uint64_t branchAddr, const Symbol &s,51int64_t a) const override;52void relocate(uint8_t *loc, const Relocation &rel,53uint64_t val) const override;54};55} // namespace5657RelExpr AVR::getRelExpr(RelType type, const Symbol &s,58const uint8_t *loc) const {59switch (type) {60case R_AVR_6:61case R_AVR_6_ADIW:62case R_AVR_8:63case R_AVR_8_LO8:64case R_AVR_8_HI8:65case R_AVR_8_HLO8:66case R_AVR_16:67case R_AVR_16_PM:68case R_AVR_32:69case R_AVR_LDI:70case R_AVR_LO8_LDI:71case R_AVR_LO8_LDI_NEG:72case R_AVR_HI8_LDI:73case R_AVR_HI8_LDI_NEG:74case R_AVR_HH8_LDI_NEG:75case R_AVR_HH8_LDI:76case R_AVR_MS8_LDI_NEG:77case R_AVR_MS8_LDI:78case R_AVR_LO8_LDI_GS:79case R_AVR_LO8_LDI_PM:80case R_AVR_LO8_LDI_PM_NEG:81case R_AVR_HI8_LDI_GS:82case R_AVR_HI8_LDI_PM:83case R_AVR_HI8_LDI_PM_NEG:84case R_AVR_HH8_LDI_PM:85case R_AVR_HH8_LDI_PM_NEG:86case R_AVR_LDS_STS_16:87case R_AVR_PORT5:88case R_AVR_PORT6:89case R_AVR_CALL:90return R_ABS;91case R_AVR_7_PCREL:92case R_AVR_13_PCREL:93return R_PC;94default:95error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +96") against symbol " + toString(s));97return R_NONE;98}99}100101static void writeLDI(uint8_t *loc, uint64_t val) {102write16le(loc, (read16le(loc) & 0xf0f0) | (val & 0xf0) << 4 | (val & 0x0f));103}104105bool AVR::needsThunk(RelExpr expr, RelType type, const InputFile *file,106uint64_t branchAddr, const Symbol &s, int64_t a) const {107switch (type) {108case R_AVR_LO8_LDI_GS:109case R_AVR_HI8_LDI_GS:110// A thunk is needed if the symbol's virtual address is out of range111// [0, 0x1ffff].112return s.getVA() >= 0x20000;113default:114return false;115}116}117118void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {119switch (rel.type) {120case R_AVR_8:121checkUInt(loc, val, 8, rel);122*loc = val;123break;124case R_AVR_8_LO8:125checkUInt(loc, val, 32, rel);126*loc = val & 0xff;127break;128case R_AVR_8_HI8:129checkUInt(loc, val, 32, rel);130*loc = (val >> 8) & 0xff;131break;132case R_AVR_8_HLO8:133checkUInt(loc, val, 32, rel);134*loc = (val >> 16) & 0xff;135break;136case 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.140write16le(loc, val & 0xffff);141break;142case R_AVR_16_PM:143checkAlignment(loc, val, 2, rel);144checkUInt(loc, val >> 1, 16, rel);145write16le(loc, val >> 1);146break;147case R_AVR_32:148checkUInt(loc, val, 32, rel);149write32le(loc, val);150break;151152case R_AVR_LDI:153checkUInt(loc, val, 8, rel);154writeLDI(loc, val & 0xff);155break;156157case R_AVR_LO8_LDI_NEG:158writeLDI(loc, -val & 0xff);159break;160case R_AVR_LO8_LDI:161writeLDI(loc, val & 0xff);162break;163case R_AVR_HI8_LDI_NEG:164writeLDI(loc, (-val >> 8) & 0xff);165break;166case R_AVR_HI8_LDI:167writeLDI(loc, (val >> 8) & 0xff);168break;169case R_AVR_HH8_LDI_NEG:170writeLDI(loc, (-val >> 16) & 0xff);171break;172case R_AVR_HH8_LDI:173writeLDI(loc, (val >> 16) & 0xff);174break;175case R_AVR_MS8_LDI_NEG:176writeLDI(loc, (-val >> 24) & 0xff);177break;178case R_AVR_MS8_LDI:179writeLDI(loc, (val >> 24) & 0xff);180break;181182case R_AVR_LO8_LDI_GS:183checkUInt(loc, val, 17, rel);184[[fallthrough]];185case R_AVR_LO8_LDI_PM:186checkAlignment(loc, val, 2, rel);187writeLDI(loc, (val >> 1) & 0xff);188break;189case R_AVR_HI8_LDI_GS:190checkUInt(loc, val, 17, rel);191[[fallthrough]];192case R_AVR_HI8_LDI_PM:193checkAlignment(loc, val, 2, rel);194writeLDI(loc, (val >> 9) & 0xff);195break;196case R_AVR_HH8_LDI_PM:197checkAlignment(loc, val, 2, rel);198writeLDI(loc, (val >> 17) & 0xff);199break;200201case R_AVR_LO8_LDI_PM_NEG:202checkAlignment(loc, val, 2, rel);203writeLDI(loc, (-val >> 1) & 0xff);204break;205case R_AVR_HI8_LDI_PM_NEG:206checkAlignment(loc, val, 2, rel);207writeLDI(loc, (-val >> 9) & 0xff);208break;209case R_AVR_HH8_LDI_PM_NEG:210checkAlignment(loc, val, 2, rel);211writeLDI(loc, (-val >> 17) & 0xff);212break;213214case R_AVR_LDS_STS_16: {215checkUInt(loc, val, 7, rel);216const uint16_t hi = val >> 4;217const uint16_t lo = val & 0xf;218write16le(loc, (read16le(loc) & 0xf8f0) | ((hi << 8) | lo));219break;220}221222case R_AVR_PORT5:223checkUInt(loc, val, 5, rel);224write16le(loc, (read16le(loc) & 0xff07) | (val << 3));225break;226case R_AVR_PORT6:227checkUInt(loc, val, 6, rel);228write16le(loc, (read16le(loc) & 0xf9f0) | (val & 0x30) << 5 | (val & 0x0f));229break;230231// Since every jump destination is word aligned we gain an extra bit232case R_AVR_7_PCREL: {233checkInt(loc, val - 2, 8, rel);234checkAlignment(loc, val, 2, rel);235const uint16_t target = (val - 2) >> 1;236write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3));237break;238}239case R_AVR_13_PCREL: {240checkAlignment(loc, val, 2, rel);241const uint16_t target = (val - 2) >> 1;242write16le(loc, (read16le(loc) & 0xf000) | (target & 0xfff));243break;244}245246case R_AVR_6:247checkInt(loc, val, 6, rel);248write16le(loc, (read16le(loc) & 0xd3f8) | (val & 0x20) << 8 |249(val & 0x18) << 7 | (val & 0x07));250break;251case R_AVR_6_ADIW:252checkInt(loc, val, 6, rel);253write16le(loc, (read16le(loc) & 0xff30) | (val & 0x30) << 2 | (val & 0x0F));254break;255256case R_AVR_CALL: {257checkAlignment(loc, val, 2, rel);258uint16_t hi = val >> 17;259uint16_t lo = val >> 1;260write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1));261write16le(loc + 2, lo);262break;263}264default:265llvm_unreachable("unknown relocation");266}267}268269TargetInfo *elf::getAVRTargetInfo() {270static AVR target;271return ⌖272}273274static uint32_t getEFlags(InputFile *file) {275return cast<ObjFile<ELF32LE>>(file)->getObj().getHeader().e_flags;276}277278uint32_t AVR::calcEFlags() const {279assert(!ctx.objectFiles.empty());280281uint32_t flags = getEFlags(ctx.objectFiles[0]);282bool hasLinkRelaxFlag = flags & EF_AVR_LINKRELAX_PREPARED;283284for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {285uint32_t objFlags = getEFlags(f);286if ((objFlags & EF_AVR_ARCH_MASK) != (flags & EF_AVR_ARCH_MASK))287error(toString(f) +288": cannot link object files with incompatible target ISA");289if (!(objFlags & EF_AVR_LINKRELAX_PREPARED))290hasLinkRelaxFlag = false;291}292293if (!hasLinkRelaxFlag)294flags &= ~EF_AVR_LINKRELAX_PREPARED;295296return flags;297}298299300