diff options
Diffstat (limited to 'llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp')
-rw-r--r-- | llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp index 7fdbb8990b55..d672d54772e0 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp @@ -7,16 +7,26 @@ // //===----------------------------------------------------------------------===// -#include "PPCMCTargetDesc.h" +#include "MCTargetDesc/PPCFixupKinds.h" +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCValue.h" #include "llvm/MC/MCXCOFFObjectWriter.h" using namespace llvm; namespace { class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter { + static constexpr uint8_t SignBitMask = 0x80; public: PPCXCOFFObjectWriter(bool Is64Bit); + + std::pair<uint8_t, uint8_t> + getRelocTypeAndSignSize(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel) const override; }; } // end anonymous namespace @@ -27,3 +37,40 @@ std::unique_ptr<MCObjectTargetWriter> llvm::createPPCXCOFFObjectWriter(bool Is64Bit) { return std::make_unique<PPCXCOFFObjectWriter>(Is64Bit); } + +std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize( + const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { + const MCSymbolRefExpr::VariantKind Modifier = + Target.isAbsolute() ? MCSymbolRefExpr::VK_None + : Target.getSymA()->getKind(); + // People from AIX OS team says AIX link editor does not care about + // the sign bit in the relocation entry "most" of the time. + // The system assembler seems to set the sign bit on relocation entry + // based on similar property of IsPCRel. So we will do the same here. + // TODO: More investigation on how assembler decides to set the sign + // bit, and we might want to match that. + const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u; + + // The magic number we use in SignAndSize has a strong relationship with + // the corresponding MCFixupKind. In most cases, it's the MCFixupKind + // number - 1, because SignAndSize encodes the bit length being + // relocated minus 1. + switch ((unsigned)Fixup.getKind()) { + default: + report_fatal_error("Unimplemented fixup kind."); + case PPC::fixup_ppc_half16: + switch (Modifier) { + default: + report_fatal_error("Unsupported modifier for half16 fixup."); + case MCSymbolRefExpr::VK_None: + return {XCOFF::RelocationType::R_TOC, EncodedSignednessIndicator | 15}; + } + break; + case PPC::fixup_ppc_br24: + // Branches are 4 byte aligned, so the 24 bits we encode in + // the instruction actually represents a 26 bit offset. + return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25}; + case FK_Data_4: + return {XCOFF::RelocationType::R_POS, EncodedSignednessIndicator | 31}; + } +} |