X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FObject%2FRelocVisitor.h;h=91eafd55ad766a49099e28ebfbdff6feca183fe4;hb=7db332b8ea60d254aac4790f38191ffd7f3c5323;hp=17e52edd5dc8bed87de9ec28e443c501303d5980;hpb=1fcbb8fbf96b24ca7c16b993eccd68b0d61dc8a3;p=oota-llvm.git diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h index 17e52edd5dc..91eafd55ad7 100644 --- a/include/llvm/Object/RelocVisitor.h +++ b/include/llvm/Object/RelocVisitor.h @@ -13,14 +13,16 @@ // //===----------------------------------------------------------------------===// -#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/COFF.h" +#include "llvm/Object/ELFObjectFile.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 { @@ -32,7 +34,6 @@ struct RelocToApply { // The width of the value; how many bytes to touch when applying the // relocation. char Width; - RelocToApply(const RelocToApply &In) : Value(In.Value), Width(In.Width) {} RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {} RelocToApply() : Value(0), Width(0) {} }; @@ -40,22 +41,39 @@ struct RelocToApply { /// @brief Base class for object file relocation visitors. class RelocVisitor { public: - explicit RelocVisitor(llvm::StringRef FileFormat) - : FileFormat(FileFormat), HasError(false) {} + explicit RelocVisitor(const ObjectFile &Obj) + : ObjToVisit(Obj), HasError(false) {} // TODO: Should handle multiple applied relocations via either passing in the // previously computed value or just count paired relocations as a single // visit. - RelocToApply visit(uint32_t RelocType, RelocationRef R, uint64_t SecAddr = 0, - uint64_t Value = 0) { - if (FileFormat == "ELF64-x86-64") { - switch (RelocType) { + RelocToApply visit(uint32_t RelocType, RelocationRef R, uint64_t Value = 0) { + if (isa(ObjToVisit)) + return visitELF(RelocType, R, Value); + if (isa(ObjToVisit)) + return visitCOFF(RelocType, R, Value); + + HasError = true; + return RelocToApply(); + } + + bool error() { return HasError; } + +private: + const ObjectFile &ObjToVisit; + bool HasError; + + RelocToApply visitELF(uint32_t RelocType, RelocationRef R, uint64_t Value) { + if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file + switch (ObjToVisit.getArch()) { + case Triple::x86_64: + switch (RelocType) { case llvm::ELF::R_X86_64_NONE: return visitELF_X86_64_NONE(R); case llvm::ELF::R_X86_64_64: return visitELF_X86_64_64(R, Value); case llvm::ELF::R_X86_64_PC32: - return visitELF_X86_64_PC32(R, Value, SecAddr); + return visitELF_X86_64_PC32(R, Value); case llvm::ELF::R_X86_64_32: return visitELF_X86_64_32(R, Value); case llvm::ELF::R_X86_64_32S: @@ -63,36 +81,196 @@ public: default: HasError = true; return RelocToApply(); + } + case Triple::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(); + } + case Triple::mips64el: + case Triple::mips64: + switch (RelocType) { + case llvm::ELF::R_MIPS_32: + return visitELF_MIPS_32(R, Value); + case llvm::ELF::R_MIPS_64: + return visitELF_MIPS_64(R, Value); + default: + HasError = true; + return RelocToApply(); + } + case Triple::ppc64le: + case Triple::ppc64: + switch (RelocType) { + case llvm::ELF::R_PPC64_ADDR32: + return visitELF_PPC64_ADDR32(R, Value); + case llvm::ELF::R_PPC64_ADDR64: + return visitELF_PPC64_ADDR64(R, Value); + default: + HasError = true; + return RelocToApply(); + } + case Triple::systemz: + switch (RelocType) { + case llvm::ELF::R_390_32: + return visitELF_390_32(R, Value); + case llvm::ELF::R_390_64: + return visitELF_390_64(R, Value); + default: + HasError = true; + return RelocToApply(); + } + case Triple::sparcv9: + switch (RelocType) { + case llvm::ELF::R_SPARC_32: + case llvm::ELF::R_SPARC_UA32: + return visitELF_SPARCV9_32(R, Value); + case llvm::ELF::R_SPARC_64: + case llvm::ELF::R_SPARC_UA64: + return visitELF_SPARCV9_64(R, Value); + default: + HasError = true; + return RelocToApply(); + } + default: + HasError = true; + return RelocToApply(); } + } else if (ObjToVisit.getBytesInAddress() == 4) { // 32-bit object file + switch (ObjToVisit.getArch()) { + case Triple::x86: + 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); + default: + HasError = true; + return RelocToApply(); + } + case Triple::ppc: + switch (RelocType) { + case llvm::ELF::R_PPC_ADDR32: + return visitELF_PPC_ADDR32(R, Value); + default: + HasError = true; + return RelocToApply(); + } + case Triple::arm: + case Triple::armeb: + switch (RelocType) { + default: + HasError = true; + return RelocToApply(); + case llvm::ELF::R_ARM_ABS32: + return visitELF_ARM_ABS32(R, Value); + } + case Triple::mipsel: + case Triple::mips: + switch (RelocType) { + case llvm::ELF::R_MIPS_32: + return visitELF_MIPS_32(R, Value); + default: + HasError = true; + return RelocToApply(); + } + case Triple::sparc: + switch (RelocType) { + case llvm::ELF::R_SPARC_32: + case llvm::ELF::R_SPARC_UA32: + return visitELF_SPARC_32(R, Value); + default: + HasError = true; + return RelocToApply(); + } + default: + HasError = true; + return RelocToApply(); + } + } else { + report_fatal_error("Invalid word size in object file"); } + } + + RelocToApply visitCOFF(uint32_t RelocType, RelocationRef R, uint64_t Value) { + switch (ObjToVisit.getArch()) { + case Triple::x86: + switch (RelocType) { + case COFF::IMAGE_REL_I386_SECREL: + return visitCOFF_I386_SECREL(R, Value); + case COFF::IMAGE_REL_I386_DIR32: + return visitCOFF_I386_DIR32(R, Value); + } + break; + case Triple::x86_64: + switch (RelocType) { + case COFF::IMAGE_REL_AMD64_SECREL: + return visitCOFF_AMD64_SECREL(R, Value); + case COFF::IMAGE_REL_AMD64_ADDR64: + return visitCOFF_AMD64_ADDR64(R, Value); + } + break; + } + HasError = true; return RelocToApply(); } - bool error() { return HasError; } + int64_t getELFAddend32LE(RelocationRef R) { + const ELF32LEObjectFile *Obj = cast(R.getObjectFile()); + DataRefImpl DRI = R.getRawDataRefImpl(); + int64_t Addend; + Obj->getRelocationAddend(DRI, Addend); + return Addend; + } -private: - llvm::StringRef FileFormat; - bool HasError; + int64_t getELFAddend64LE(RelocationRef R) { + const ELF64LEObjectFile *Obj = cast(R.getObjectFile()); + DataRefImpl DRI = R.getRawDataRefImpl(); + int64_t Addend; + Obj->getRelocationAddend(DRI, Addend); + return Addend; + } + + int64_t getELFAddend32BE(RelocationRef R) { + const ELF32BEObjectFile *Obj = cast(R.getObjectFile()); + DataRefImpl DRI = R.getRawDataRefImpl(); + int64_t Addend; + Obj->getRelocationAddend(DRI, Addend); + return Addend; + } + int64_t getELFAddend64BE(RelocationRef R) { + const ELF64BEObjectFile *Obj = cast(R.getObjectFile()); + DataRefImpl DRI = R.getRawDataRefImpl(); + int64_t Addend; + Obj->getRelocationAddend(DRI, Addend); + return Addend; + } /// Operations - // Width is the width in bytes of the extend. - RelocToApply zeroExtend(RelocToApply r, char Width) { - if (Width == r.Width) - return r; - r.Value &= (1LL << ((Width * 8))) - 1; - return r; - } - RelocToApply signExtend(RelocToApply r, char Width) { - if (Width == r.Width) - return r; - bool SignBit = r.Value & (1LL << ((Width * 8) - 1)); - if (SignBit) { - r.Value |= ~((1LL << (Width * 8)) - 1); - } else { - r.Value &= (1LL << (Width * 8)) - 1; - } - return r; + /// 386-ELF + RelocToApply visitELF_386_NONE(RelocationRef R) { + return RelocToApply(0, 0); + } + + // 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 = getELFAddend32LE(R); + return RelocToApply(Value + Addend, 4); + } + + RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend32LE(R); + uint64_t Address; + R.getOffset(Address); + return RelocToApply(Value + Addend - Address, 4); } /// X86-64 ELF @@ -100,30 +278,141 @@ private: return RelocToApply(0, 0); } RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) { - int64_t Addend; - R.getAdditionalInfo(Addend); + int64_t Addend = getELFAddend64LE(R); return RelocToApply(Value + Addend, 8); } - RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value, - uint64_t SecAddr) { - int64_t Addend; - R.getAdditionalInfo(Addend); + RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend64LE(R); uint64_t Address; - R.getAddress(Address); + R.getOffset(Address); return RelocToApply(Value + Addend - Address, 4); } RelocToApply visitELF_X86_64_32(RelocationRef R, uint64_t Value) { - int64_t Addend; - R.getAdditionalInfo(Addend); + int64_t Addend = getELFAddend64LE(R); uint32_t Res = (Value + Addend) & 0xFFFFFFFF; return RelocToApply(Res, 4); } RelocToApply visitELF_X86_64_32S(RelocationRef R, uint64_t Value) { - int64_t Addend; - R.getAdditionalInfo(Addend); + int64_t Addend = getELFAddend64LE(R); int32_t Res = (Value + Addend) & 0xFFFFFFFF; return RelocToApply(Res, 4); } + + /// PPC64 ELF + RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) { + int64_t Addend; + getELFRelocationAddend(R, Addend); + uint32_t Res = (Value + Addend) & 0xFFFFFFFF; + return RelocToApply(Res, 4); + } + RelocToApply visitELF_PPC64_ADDR64(RelocationRef R, uint64_t Value) { + int64_t Addend; + getELFRelocationAddend(R, Addend); + return RelocToApply(Value + Addend, 8); + } + + /// PPC32 ELF + RelocToApply visitELF_PPC_ADDR32(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend32BE(R); + uint32_t Res = (Value + Addend) & 0xFFFFFFFF; + return RelocToApply(Res, 4); + } + + /// MIPS ELF + RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) { + int64_t Addend; + getELFRelocationAddend(R, Addend); + uint32_t Res = (Value + Addend) & 0xFFFFFFFF; + return RelocToApply(Res, 4); + } + + RelocToApply visitELF_MIPS_64(RelocationRef R, uint64_t Value) { + int64_t Addend; + getELFRelocationAddend(R, Addend); + uint64_t Res = (Value + Addend); + return RelocToApply(Res, 8); + } + + // AArch64 ELF + RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) { + int64_t Addend; + getELFRelocationAddend(R, 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(Res), 4); + } + + RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) { + int64_t Addend; + getELFRelocationAddend(R, Addend); + return RelocToApply(Value + Addend, 8); + } + + // SystemZ ELF + RelocToApply visitELF_390_32(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend64BE(R); + 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(Res), 4); + } + + RelocToApply visitELF_390_64(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend64BE(R); + return RelocToApply(Value + Addend, 8); + } + + RelocToApply visitELF_SPARC_32(RelocationRef R, uint32_t Value) { + int32_t Addend = getELFAddend32BE(R); + return RelocToApply(Value + Addend, 4); + } + + RelocToApply visitELF_SPARCV9_32(RelocationRef R, uint64_t Value) { + int32_t Addend = getELFAddend64BE(R); + return RelocToApply(Value + Addend, 4); + } + + RelocToApply visitELF_SPARCV9_64(RelocationRef R, uint64_t Value) { + int64_t Addend = getELFAddend64BE(R); + return RelocToApply(Value + Addend, 8); + } + + RelocToApply visitELF_ARM_ABS32(RelocationRef R, uint64_t Value) { + int64_t Addend; + getELFRelocationAddend(R, 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(Res), 4); + } + + /// I386 COFF + RelocToApply visitCOFF_I386_SECREL(RelocationRef R, uint64_t Value) { + return RelocToApply(static_cast(Value), /*Width=*/4); + } + + RelocToApply visitCOFF_I386_DIR32(RelocationRef R, uint64_t Value) { + return RelocToApply(static_cast(Value), /*Width=*/4); + } + + /// AMD64 COFF + RelocToApply visitCOFF_AMD64_SECREL(RelocationRef R, uint64_t Value) { + return RelocToApply(static_cast(Value), /*Width=*/4); + } + + RelocToApply visitCOFF_AMD64_ADDR64(RelocationRef R, uint64_t Value) { + return RelocToApply(Value, /*Width=*/8); + } }; }