1 //===- AVR.cpp ------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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.
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:
20 // ld.lld -Ttext=0 -o foo foo.o
21 // objcopy -O binary --only-section=.text foo output.bin
23 // Note that the current AVR support is very preliminary so you can't
24 // link any useful program yet, though.
26 //===----------------------------------------------------------------------===//
28 #include "InputFiles.h"
32 #include "lld/Common/ErrorHandler.h"
33 #include "llvm/BinaryFormat/ELF.h"
34 #include "llvm/Support/Endian.h"
37 using namespace llvm::object
;
38 using namespace llvm::support::endian
;
39 using namespace llvm::ELF
;
41 using namespace lld::elf
;
44 class AVR final
: public TargetInfo
{
46 AVR() { needsThunks
= true; }
47 uint32_t calcEFlags() const override
;
48 RelExpr
getRelExpr(RelType type
, const Symbol
&s
,
49 const uint8_t *loc
) const override
;
50 bool needsThunk(RelExpr expr
, RelType type
, const InputFile
*file
,
51 uint64_t branchAddr
, const Symbol
&s
,
52 int64_t a
) const override
;
53 void relocate(uint8_t *loc
, const Relocation
&rel
,
54 uint64_t val
) const override
;
58 RelExpr
AVR::getRelExpr(RelType type
, const Symbol
&s
,
59 const uint8_t *loc
) const {
72 case R_AVR_LO8_LDI_NEG
:
74 case R_AVR_HI8_LDI_NEG
:
75 case R_AVR_HH8_LDI_NEG
:
77 case R_AVR_MS8_LDI_NEG
:
79 case R_AVR_LO8_LDI_GS
:
80 case R_AVR_LO8_LDI_PM
:
81 case R_AVR_LO8_LDI_PM_NEG
:
82 case R_AVR_HI8_LDI_GS
:
83 case R_AVR_HI8_LDI_PM
:
84 case R_AVR_HI8_LDI_PM_NEG
:
85 case R_AVR_HH8_LDI_PM
:
86 case R_AVR_HH8_LDI_PM_NEG
:
87 case R_AVR_LDS_STS_16
:
96 error(getErrorLocation(loc
) + "unknown relocation (" + Twine(type
) +
97 ") against symbol " + toString(s
));
102 static void writeLDI(uint8_t *loc
, uint64_t val
) {
103 write16le(loc
, (read16le(loc
) & 0xf0f0) | (val
& 0xf0) << 4 | (val
& 0x0f));
106 bool AVR::needsThunk(RelExpr expr
, RelType type
, const InputFile
*file
,
107 uint64_t branchAddr
, const Symbol
&s
, int64_t a
) const {
109 case R_AVR_LO8_LDI_GS
:
110 case R_AVR_HI8_LDI_GS
:
111 // A thunk is needed if the symbol's virtual address is out of range
113 return s
.getVA() >= 0x20000;
119 void AVR::relocate(uint8_t *loc
, const Relocation
&rel
, uint64_t val
) const {
122 checkUInt(loc
, val
, 8, rel
);
126 checkUInt(loc
, val
, 32, rel
);
130 checkUInt(loc
, val
, 32, rel
);
131 *loc
= (val
>> 8) & 0xff;
134 checkUInt(loc
, val
, 32, rel
);
135 *loc
= (val
>> 16) & 0xff;
138 // Note: this relocation is often used between code and data space, which
139 // are 0x800000 apart in the output ELF file. The bitmask cuts off the high
141 write16le(loc
, val
& 0xffff);
144 checkAlignment(loc
, val
, 2, rel
);
145 checkUInt(loc
, val
>> 1, 16, rel
);
146 write16le(loc
, val
>> 1);
149 checkUInt(loc
, val
, 32, rel
);
154 checkUInt(loc
, val
, 8, rel
);
155 writeLDI(loc
, val
& 0xff);
158 case R_AVR_LO8_LDI_NEG
:
159 writeLDI(loc
, -val
& 0xff);
162 writeLDI(loc
, val
& 0xff);
164 case R_AVR_HI8_LDI_NEG
:
165 writeLDI(loc
, (-val
>> 8) & 0xff);
168 writeLDI(loc
, (val
>> 8) & 0xff);
170 case R_AVR_HH8_LDI_NEG
:
171 writeLDI(loc
, (-val
>> 16) & 0xff);
174 writeLDI(loc
, (val
>> 16) & 0xff);
176 case R_AVR_MS8_LDI_NEG
:
177 writeLDI(loc
, (-val
>> 24) & 0xff);
180 writeLDI(loc
, (val
>> 24) & 0xff);
183 case R_AVR_LO8_LDI_GS
:
184 checkUInt(loc
, val
, 17, rel
);
186 case R_AVR_LO8_LDI_PM
:
187 checkAlignment(loc
, val
, 2, rel
);
188 writeLDI(loc
, (val
>> 1) & 0xff);
190 case R_AVR_HI8_LDI_GS
:
191 checkUInt(loc
, val
, 17, rel
);
193 case R_AVR_HI8_LDI_PM
:
194 checkAlignment(loc
, val
, 2, rel
);
195 writeLDI(loc
, (val
>> 9) & 0xff);
197 case R_AVR_HH8_LDI_PM
:
198 checkAlignment(loc
, val
, 2, rel
);
199 writeLDI(loc
, (val
>> 17) & 0xff);
202 case R_AVR_LO8_LDI_PM_NEG
:
203 checkAlignment(loc
, val
, 2, rel
);
204 writeLDI(loc
, (-val
>> 1) & 0xff);
206 case R_AVR_HI8_LDI_PM_NEG
:
207 checkAlignment(loc
, val
, 2, rel
);
208 writeLDI(loc
, (-val
>> 9) & 0xff);
210 case R_AVR_HH8_LDI_PM_NEG
:
211 checkAlignment(loc
, val
, 2, rel
);
212 writeLDI(loc
, (-val
>> 17) & 0xff);
215 case R_AVR_LDS_STS_16
: {
216 checkUInt(loc
, val
, 7, rel
);
217 const uint16_t hi
= val
>> 4;
218 const uint16_t lo
= val
& 0xf;
219 write16le(loc
, (read16le(loc
) & 0xf8f0) | ((hi
<< 8) | lo
));
224 checkUInt(loc
, val
, 5, rel
);
225 write16le(loc
, (read16le(loc
) & 0xff07) | (val
<< 3));
228 checkUInt(loc
, val
, 6, rel
);
229 write16le(loc
, (read16le(loc
) & 0xf9f0) | (val
& 0x30) << 5 | (val
& 0x0f));
232 // Since every jump destination is word aligned we gain an extra bit
233 case R_AVR_7_PCREL
: {
234 checkInt(loc
, val
- 2, 7, rel
);
235 checkAlignment(loc
, val
, 2, rel
);
236 const uint16_t target
= (val
- 2) >> 1;
237 write16le(loc
, (read16le(loc
) & 0xfc07) | ((target
& 0x7f) << 3));
240 case R_AVR_13_PCREL
: {
241 checkInt(loc
, val
- 2, 13, rel
);
242 checkAlignment(loc
, val
, 2, rel
);
243 const uint16_t target
= (val
- 2) >> 1;
244 write16le(loc
, (read16le(loc
) & 0xf000) | (target
& 0xfff));
249 checkInt(loc
, val
, 6, rel
);
250 write16le(loc
, (read16le(loc
) & 0xd3f8) | (val
& 0x20) << 8 |
251 (val
& 0x18) << 7 | (val
& 0x07));
254 checkInt(loc
, val
, 6, rel
);
255 write16le(loc
, (read16le(loc
) & 0xff30) | (val
& 0x30) << 2 | (val
& 0x0F));
259 checkAlignment(loc
, val
, 2, rel
);
260 uint16_t hi
= val
>> 17;
261 uint16_t lo
= val
>> 1;
262 write16le(loc
, read16le(loc
) | ((hi
>> 1) << 4) | (hi
& 1));
263 write16le(loc
+ 2, lo
);
267 llvm_unreachable("unknown relocation");
271 TargetInfo
*elf::getAVRTargetInfo() {
276 static uint32_t getEFlags(InputFile
*file
) {
277 return cast
<ObjFile
<ELF32LE
>>(file
)->getObj().getHeader().e_flags
;
280 uint32_t AVR::calcEFlags() const {
281 assert(!ctx
.objectFiles
.empty());
283 uint32_t flags
= getEFlags(ctx
.objectFiles
[0]);
284 bool hasLinkRelaxFlag
= flags
& EF_AVR_LINKRELAX_PREPARED
;
286 for (InputFile
*f
: ArrayRef(ctx
.objectFiles
).slice(1)) {
287 uint32_t objFlags
= getEFlags(f
);
288 if ((objFlags
& EF_AVR_ARCH_MASK
) != (flags
& EF_AVR_ARCH_MASK
))
290 ": cannot link object files with incompatible target ISA");
291 if (!(objFlags
& EF_AVR_LINKRELAX_PREPARED
))
292 hasLinkRelaxFlag
= false;
295 if (!hasLinkRelaxFlag
)
296 flags
&= ~EF_AVR_LINKRELAX_PREPARED
;