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