MipsAsmBackend.cpp revision 47b92f3d8362518596d57269dc53d985bc13323a
1//===-- MipsASMBackend.cpp -  ---------===//
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// This file implements the MipsAsmBackend and MipsELFObjectWriter classes.
11//
12//===----------------------------------------------------------------------===//
13//
14
15#include "MipsFixupKinds.h"
16#include "MCTargetDesc/MipsMCTargetDesc.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/MC/MCAsmBackend.h"
19#include "llvm/MC/MCAssembler.h"
20#include "llvm/MC/MCDirectives.h"
21#include "llvm/MC/MCELFObjectWriter.h"
22#include "llvm/MC/MCExpr.h"
23#include "llvm/MC/MCMachObjectWriter.h"
24#include "llvm/MC/MCObjectWriter.h"
25#include "llvm/MC/MCSectionELF.h"
26#include "llvm/MC/MCSectionMachO.h"
27#include "llvm/MC/MCSubtargetInfo.h"
28#include "llvm/Object/MachOFormat.h"
29#include "llvm/Support/ELF.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/raw_ostream.h"
32using namespace llvm;
33
34static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
35
36  // Add/subtract and shift
37  switch (Kind) {
38  default:
39    break;
40  case Mips::fixup_Mips_PC16:
41    // So far we are only using this type for branches.
42    // For branches we start 1 instruction after the branch
43    // so the displacement will be one instruction size less.
44    Value -= 4;
45    // The displacement is then divided by 4 to give us an 18 bit
46    // address range.
47    Value >>= 2;
48    break;
49  case Mips::fixup_Mips_26:
50    // So far we are only using this type for jumps.
51    // The displacement is then divided by 4 to give us an 28 bit
52    // address range.
53    Value >>= 2;
54    break;
55  }
56
57  // Mask off value for placement as an operand
58  switch (Kind) {
59  default:
60    break;
61  case FK_Data_4:
62    Value &= 0xffffffff;
63    break;
64  case Mips::fixup_Mips_26:
65    Value &= 0x03ffffff;
66    break;
67  case Mips::fixup_Mips_LO16:
68  case Mips::fixup_Mips_PC16:
69    Value &= 0x0000ffff;
70    break;
71  }
72
73  return Value;
74}
75
76namespace {
77
78class MipsELFObjectWriter : public MCELFObjectTargetWriter {
79public:
80  MipsELFObjectWriter(bool is64Bit, Triple::OSType OSType, uint16_t EMachine,
81                      bool HasRelocationAddend)
82    : MCELFObjectTargetWriter(is64Bit, OSType, EMachine,
83                              HasRelocationAddend) {}
84};
85
86class MipsAsmBackend : public MCAsmBackend {
87public:
88  MipsAsmBackend(const Target &T) : MCAsmBackend() {}
89
90  /// ApplyFixup - Apply the \arg Value for given \arg Fixup into the provided
91  /// data fragment, at the offset specified by the fixup and following the
92  /// fixup kind as appropriate.
93  void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
94                  uint64_t Value) const {
95    unsigned Kind = (unsigned)Fixup.getKind();
96    Value = adjustFixupValue(Kind, Value);
97
98    if (!Value)
99      return;           // Doesn't change encoding.
100
101    unsigned Offset = Fixup.getOffset();
102    switch (Kind) {
103    default:
104      llvm_unreachable("Unknown fixup kind!");
105    case Mips::fixup_Mips_GOT16: // This will be fixed up at link time
106     break;
107    case FK_Data_4:
108    case Mips::fixup_Mips_26:
109    case Mips::fixup_Mips_LO16:
110    case Mips::fixup_Mips_PC16:
111      // For each byte of the fragment that the fixup touches, mask i
112      // the fixup value. The Value has been "split up" into the appr
113      // bitfields above.
114      for (unsigned i = 0; i != 4; ++i) // FIXME - Need to support 2 and 8 bytes
115        Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
116      break;
117    }
118  }
119
120  unsigned getNumFixupKinds() const { return Mips::NumTargetFixupKinds; }
121
122  const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
123    const static MCFixupKindInfo Infos[Mips::NumTargetFixupKinds] = {
124      // This table *must* be in the order that the fixup_* kinds a
125      // MipsFixupKinds.h.
126      //
127      // name                    offset  bits  flags
128      { "fixup_Mips_NONE",         0,      0,   0 },
129      { "fixup_Mips_16",           0,     16,   0 },
130      { "fixup_Mips_32",           0,     32,   0 },
131      { "fixup_Mips_REL32",        0,     32,   0 },
132      { "fixup_Mips_26",           0,     26,   0 },
133      { "fixup_Mips_HI16",         0,     16,   0 },
134      { "fixup_Mips_LO16",         0,     16,   0 },
135      { "fixup_Mips_GPREL16",      0,     16,   0 },
136      { "fixup_Mips_LITERAL",      0,     16,   0 },
137      { "fixup_Mips_GOT16",        0,     16,   0 },
138      { "fixup_Mips_PC16",         0,     16,  MCFixupKindInfo::FKF_IsPCRel },
139      { "fixup_Mips_CALL16",       0,     16,   0 },
140      { "fixup_Mips_GPREL32",      0,     32,   0 },
141      { "fixup_Mips_SHIFT5",       6,      5,   0 },
142      { "fixup_Mips_SHIFT6",       6,      5,   0 },
143      { "fixup_Mips_64",           0,     64,   0 },
144      { "fixup_Mips_TLSGD",        0,     16,   0 },
145      { "fixup_Mips_GOTTPREL",     0,     16,   0 },
146      { "fixup_Mips_TPREL_HI",     0,     16,   0 },
147      { "fixup_Mips_TPREL_LO",     0,     16,   0 },
148      { "fixup_Mips_Branch_PCRel", 0,     16,  MCFixupKindInfo::FKF_IsPCRel }
149    };
150
151    if (Kind < FirstTargetFixupKind)
152      return MCAsmBackend::getFixupKindInfo(Kind);
153
154    assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
155           "Invalid kind!");
156    return Infos[Kind - FirstTargetFixupKind];
157  }
158
159  /// @name Target Relaxation Interfaces
160  /// @{
161
162  /// MayNeedRelaxation - Check whether the given instruction may need
163  /// relaxation.
164  ///
165  /// \param Inst - The instruction to test.
166  bool MayNeedRelaxation(const MCInst &Inst) const {
167    return false;
168  }
169
170  /// RelaxInstruction - Relax the instruction in the given fragment
171  /// to the next wider instruction.
172  ///
173  /// \param Inst - The instruction to relax, which may be the same
174  /// as the output.
175  /// \parm Res [output] - On return, the relaxed instruction.
176  void RelaxInstruction(const MCInst &Inst, MCInst &Res) const {
177  }
178
179  /// @}
180
181  /// WriteNopData - Write an (optimal) nop sequence of Count bytes
182  /// to the given output. If the target cannot generate such a sequence,
183  /// it should return an error.
184  ///
185  /// \return - True on success.
186  bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const {
187    return true;
188  }
189};
190
191class MipsEB_AsmBackend : public MipsAsmBackend {
192public:
193  Triple::OSType OSType;
194
195  MipsEB_AsmBackend(const Target &T, Triple::OSType _OSType)
196    : MipsAsmBackend(T), OSType(_OSType) {}
197
198  MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
199    return createELFObjectWriter(createELFObjectTargetWriter(),
200                                 OS, /*IsLittleEndian*/ false);
201  }
202
203  MCELFObjectTargetWriter *createELFObjectTargetWriter() const {
204    return new MipsELFObjectWriter(false, OSType, ELF::EM_MIPS, false);
205  }
206};
207
208class MipsEL_AsmBackend : public MipsAsmBackend {
209public:
210  Triple::OSType OSType;
211
212  MipsEL_AsmBackend(const Target &T, Triple::OSType _OSType)
213    : MipsAsmBackend(T), OSType(_OSType) {}
214
215  MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
216    return createELFObjectWriter(createELFObjectTargetWriter(),
217                                 OS, /*IsLittleEndian*/ true);
218  }
219
220  MCELFObjectTargetWriter *createELFObjectTargetWriter() const {
221    return new MipsELFObjectWriter(false, OSType, ELF::EM_MIPS, false);
222  }
223};
224} // namespace
225
226MCAsmBackend *llvm::createMipsAsmBackend(const Target &T, StringRef TT) {
227  Triple TheTriple(TT);
228
229  // just return little endian for now
230  //
231  return new MipsEL_AsmBackend(T, Triple(TT).getOS());
232}
233