10b57cec5SDimitry Andric //===- AVR.cpp ------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
9fe6060f1SDimitry Andric // AVR is a Harvard-architecture 8-bit microcontroller designed for small
100b57cec5SDimitry Andric // baremetal programs. All AVR-family processors have 32 8-bit registers.
110b57cec5SDimitry Andric // The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest
120b57cec5SDimitry Andric // one supports up to 2^24 data address space and 2^22 code address space.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric // Since it is a baremetal programming, there's usually no loader to load
150b57cec5SDimitry Andric // ELF files on AVRs. You are expected to link your program against address
160b57cec5SDimitry Andric // 0 and pull out a .text section from the result using objcopy, so that you
170b57cec5SDimitry Andric // can write the linked code to on-chip flush memory. You can do that with
180b57cec5SDimitry Andric // the following commands:
190b57cec5SDimitry Andric //
200b57cec5SDimitry Andric // ld.lld -Ttext=0 -o foo foo.o
210b57cec5SDimitry Andric // objcopy -O binary --only-section=.text foo output.bin
220b57cec5SDimitry Andric //
230b57cec5SDimitry Andric // Note that the current AVR support is very preliminary so you can't
240b57cec5SDimitry Andric // link any useful program yet, though.
250b57cec5SDimitry Andric //
260b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric #include "InputFiles.h"
290b57cec5SDimitry Andric #include "Symbols.h"
300b57cec5SDimitry Andric #include "Target.h"
3106c3fb27SDimitry Andric #include "Thunks.h"
320b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
3381ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
340b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric using namespace llvm;
370b57cec5SDimitry Andric using namespace llvm::object;
380b57cec5SDimitry Andric using namespace llvm::support::endian;
390b57cec5SDimitry Andric using namespace llvm::ELF;
405ffd83dbSDimitry Andric using namespace lld;
415ffd83dbSDimitry Andric using namespace lld::elf;
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric namespace {
440b57cec5SDimitry Andric class AVR final : public TargetInfo {
450b57cec5SDimitry Andric public:
AVR()4606c3fb27SDimitry Andric AVR() { needsThunks = true; }
47fe6060f1SDimitry Andric uint32_t calcEFlags() const override;
480b57cec5SDimitry Andric RelExpr getRelExpr(RelType type, const Symbol &s,
490b57cec5SDimitry Andric const uint8_t *loc) const override;
5006c3fb27SDimitry Andric bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
5106c3fb27SDimitry Andric uint64_t branchAddr, const Symbol &s,
5206c3fb27SDimitry Andric int64_t a) const override;
535ffd83dbSDimitry Andric void relocate(uint8_t *loc, const Relocation &rel,
545ffd83dbSDimitry Andric uint64_t val) const override;
550b57cec5SDimitry Andric };
560b57cec5SDimitry Andric } // namespace
570b57cec5SDimitry Andric
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const580b57cec5SDimitry Andric RelExpr AVR::getRelExpr(RelType type, const Symbol &s,
590b57cec5SDimitry Andric const uint8_t *loc) const {
605ffd83dbSDimitry Andric switch (type) {
61fe6060f1SDimitry Andric case R_AVR_6:
62fe6060f1SDimitry Andric case R_AVR_6_ADIW:
63fe6060f1SDimitry Andric case R_AVR_8:
6406c3fb27SDimitry Andric case R_AVR_8_LO8:
6506c3fb27SDimitry Andric case R_AVR_8_HI8:
6606c3fb27SDimitry Andric case R_AVR_8_HLO8:
67fe6060f1SDimitry Andric case R_AVR_16:
68fe6060f1SDimitry Andric case R_AVR_16_PM:
69fe6060f1SDimitry Andric case R_AVR_32:
70fe6060f1SDimitry Andric case R_AVR_LDI:
71fe6060f1SDimitry Andric case R_AVR_LO8_LDI:
72fe6060f1SDimitry Andric case R_AVR_LO8_LDI_NEG:
73fe6060f1SDimitry Andric case R_AVR_HI8_LDI:
74fe6060f1SDimitry Andric case R_AVR_HI8_LDI_NEG:
75fe6060f1SDimitry Andric case R_AVR_HH8_LDI_NEG:
76fe6060f1SDimitry Andric case R_AVR_HH8_LDI:
77fe6060f1SDimitry Andric case R_AVR_MS8_LDI_NEG:
78fe6060f1SDimitry Andric case R_AVR_MS8_LDI:
7906c3fb27SDimitry Andric case R_AVR_LO8_LDI_GS:
80fe6060f1SDimitry Andric case R_AVR_LO8_LDI_PM:
81fe6060f1SDimitry Andric case R_AVR_LO8_LDI_PM_NEG:
8206c3fb27SDimitry Andric case R_AVR_HI8_LDI_GS:
83fe6060f1SDimitry Andric case R_AVR_HI8_LDI_PM:
84fe6060f1SDimitry Andric case R_AVR_HI8_LDI_PM_NEG:
85fe6060f1SDimitry Andric case R_AVR_HH8_LDI_PM:
86fe6060f1SDimitry Andric case R_AVR_HH8_LDI_PM_NEG:
87bdd1243dSDimitry Andric case R_AVR_LDS_STS_16:
88fe6060f1SDimitry Andric case R_AVR_PORT5:
89fe6060f1SDimitry Andric case R_AVR_PORT6:
90fe6060f1SDimitry Andric case R_AVR_CALL:
91fe6060f1SDimitry Andric return R_ABS;
925ffd83dbSDimitry Andric case R_AVR_7_PCREL:
935ffd83dbSDimitry Andric case R_AVR_13_PCREL:
945ffd83dbSDimitry Andric return R_PC;
955ffd83dbSDimitry Andric default:
96fe6060f1SDimitry Andric error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
97fe6060f1SDimitry Andric ") against symbol " + toString(s));
98fe6060f1SDimitry Andric return R_NONE;
990b57cec5SDimitry Andric }
1005ffd83dbSDimitry Andric }
1010b57cec5SDimitry Andric
writeLDI(uint8_t * loc,uint64_t val)1025ffd83dbSDimitry Andric static void writeLDI(uint8_t *loc, uint64_t val) {
1035ffd83dbSDimitry Andric write16le(loc, (read16le(loc) & 0xf0f0) | (val & 0xf0) << 4 | (val & 0x0f));
1045ffd83dbSDimitry Andric }
1055ffd83dbSDimitry Andric
needsThunk(RelExpr expr,RelType type,const InputFile * file,uint64_t branchAddr,const Symbol & s,int64_t a) const10606c3fb27SDimitry Andric bool AVR::needsThunk(RelExpr expr, RelType type, const InputFile *file,
10706c3fb27SDimitry Andric uint64_t branchAddr, const Symbol &s, int64_t a) const {
10806c3fb27SDimitry Andric switch (type) {
10906c3fb27SDimitry Andric case R_AVR_LO8_LDI_GS:
11006c3fb27SDimitry Andric case R_AVR_HI8_LDI_GS:
11106c3fb27SDimitry Andric // A thunk is needed if the symbol's virtual address is out of range
11206c3fb27SDimitry Andric // [0, 0x1ffff].
11306c3fb27SDimitry Andric return s.getVA() >= 0x20000;
11406c3fb27SDimitry Andric default:
11506c3fb27SDimitry Andric return false;
11606c3fb27SDimitry Andric }
11706c3fb27SDimitry Andric }
11806c3fb27SDimitry Andric
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const1195ffd83dbSDimitry Andric void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
1205ffd83dbSDimitry Andric switch (rel.type) {
1215ffd83dbSDimitry Andric case R_AVR_8:
1225ffd83dbSDimitry Andric checkUInt(loc, val, 8, rel);
1235ffd83dbSDimitry Andric *loc = val;
1245ffd83dbSDimitry Andric break;
12506c3fb27SDimitry Andric case R_AVR_8_LO8:
12606c3fb27SDimitry Andric checkUInt(loc, val, 32, rel);
12706c3fb27SDimitry Andric *loc = val & 0xff;
12806c3fb27SDimitry Andric break;
12906c3fb27SDimitry Andric case R_AVR_8_HI8:
13006c3fb27SDimitry Andric checkUInt(loc, val, 32, rel);
13106c3fb27SDimitry Andric *loc = (val >> 8) & 0xff;
13206c3fb27SDimitry Andric break;
13306c3fb27SDimitry Andric case R_AVR_8_HLO8:
13406c3fb27SDimitry Andric checkUInt(loc, val, 32, rel);
13506c3fb27SDimitry Andric *loc = (val >> 16) & 0xff;
13606c3fb27SDimitry Andric break;
1375ffd83dbSDimitry Andric case R_AVR_16:
1385ffd83dbSDimitry Andric // Note: this relocation is often used between code and data space, which
1395ffd83dbSDimitry Andric // are 0x800000 apart in the output ELF file. The bitmask cuts off the high
1405ffd83dbSDimitry Andric // bit.
1415ffd83dbSDimitry Andric write16le(loc, val & 0xffff);
1425ffd83dbSDimitry Andric break;
1435ffd83dbSDimitry Andric case R_AVR_16_PM:
1445ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
1455ffd83dbSDimitry Andric checkUInt(loc, val >> 1, 16, rel);
1465ffd83dbSDimitry Andric write16le(loc, val >> 1);
1475ffd83dbSDimitry Andric break;
1485ffd83dbSDimitry Andric case R_AVR_32:
1495ffd83dbSDimitry Andric checkUInt(loc, val, 32, rel);
1505ffd83dbSDimitry Andric write32le(loc, val);
1515ffd83dbSDimitry Andric break;
1525ffd83dbSDimitry Andric
1535ffd83dbSDimitry Andric case R_AVR_LDI:
1545ffd83dbSDimitry Andric checkUInt(loc, val, 8, rel);
1555ffd83dbSDimitry Andric writeLDI(loc, val & 0xff);
1565ffd83dbSDimitry Andric break;
1575ffd83dbSDimitry Andric
1585ffd83dbSDimitry Andric case R_AVR_LO8_LDI_NEG:
1595ffd83dbSDimitry Andric writeLDI(loc, -val & 0xff);
1605ffd83dbSDimitry Andric break;
1615ffd83dbSDimitry Andric case R_AVR_LO8_LDI:
1625ffd83dbSDimitry Andric writeLDI(loc, val & 0xff);
1635ffd83dbSDimitry Andric break;
1645ffd83dbSDimitry Andric case R_AVR_HI8_LDI_NEG:
1655ffd83dbSDimitry Andric writeLDI(loc, (-val >> 8) & 0xff);
1665ffd83dbSDimitry Andric break;
1675ffd83dbSDimitry Andric case R_AVR_HI8_LDI:
1685ffd83dbSDimitry Andric writeLDI(loc, (val >> 8) & 0xff);
1695ffd83dbSDimitry Andric break;
1705ffd83dbSDimitry Andric case R_AVR_HH8_LDI_NEG:
1715ffd83dbSDimitry Andric writeLDI(loc, (-val >> 16) & 0xff);
1725ffd83dbSDimitry Andric break;
1735ffd83dbSDimitry Andric case R_AVR_HH8_LDI:
1745ffd83dbSDimitry Andric writeLDI(loc, (val >> 16) & 0xff);
1755ffd83dbSDimitry Andric break;
1765ffd83dbSDimitry Andric case R_AVR_MS8_LDI_NEG:
1775ffd83dbSDimitry Andric writeLDI(loc, (-val >> 24) & 0xff);
1785ffd83dbSDimitry Andric break;
1795ffd83dbSDimitry Andric case R_AVR_MS8_LDI:
1805ffd83dbSDimitry Andric writeLDI(loc, (val >> 24) & 0xff);
1815ffd83dbSDimitry Andric break;
1825ffd83dbSDimitry Andric
18306c3fb27SDimitry Andric case R_AVR_LO8_LDI_GS:
18406c3fb27SDimitry Andric checkUInt(loc, val, 17, rel);
18506c3fb27SDimitry Andric [[fallthrough]];
1865ffd83dbSDimitry Andric case R_AVR_LO8_LDI_PM:
1875ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
1885ffd83dbSDimitry Andric writeLDI(loc, (val >> 1) & 0xff);
1895ffd83dbSDimitry Andric break;
19006c3fb27SDimitry Andric case R_AVR_HI8_LDI_GS:
19106c3fb27SDimitry Andric checkUInt(loc, val, 17, rel);
19206c3fb27SDimitry Andric [[fallthrough]];
1935ffd83dbSDimitry Andric case R_AVR_HI8_LDI_PM:
1945ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
1955ffd83dbSDimitry Andric writeLDI(loc, (val >> 9) & 0xff);
1965ffd83dbSDimitry Andric break;
1975ffd83dbSDimitry Andric case R_AVR_HH8_LDI_PM:
1985ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
1995ffd83dbSDimitry Andric writeLDI(loc, (val >> 17) & 0xff);
2005ffd83dbSDimitry Andric break;
2015ffd83dbSDimitry Andric
2025ffd83dbSDimitry Andric case R_AVR_LO8_LDI_PM_NEG:
2035ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
2045ffd83dbSDimitry Andric writeLDI(loc, (-val >> 1) & 0xff);
2055ffd83dbSDimitry Andric break;
2065ffd83dbSDimitry Andric case R_AVR_HI8_LDI_PM_NEG:
2075ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
2085ffd83dbSDimitry Andric writeLDI(loc, (-val >> 9) & 0xff);
2095ffd83dbSDimitry Andric break;
2105ffd83dbSDimitry Andric case R_AVR_HH8_LDI_PM_NEG:
2115ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
2125ffd83dbSDimitry Andric writeLDI(loc, (-val >> 17) & 0xff);
2135ffd83dbSDimitry Andric break;
2145ffd83dbSDimitry Andric
215bdd1243dSDimitry Andric case R_AVR_LDS_STS_16: {
216bdd1243dSDimitry Andric checkUInt(loc, val, 7, rel);
217bdd1243dSDimitry Andric const uint16_t hi = val >> 4;
218bdd1243dSDimitry Andric const uint16_t lo = val & 0xf;
219bdd1243dSDimitry Andric write16le(loc, (read16le(loc) & 0xf8f0) | ((hi << 8) | lo));
220bdd1243dSDimitry Andric break;
221bdd1243dSDimitry Andric }
222bdd1243dSDimitry Andric
2235ffd83dbSDimitry Andric case R_AVR_PORT5:
2245ffd83dbSDimitry Andric checkUInt(loc, val, 5, rel);
2255ffd83dbSDimitry Andric write16le(loc, (read16le(loc) & 0xff07) | (val << 3));
2265ffd83dbSDimitry Andric break;
2275ffd83dbSDimitry Andric case R_AVR_PORT6:
2285ffd83dbSDimitry Andric checkUInt(loc, val, 6, rel);
2295ffd83dbSDimitry Andric write16le(loc, (read16le(loc) & 0xf9f0) | (val & 0x30) << 5 | (val & 0x0f));
2305ffd83dbSDimitry Andric break;
2315ffd83dbSDimitry Andric
2325ffd83dbSDimitry Andric // Since every jump destination is word aligned we gain an extra bit
2335ffd83dbSDimitry Andric case R_AVR_7_PCREL: {
234*0fca6ea1SDimitry Andric checkInt(loc, val - 2, 8, rel);
2355ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
2365ffd83dbSDimitry Andric const uint16_t target = (val - 2) >> 1;
2375ffd83dbSDimitry Andric write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3));
2385ffd83dbSDimitry Andric break;
2395ffd83dbSDimitry Andric }
2405ffd83dbSDimitry Andric case R_AVR_13_PCREL: {
2415ffd83dbSDimitry Andric checkAlignment(loc, val, 2, rel);
2425ffd83dbSDimitry Andric const uint16_t target = (val - 2) >> 1;
2435ffd83dbSDimitry Andric write16le(loc, (read16le(loc) & 0xf000) | (target & 0xfff));
2445ffd83dbSDimitry Andric break;
2455ffd83dbSDimitry Andric }
2465ffd83dbSDimitry Andric
2475ffd83dbSDimitry Andric case R_AVR_6:
2485ffd83dbSDimitry Andric checkInt(loc, val, 6, rel);
2495ffd83dbSDimitry Andric write16le(loc, (read16le(loc) & 0xd3f8) | (val & 0x20) << 8 |
2505ffd83dbSDimitry Andric (val & 0x18) << 7 | (val & 0x07));
2515ffd83dbSDimitry Andric break;
2525ffd83dbSDimitry Andric case R_AVR_6_ADIW:
2535ffd83dbSDimitry Andric checkInt(loc, val, 6, rel);
2545ffd83dbSDimitry Andric write16le(loc, (read16le(loc) & 0xff30) | (val & 0x30) << 2 | (val & 0x0F));
2555ffd83dbSDimitry Andric break;
2565ffd83dbSDimitry Andric
2570b57cec5SDimitry Andric case R_AVR_CALL: {
2585f757f3fSDimitry Andric checkAlignment(loc, val, 2, rel);
2590b57cec5SDimitry Andric uint16_t hi = val >> 17;
2600b57cec5SDimitry Andric uint16_t lo = val >> 1;
2610b57cec5SDimitry Andric write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1));
2620b57cec5SDimitry Andric write16le(loc + 2, lo);
2630b57cec5SDimitry Andric break;
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric default:
266fe6060f1SDimitry Andric llvm_unreachable("unknown relocation");
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric
getAVRTargetInfo()2705ffd83dbSDimitry Andric TargetInfo *elf::getAVRTargetInfo() {
2710b57cec5SDimitry Andric static AVR target;
2720b57cec5SDimitry Andric return ⌖
2730b57cec5SDimitry Andric }
274fe6060f1SDimitry Andric
getEFlags(InputFile * file)275fe6060f1SDimitry Andric static uint32_t getEFlags(InputFile *file) {
276fe6060f1SDimitry Andric return cast<ObjFile<ELF32LE>>(file)->getObj().getHeader().e_flags;
277fe6060f1SDimitry Andric }
278fe6060f1SDimitry Andric
calcEFlags() const279fe6060f1SDimitry Andric uint32_t AVR::calcEFlags() const {
280bdd1243dSDimitry Andric assert(!ctx.objectFiles.empty());
281fe6060f1SDimitry Andric
282bdd1243dSDimitry Andric uint32_t flags = getEFlags(ctx.objectFiles[0]);
283fe6060f1SDimitry Andric bool hasLinkRelaxFlag = flags & EF_AVR_LINKRELAX_PREPARED;
284fe6060f1SDimitry Andric
285bdd1243dSDimitry Andric for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
286fe6060f1SDimitry Andric uint32_t objFlags = getEFlags(f);
287fe6060f1SDimitry Andric if ((objFlags & EF_AVR_ARCH_MASK) != (flags & EF_AVR_ARCH_MASK))
288fe6060f1SDimitry Andric error(toString(f) +
289fe6060f1SDimitry Andric ": cannot link object files with incompatible target ISA");
290fe6060f1SDimitry Andric if (!(objFlags & EF_AVR_LINKRELAX_PREPARED))
291fe6060f1SDimitry Andric hasLinkRelaxFlag = false;
292fe6060f1SDimitry Andric }
293fe6060f1SDimitry Andric
294fe6060f1SDimitry Andric if (!hasLinkRelaxFlag)
295fe6060f1SDimitry Andric flags &= ~EF_AVR_LINKRELAX_PREPARED;
296fe6060f1SDimitry Andric
297fe6060f1SDimitry Andric return flags;
298fe6060f1SDimitry Andric }
299