1//===-- PPCELFObjectWriter.cpp - PPC ELF Writer ---------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "MCTargetDesc/PPCFixupKinds.h"
11#include "MCTargetDesc/PPCMCTargetDesc.h"
12#include "llvm/MC/MCELFObjectWriter.h"
13#include "llvm/Support/ErrorHandling.h"
14
15using namespace llvm;
16
17namespace {
18  class PPCELFObjectWriter : public MCELFObjectTargetWriter {
19  public:
20    PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI);
21
22    virtual ~PPCELFObjectWriter();
23  protected:
24    virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
25                                  bool IsPCRel, bool IsRelocWithSymbol,
26                                  int64_t Addend) const;
27    virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset);
28  };
29}
30
31PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)
32  : MCELFObjectTargetWriter(Is64Bit, OSABI,
33                            Is64Bit ?  ELF::EM_PPC64 : ELF::EM_PPC,
34                            /*HasRelocationAddend*/ true) {}
35
36PPCELFObjectWriter::~PPCELFObjectWriter() {
37}
38
39unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
40                                             const MCFixup &Fixup,
41                                             bool IsPCRel,
42                                             bool IsRelocWithSymbol,
43                                             int64_t Addend) const {
44  // determine the type of the relocation
45  unsigned Type;
46  if (IsPCRel) {
47    switch ((unsigned)Fixup.getKind()) {
48    default:
49      llvm_unreachable("Unimplemented");
50    case PPC::fixup_ppc_br24:
51      Type = ELF::R_PPC_REL24;
52      break;
53    case FK_PCRel_4:
54      Type = ELF::R_PPC_REL32;
55      break;
56    }
57  } else {
58    switch ((unsigned)Fixup.getKind()) {
59      default: llvm_unreachable("invalid fixup kind!");
60    case PPC::fixup_ppc_br24:
61      Type = ELF::R_PPC_ADDR24;
62      break;
63    case PPC::fixup_ppc_brcond14:
64      Type = ELF::R_PPC_ADDR14_BRTAKEN; // XXX: or BRNTAKEN?_
65      break;
66    case PPC::fixup_ppc_ha16:
67      Type = ELF::R_PPC_ADDR16_HA;
68      break;
69    case PPC::fixup_ppc_lo16:
70      Type = ELF::R_PPC_ADDR16_LO;
71      break;
72    case PPC::fixup_ppc_lo14:
73      Type = ELF::R_PPC_ADDR14;
74      break;
75    case FK_Data_4:
76      Type = ELF::R_PPC_ADDR32;
77      break;
78    case FK_Data_2:
79      Type = ELF::R_PPC_ADDR16;
80      break;
81    }
82  }
83  return Type;
84}
85
86void PPCELFObjectWriter::
87adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) {
88  switch ((unsigned)Fixup.getKind()) {
89    case PPC::fixup_ppc_ha16:
90    case PPC::fixup_ppc_lo16:
91      RelocOffset += 2;
92      break;
93    default:
94      break;
95  }
96}
97
98MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS,
99                                               bool Is64Bit,
100                                               uint8_t OSABI) {
101  MCELFObjectTargetWriter *MOTW = new PPCELFObjectWriter(Is64Bit, OSABI);
102  return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/false);
103}
104