xref: /llvm-project-15.0.7/lld/ELF/Arch/AVR.cpp (revision 1206b95e)
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 micrcontroller 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 "lld/Common/ErrorHandler.h"
32 #include "llvm/Object/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();
46   uint32_t calcEFlags() const override;
47   RelExpr getRelExpr(RelType type, const Symbol &s,
48                      const uint8_t *loc) const override;
49   void relocate(uint8_t *loc, const Relocation &rel,
50                 uint64_t val) const override;
51 };
52 } // namespace
53 
54 AVR::AVR() { noneRel = R_AVR_NONE; }
55 
56 RelExpr AVR::getRelExpr(RelType type, const Symbol &s,
57                         const uint8_t *loc) const {
58   switch (type) {
59   case R_AVR_7_PCREL:
60   case R_AVR_13_PCREL:
61     return R_PC;
62   default:
63     return R_ABS;
64   }
65 }
66 
67 static void writeLDI(uint8_t *loc, uint64_t val) {
68   write16le(loc, (read16le(loc) & 0xf0f0) | (val & 0xf0) << 4 | (val & 0x0f));
69 }
70 
71 void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
72   switch (rel.type) {
73   case R_AVR_8:
74     checkUInt(loc, val, 8, rel);
75     *loc = val;
76     break;
77   case R_AVR_16:
78     // Note: this relocation is often used between code and data space, which
79     // are 0x800000 apart in the output ELF file. The bitmask cuts off the high
80     // bit.
81     write16le(loc, val & 0xffff);
82     break;
83   case R_AVR_16_PM:
84     checkAlignment(loc, val, 2, rel);
85     checkUInt(loc, val >> 1, 16, rel);
86     write16le(loc, val >> 1);
87     break;
88   case R_AVR_32:
89     checkUInt(loc, val, 32, rel);
90     write32le(loc, val);
91     break;
92 
93   case R_AVR_LDI:
94     checkUInt(loc, val, 8, rel);
95     writeLDI(loc, val & 0xff);
96     break;
97 
98   case R_AVR_LO8_LDI_NEG:
99     writeLDI(loc, -val & 0xff);
100     break;
101   case R_AVR_LO8_LDI:
102     writeLDI(loc, val & 0xff);
103     break;
104   case R_AVR_HI8_LDI_NEG:
105     writeLDI(loc, (-val >> 8) & 0xff);
106     break;
107   case R_AVR_HI8_LDI:
108     writeLDI(loc, (val >> 8) & 0xff);
109     break;
110   case R_AVR_HH8_LDI_NEG:
111     writeLDI(loc, (-val >> 16) & 0xff);
112     break;
113   case R_AVR_HH8_LDI:
114     writeLDI(loc, (val >> 16) & 0xff);
115     break;
116   case R_AVR_MS8_LDI_NEG:
117     writeLDI(loc, (-val >> 24) & 0xff);
118     break;
119   case R_AVR_MS8_LDI:
120     writeLDI(loc, (val >> 24) & 0xff);
121     break;
122 
123   case R_AVR_LO8_LDI_PM:
124     checkAlignment(loc, val, 2, rel);
125     writeLDI(loc, (val >> 1) & 0xff);
126     break;
127   case R_AVR_HI8_LDI_PM:
128     checkAlignment(loc, val, 2, rel);
129     writeLDI(loc, (val >> 9) & 0xff);
130     break;
131   case R_AVR_HH8_LDI_PM:
132     checkAlignment(loc, val, 2, rel);
133     writeLDI(loc, (val >> 17) & 0xff);
134     break;
135 
136   case R_AVR_LO8_LDI_PM_NEG:
137     checkAlignment(loc, val, 2, rel);
138     writeLDI(loc, (-val >> 1) & 0xff);
139     break;
140   case R_AVR_HI8_LDI_PM_NEG:
141     checkAlignment(loc, val, 2, rel);
142     writeLDI(loc, (-val >> 9) & 0xff);
143     break;
144   case R_AVR_HH8_LDI_PM_NEG:
145     checkAlignment(loc, val, 2, rel);
146     writeLDI(loc, (-val >> 17) & 0xff);
147     break;
148 
149   case R_AVR_PORT5:
150     checkUInt(loc, val, 5, rel);
151     write16le(loc, (read16le(loc) & 0xff07) | (val << 3));
152     break;
153   case R_AVR_PORT6:
154     checkUInt(loc, val, 6, rel);
155     write16le(loc, (read16le(loc) & 0xf9f0) | (val & 0x30) << 5 | (val & 0x0f));
156     break;
157 
158   // Since every jump destination is word aligned we gain an extra bit
159   case R_AVR_7_PCREL: {
160     checkInt(loc, val, 7, rel);
161     checkAlignment(loc, val, 2, rel);
162     const uint16_t target = (val - 2) >> 1;
163     write16le(loc, (read16le(loc) & 0xfc07) | ((target & 0x7f) << 3));
164     break;
165   }
166   case R_AVR_13_PCREL: {
167     checkAlignment(loc, val, 2, rel);
168     const uint16_t target = (val - 2) >> 1;
169     write16le(loc, (read16le(loc) & 0xf000) | (target & 0xfff));
170     break;
171   }
172 
173   case R_AVR_6:
174     checkInt(loc, val, 6, rel);
175     write16le(loc, (read16le(loc) & 0xd3f8) | (val & 0x20) << 8 |
176                        (val & 0x18) << 7 | (val & 0x07));
177     break;
178   case R_AVR_6_ADIW:
179     checkInt(loc, val, 6, rel);
180     write16le(loc, (read16le(loc) & 0xff30) | (val & 0x30) << 2 | (val & 0x0F));
181     break;
182 
183   case R_AVR_CALL: {
184     uint16_t hi = val >> 17;
185     uint16_t lo = val >> 1;
186     write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1));
187     write16le(loc + 2, lo);
188     break;
189   }
190   default:
191     error(getErrorLocation(loc) + "unrecognized relocation " +
192           toString(rel.type));
193   }
194 }
195 
196 TargetInfo *elf::getAVRTargetInfo() {
197   static AVR target;
198   return &target;
199 }
200 
201 static uint32_t getEFlags(InputFile *file) {
202   return cast<ObjFile<ELF32LE>>(file)->getObj().getHeader().e_flags;
203 }
204 
205 uint32_t AVR::calcEFlags() const {
206   assert(!objectFiles.empty());
207 
208   uint32_t flags = getEFlags(objectFiles[0]);
209   bool hasLinkRelaxFlag = flags & EF_AVR_LINKRELAX_PREPARED;
210 
211   for (InputFile *f : makeArrayRef(objectFiles).slice(1)) {
212     uint32_t objFlags = getEFlags(f);
213     if ((objFlags & EF_AVR_ARCH_MASK) != (flags & EF_AVR_ARCH_MASK))
214       error(toString(f) +
215             ": cannot link object files with incompatible target ISA");
216     if (!(objFlags & EF_AVR_LINKRELAX_PREPARED))
217       hasLinkRelaxFlag = false;
218   }
219 
220   if (!hasLinkRelaxFlag)
221     flags &= ~EF_AVR_LINKRELAX_PREPARED;
222 
223   return flags;
224 }
225