diff options
Diffstat (limited to 'include/llvm/Object/RelocVisitor.h')
-rw-r--r-- | include/llvm/Object/RelocVisitor.h | 124 |
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); + } + }; } |