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