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