Skip to content

Instantly share code, notes, and snippets.

@aykevl
Created June 10, 2020 19:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aykevl/ce3c04e1175d9602c9dfaf0cf91298ba to your computer and use it in GitHub Desktop.
Save aykevl/ce3c04e1175d9602c9dfaf0cf91298ba to your computer and use it in GitHub Desktop.
commit 86b6f41a63f995f219218c00ef539e6d1d924336
Author: Ayke van Laethem <aykevanlaethem@gmail.com>
Date: Mon Apr 27 18:58:03 2020 +0200
[lld][AVR] Implement some more relocations
With these relocations, I can link a variety of programs (including all
TinyGo tests, as far as they compile).
diff --git a/lld/ELF/Arch/AVR.cpp b/lld/ELF/Arch/AVR.cpp
index 9b733837dd5..8568d9985b6 100644
--- a/lld/ELF/Arch/AVR.cpp
+++ b/lld/ELF/Arch/AVR.cpp
@@ -54,18 +54,83 @@ AVR::AVR() { noneRel = R_AVR_NONE; }
RelExpr AVR::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
- return R_ABS;
+ switch (type) {
+ case R_AVR_7_PCREL:
+ case R_AVR_13_PCREL:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
}
void AVR::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
switch (rel.type) {
case R_AVR_CALL: {
+ // Fixup for call instructions.
+ // Format: 1001 010k kkkk 111k kkkk kkkk kkkk kkkk
+ checkInt(loc, val, 23, rel);
+ checkAlignment(loc, val, 2, rel);
uint16_t hi = val >> 17;
uint16_t lo = val >> 1;
write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1));
write16le(loc + 2, lo);
break;
}
+ case R_AVR_LO8_LDI:
+ case R_AVR_HI8_LDI:
+ case R_AVR_LO8_LDI_NEG:
+ case R_AVR_HI8_LDI_NEG:
+ case R_AVR_LO8_LDI_PM:
+ case R_AVR_HI8_LDI_PM: {
+ // Fixups for instructions such as ldi and subi. Usually two instructions
+ // are used together, one that uses the lower half and one that uses the
+ // upper half of a 16-bit value.
+ // Format: 1110 KKKK dddd KKKK
+ if (rel.type == R_AVR_LO8_LDI_NEG || rel.type == R_AVR_HI8_LDI_NEG) {
+ // Relocations for subi/sbci.
+ val &= 0xffff; // clear the upper bit if this is a relocation to data space
+ val = 0x10000 - val; // make negative
+ }
+ if (rel.type == R_AVR_LO8_LDI_PM || rel.type == R_AVR_HI8_LDI_PM)
+ // Fixup for loading a function pointer, for example.
+ val = val >> 1;
+ if (rel.type == R_AVR_HI8_LDI || rel.type == R_AVR_HI8_LDI_PM || rel.type == R_AVR_HI8_LDI_NEG)
+ // Load the upper byte (R_AVR_HI8_LDI* relocations).
+ val >>= 8;
+ uint16_t hi4 = (val >> 4) & 0xf;
+ uint16_t lo4 = val & 0xf;
+ write16le(loc, read16le(loc) | (hi4 << 8) | lo4 );
+ break;
+ }
+ case R_AVR_7_PCREL:
+ // Fixup for relative branches such as brne. The branch target (in words)
+ // is k+1, so we have to subtract two from the branch target to correct for
+ // that.
+ // Format: 1111 01kk kkkk k001
+ val = (int64_t)val - 2;
+ checkInt(loc, val, 7, rel);
+ checkAlignment(loc, val, 2, rel);
+ write16le(loc, read16le(loc) | ((val >> 1) & 0x7f) << 3);
+ break;
+ case R_AVR_13_PCREL:
+ // Fixup for relative jumps: rjmp and rcall. Like R_AVR_7_PCREL, the branch
+ // target should be adjusted.
+ // Format: 1100 kkkk kkkk kkkk
+ val = (int64_t)val - 2;
+ checkInt(loc, val, 13, rel);
+ checkAlignment(loc, val, 2, rel);
+ write16le(loc, read16le(loc) | ((val >> 1) & 0xfff));
+ break;
+ case R_AVR_16:
+ // Note: this relocation is often used between code and data space, which
+ // are 0x800000 apart in the output ELF file. The bitmask cuts off the high
+ // bit.
+ write16le(loc, val & 0xffff);
+ break;
+ case R_AVR_32:
+ checkIntUInt(loc, val, 32, rel);
+ write32le(loc, val);
+ break;
default:
error(getErrorLocation(loc) + "unrecognized relocation " +
toString(rel.type));
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index bcef615f1c6..e3f54725b9a 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -854,8 +854,8 @@ static bool getIsRela(opt::InputArgList &args) {
// Otherwise use the psABI defined relocation entry format.
uint16_t m = config->emachine;
- return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC ||
- m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64;
+ return m == EM_AARCH64 || m == EM_AMDGPU || m == EM_AVR || m == EM_HEXAGON ||
+ m == EM_PPC || m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64;
}
static void parseClangOption(StringRef opt, const Twine &msg) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment