summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp')
-rw-r--r--lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
new file mode 100644
index 000000000000..da5a24c6ec37
--- /dev/null
+++ b/lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp
@@ -0,0 +1,57 @@
+//===- lib/ReaderWriter/ELF/X86/X86RelocationHandler.cpp ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86LinkingContext.h"
+#include "X86TargetHandler.h"
+#include "llvm/Support/Endian.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm::support::endian;
+
+namespace {
+/// \brief R_386_32 - word32: S + A
+static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ int32_t result = (uint32_t)(S + A);
+ write32le(location, result | read32le(location));
+ return 0;
+}
+
+/// \brief R_386_PC32 - word32: S + A - P
+static int relocPC32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
+ uint32_t result = (uint32_t)((S + A) - P);
+ write32le(location, result + read32le(location));
+ return 0;
+}
+}
+
+std::error_code X86TargetRelocationHandler::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::x86);
+ switch (ref.kindValue()) {
+ case R_386_32:
+ reloc32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ case R_386_PC32:
+ relocPC32(location, relocVAddress, targetVAddress, ref.addend());
+ break;
+ default:
+ return make_unhandled_reloc_error();
+ }
+
+ return std::error_code();
+}