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