summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
diff options
context:
space:
mode:
authorGreg Fitzgerald <garious@gmail.com>2015-01-21 07:35:48 +0000
committerGreg Fitzgerald <garious@gmail.com>2015-01-21 07:35:48 +0000
commit8a1887f1f1efd32e33b5389715587e85d9592216 (patch)
tree5664bfdccd4d6882f8e03eb3c6c13c05e5e9cee5 /lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
parentf38dea1cfa2dba7848aaba79ad9866896e00f0ad (diff)
downloadbcm5719-llvm-8a1887f1f1efd32e33b5389715587e85d9592216.tar.gz
bcm5719-llvm-8a1887f1f1efd32e33b5389715587e85d9592216.zip
[ELF] Minimal implementation for ARM static linking
The code is able to statically link the simplest case of: int main() { return 0; } * Only works with ARM code - no Thumb code, no interwork (-marm -mno-thumb-interwork) * musl libc built with no interwork and no Thumb code Differential Revision: http://reviews.llvm.org/D6716 From: Denis Protivensky <dprotivensky@accesssoftek.com> llvm-svn: 226643
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp')
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp109
1 files changed, 109 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
new file mode 100644
index 00000000000..e3e1d837ca1
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
@@ -0,0 +1,109 @@
+//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp ----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARMTargetHandler.h"
+#include "ARMLinkingContext.h"
+
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace lld;
+using namespace elf;
+
+static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) {
+ const auto value = int32_t(
+ *reinterpret_cast<const llvm::support::little32_t *>(location));
+
+ const bool isBLX = (value & 0xF0000000) == 0xF0000000;
+ const int32_t bitH = isBLX ? ((value & 0x1000000) >> 24) : 0;
+
+ const int32_t result = ((value & 0xFFFFFF) << 2) | (bitH << 1);
+ return llvm::SignExtend64<26>(result);
+}
+
+static Reference::Addend readAddend(const uint8_t *location,
+ Reference::KindValue kindValue) {
+ switch (kindValue) {
+ case R_ARM_ABS32:
+ return int32_t(
+ *reinterpret_cast<const llvm::support::little32_t *>(location));
+ case R_ARM_CALL:
+ return readAddend_ARM_CALL(location);
+ default:
+ return 0;
+ }
+}
+
+static inline void applyArmReloc(uint8_t *location, uint32_t result,
+ uint32_t mask = 0xFFFFFFFF) {
+ assert(!(result & ~mask));
+ *reinterpret_cast<llvm::support::ulittle32_t *>(location) =
+ (uint32_t(*reinterpret_cast<llvm::support::ulittle32_t *>(location)) &
+ ~mask) | (result & mask);
+}
+
+/// \brief R_ARM_ABS32 - (S + A) | T => S + A
+static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A);
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+/// \brief R_ARM_CALL - ((S + A) | T) - P => S + A - P
+static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)((S + A) - P);
+ const uint32_t imm24 = (result & 0x03FFFFFC) >> 2;
+
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, imm24, 0xFFFFFF);
+}
+
+std::error_code ARMTargetRelocationHandler::applyRelocation(
+ ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
+ const Reference &ref) const {
+ uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
+ uint8_t *location = atomContent + ref.offsetInAtom();
+ uint64_t targetVAddress = writer.addressOfAtom(ref.target());
+ uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
+
+ if (ref.kindNamespace() != Reference::KindNamespace::ELF)
+ return std::error_code();
+ assert(ref.kindArch() == Reference::KindArch::ARM);
+
+ // Calculate proper initial addend for the relocation
+ const Reference::Addend addend =
+ readAddend(location, ref.kindValue());
+
+ switch (ref.kindValue()) {
+ case R_ARM_NONE:
+ break;
+ case R_ARM_ABS32:
+ relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend);
+ break;
+ case R_ARM_CALL:
+ relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend);
+ break;
+ default:
+ make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}
OpenPOWER on IntegriCloud