summaryrefslogtreecommitdiff
path: root/include/llvm/Object/RelocVisitor.h
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2013-04-08 18:41:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2013-04-08 18:41:23 +0000
commit4a16efa3e43e35f0cc9efe3a67f620f0017c3d36 (patch)
tree06099edc18d30894081a822b756f117cbe0b8207 /include/llvm/Object/RelocVisitor.h
parent482e7bddf617ae804dc47133cb07eb4aa81e45de (diff)
Notes
Diffstat (limited to 'include/llvm/Object/RelocVisitor.h')
-rw-r--r--include/llvm/Object/RelocVisitor.h124
1 files changed, 101 insertions, 23 deletions
diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h
index 7668bdedb7bba..2dcbdf905327d 100644
--- a/include/llvm/Object/RelocVisitor.h
+++ b/include/llvm/Object/RelocVisitor.h
@@ -13,14 +13,14 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _LLVM_OBJECT_RELOCVISITOR
-#define _LLVM_OBJECT_RELOCVISITOR
+#ifndef LLVM_OBJECT_RELOCVISITOR_H
+#define LLVM_OBJECT_RELOCVISITOR_H
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ELF.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/ADT/StringRef.h"
namespace llvm {
namespace object {
@@ -40,7 +40,7 @@ struct RelocToApply {
/// @brief Base class for object file relocation visitors.
class RelocVisitor {
public:
- explicit RelocVisitor(llvm::StringRef FileFormat)
+ explicit RelocVisitor(StringRef FileFormat)
: FileFormat(FileFormat), HasError(false) {}
// TODO: Should handle multiple applied relocations via either passing in the
@@ -64,35 +64,77 @@ public:
HasError = true;
return RelocToApply();
}
+ } else if (FileFormat == "ELF32-i386") {
+ switch (RelocType) {
+ case llvm::ELF::R_386_NONE:
+ return visitELF_386_NONE(R);
+ case llvm::ELF::R_386_32:
+ return visitELF_386_32(R, Value);
+ case llvm::ELF::R_386_PC32:
+ return visitELF_386_PC32(R, Value, SecAddr);
+ default:
+ HasError = true;
+ return RelocToApply();
+ }
+ } else if (FileFormat == "ELF64-ppc64") {
+ switch (RelocType) {
+ case llvm::ELF::R_PPC64_ADDR32:
+ return visitELF_PPC64_ADDR32(R, Value);
+ default:
+ HasError = true;
+ return RelocToApply();
+ }
+ } else if (FileFormat == "ELF32-mips") {
+ switch (RelocType) {
+ case llvm::ELF::R_MIPS_32:
+ return visitELF_MIPS_32(R, Value);
+ default:
+ HasError = true;
+ return RelocToApply();
+ }
+ } else if (FileFormat == "ELF64-aarch64") {
+ switch (RelocType) {
+ case llvm::ELF::R_AARCH64_ABS32:
+ return visitELF_AARCH64_ABS32(R, Value);
+ case llvm::ELF::R_AARCH64_ABS64:
+ return visitELF_AARCH64_ABS64(R, Value);
+ default:
+ HasError = true;
+ return RelocToApply();
+ }
}
+ HasError = true;
return RelocToApply();
}
bool error() { return HasError; }
private:
- llvm::StringRef FileFormat;
+ StringRef FileFormat;
bool HasError;
/// Operations
- // Width is the width in bytes of the extend.
- RelocToApply zeroExtend(RelocToApply r, char Width) {
- if (Width == r.Width)
- return r;
- r.Value &= (1 << ((Width * 8))) - 1;
- return r;
+ /// 386-ELF
+ RelocToApply visitELF_386_NONE(RelocationRef R) {
+ return RelocToApply(0, 0);
}
- RelocToApply signExtend(RelocToApply r, char Width) {
- if (Width == r.Width)
- return r;
- bool SignBit = r.Value & (1 << ((Width * 8) - 1));
- if (SignBit) {
- r.Value |= ~((1 << (Width * 8)) - 1);
- } else {
- r.Value &= (1 << (Width * 8)) - 1;
- }
- return r;
+
+ // Ideally the Addend here will be the addend in the data for
+ // the relocation. It's not actually the case for Rel relocations.
+ RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) {
+ int64_t Addend;
+ R.getAdditionalInfo(Addend);
+ return RelocToApply(Value + Addend, 4);
+ }
+
+ RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value,
+ uint64_t SecAddr) {
+ int64_t Addend;
+ R.getAdditionalInfo(Addend);
+ uint64_t Address;
+ R.getAddress(Address);
+ return RelocToApply(Value + Addend - Address, 4);
}
/// X86-64 ELF
@@ -124,6 +166,42 @@ private:
int32_t Res = (Value + Addend) & 0xFFFFFFFF;
return RelocToApply(Res, 4);
}
+
+ /// PPC64 ELF
+ RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) {
+ int64_t Addend;
+ R.getAdditionalInfo(Addend);
+ uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
+ return RelocToApply(Res, 4);
+ }
+
+ /// MIPS ELF
+ RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) {
+ int64_t Addend;
+ R.getAdditionalInfo(Addend);
+ uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
+ return RelocToApply(Res, 4);
+ }
+
+ // AArch64 ELF
+ RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) {
+ int64_t Addend;
+ R.getAdditionalInfo(Addend);
+ int64_t Res = Value + Addend;
+
+ // Overflow check allows for both signed and unsigned interpretation.
+ if (Res < INT32_MIN || Res > UINT32_MAX)
+ HasError = true;
+
+ return RelocToApply(static_cast<uint32_t>(Res), 4);
+ }
+
+ RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) {
+ int64_t Addend;
+ R.getAdditionalInfo(Addend);
+ return RelocToApply(Value + Addend, 8);
+ }
+
};
}