diff options
author | Jason W Kim <jason.w.kim.2009@gmail.com> | 2010-12-01 02:40:06 +0000 |
---|---|---|
committer | Jason W Kim <jason.w.kim.2009@gmail.com> | 2010-12-01 02:40:06 +0000 |
commit | 85fed5e0c5bc010f967948a4af6b425a5a2f2bd0 (patch) | |
tree | 339b05440d349244878383e60af94c7952bb28b4 /lib/Target/ARM/ARMAsmBackend.cpp | |
parent | 0480e28fb2a7d4e140d56c39e9705c922456585c (diff) | |
download | external_llvm-85fed5e0c5bc010f967948a4af6b425a5a2f2bd0.zip external_llvm-85fed5e0c5bc010f967948a4af6b425a5a2f2bd0.tar.gz external_llvm-85fed5e0c5bc010f967948a4af6b425a5a2f2bd0.tar.bz2 |
ARM/MC/ELF relocation "hello world" for movw/movt.
Lifted adjustFixupValue() from Darwin for sharing w ELF.
Test added
TODO:
refactor ELFObjectWriter::RecordRelocation more.
Possibly share more code with Darwin?
Lots more relocations...
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120534 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/ARM/ARMAsmBackend.cpp')
-rw-r--r-- | lib/Target/ARM/ARMAsmBackend.cpp | 119 |
1 files changed, 75 insertions, 44 deletions
diff --git a/lib/Target/ARM/ARMAsmBackend.cpp b/lib/Target/ARM/ARMAsmBackend.cpp index 6267a5a..432d077 100644 --- a/lib/Target/ARM/ARMAsmBackend.cpp +++ b/lib/Target/ARM/ARMAsmBackend.cpp @@ -38,6 +38,48 @@ public: unsigned getPointerSize() const { return 4; } + +protected: + static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_4: + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movw_lo16: + return Value; + case ARM::fixup_arm_pcrel_12: { + bool isAdd = true; + // ARM PC-relative values are offset by 8. + Value -= 8; + if ((int64_t)Value < 0) { + Value = -Value; + isAdd = false; + } + assert ((Value < 4096) && "Out of range pc-relative fixup value!"); + Value |= isAdd << 23; + return Value; + } + case ARM::fixup_arm_branch: + // These values don't encode the low two bits since they're always zero. + // Offset by 8 just as above. + return (Value - 8) >> 2; + case ARM::fixup_arm_vfp_pcrel_12: { + // Offset by 8 just as above. + Value = Value - 8; + bool isAdd = true; + if ((int64_t)Value < 0) { + Value = -Value; + isAdd = false; + } + // These values don't encode the low two bits since they're always zero. + Value >>= 2; + assert ((Value < 256) && "Out of range pc-relative fixup value!"); + Value |= isAdd << 23; + return Value; + } + } + } }; } // end anonymous namespace @@ -52,10 +94,6 @@ void ARMAsmBackend::RelaxInstruction(const MCInst &Inst, MCInst &Res) const { } bool ARMAsmBackend::WriteNopData(uint64_t Count, MCObjectWriter *OW) const { -// if ((Count % 4) != 0) { -// // Fixme: % 2 for Thumb? -// return false; -// } // FIXME: Zero fill for now. That's not right, but at least will get the // section size right. for (uint64_t i = 0; i != Count; ++i) @@ -94,7 +132,39 @@ public: // Fixme: can we raise this to share code between Darwin and ELF? void ELFARMAsmBackend::ApplyFixup(const MCFixup &Fixup, MCDataFragment &DF, uint64_t Value) const { - assert(0 && "ELFARMAsmBackend::ApplyFixup() unimplemented"); + uint32_t Mask = 0; + // Fixme: 2 for Thumb + int NumBytes = 4; + Value = adjustFixupValue(Fixup.getKind(), Value); + + switch (Fixup.getKind()) { + default: assert(0 && "Unsupported Fixup kind"); break; + case ARM::fixup_arm_branch: { + unsigned Lo24 = Value & 0xFFFFFF; + Mask = ~(0xFFFFFF); + Value = Lo24; + }; break; + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movw_lo16: { + unsigned Hi4 = (Value & 0xF000) >> 12; + unsigned Lo12 = Value & 0x0FFF; + // inst{19-16} = Hi4; + // inst{11-0} = Lo12; + Value = (Hi4 << 16) | (Lo12); + Mask = ~(0xF0FFF); + }; break; + } + + assert((Fixup.getOffset() % NumBytes == 0) + && "Offset mod NumBytes is nonzero!"); + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + // The Value has been "split up" into the appropriate bitfields above. + // Fixme: how to share code with the .td generated code? + for (unsigned i = 0; i != NumBytes; ++i) { + DF.getContents()[Fixup.getOffset() + i] &= uint8_t(Mask >> (i * 8)); + DF.getContents()[Fixup.getOffset() + i] |= uint8_t(Value >> (i * 8)); + } } namespace { @@ -137,45 +207,6 @@ static unsigned getFixupKindNumBytes(unsigned Kind) { } } -static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { - switch (Kind) { - default: - llvm_unreachable("Unknown fixup kind!"); - case FK_Data_4: - return Value; - case ARM::fixup_arm_pcrel_12: { - bool isAdd = true; - // ARM PC-relative values are offset by 8. - Value -= 8; - if ((int64_t)Value < 0) { - Value = -Value; - isAdd = false; - } - assert ((Value < 4096) && "Out of range pc-relative fixup value!"); - Value |= isAdd << 23; - return Value; - } - case ARM::fixup_arm_branch: - // These values don't encode the low two bits since they're always zero. - // Offset by 8 just as above. - return (Value - 8) >> 2; - case ARM::fixup_arm_vfp_pcrel_12: { - // Offset by 8 just as above. - Value = Value - 8; - bool isAdd = true; - if ((int64_t)Value < 0) { - Value = -Value; - isAdd = false; - } - // These values don't encode the low two bits since they're always zero. - Value >>= 2; - assert ((Value < 256) && "Out of range pc-relative fixup value!"); - Value |= isAdd << 23; - return Value; - } - } -} - void DarwinARMAsmBackend::ApplyFixup(const MCFixup &Fixup, MCDataFragment &DF, uint64_t Value) const { unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); |