1c5707112e7635d1dd2f2cc9c4f42e79a51302ccaJia Liu//===-- MipsELFObjectWriter.cpp - Mips ELF Writer -------------------------===//
2090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola//
3090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola//                     The LLVM Compiler Infrastructure
4090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola//
5090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola// This file is distributed under the University of Illinois Open Source
6090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola// License. See LICENSE.TXT for details.
7090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola//
8090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola//===----------------------------------------------------------------------===//
9090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
1037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka#include "MCTargetDesc/MipsBaseInfo.h"
11090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola#include "MCTargetDesc/MipsFixupKinds.h"
12090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola#include "MCTargetDesc/MipsMCTargetDesc.h"
1337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka#include "llvm/MC/MCAssembler.h"
14090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola#include "llvm/MC/MCELFObjectWriter.h"
15090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola#include "llvm/MC/MCExpr.h"
16090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola#include "llvm/MC/MCSection.h"
17090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola#include "llvm/MC/MCValue.h"
18090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola#include "llvm/Support/ErrorHandling.h"
1937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka#include <list>
20090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
21090445967f0b5988446faffefd1d0722f982bc7aRafael Espindolausing namespace llvm;
22090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
23090445967f0b5988446faffefd1d0722f982bc7aRafael Espindolanamespace {
2437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  struct RelEntry {
2537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    RelEntry(const ELFRelocationEntry &R, const MCSymbol *S, int64_t O) :
2637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka      Reloc(R), Sym(S), Offset(O) {}
2737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    ELFRelocationEntry Reloc;
2837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    const MCSymbol *Sym;
2937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    int64_t Offset;
3037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  };
3137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
3237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  typedef std::list<RelEntry> RelLs;
3337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  typedef RelLs::iterator RelLsIter;
3437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
35090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  class MipsELFObjectWriter : public MCELFObjectTargetWriter {
36090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  public:
37b889e0cd2fea4afee623d5be603b912b955a2ecaAkira Hatanaka    MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI,
38b889e0cd2fea4afee623d5be603b912b955a2ecaAkira Hatanaka                        bool _isN64, bool IsLittleEndian);
39090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
40090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    virtual ~MipsELFObjectWriter();
41090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
42090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
43090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                  bool IsPCRel, bool IsRelocWithSymbol,
44090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                  int64_t Addend) const;
45090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
46090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           const MCValue &Target,
47090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           const MCFragment &F,
48090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           const MCFixup &Fixup,
49090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           bool IsPCRel) const;
5037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    virtual void sortRelocs(const MCAssembler &Asm,
5137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka                            std::vector<ELFRelocationEntry> &Relocs);
52090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  };
53090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola}
54090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
5593ee286e8d949147f8df7f093c9bd8529a99102dJack CarterMipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI,
56b889e0cd2fea4afee623d5be603b912b955a2ecaAkira Hatanaka                                         bool _isN64, bool IsLittleEndian)
57a551a48402385cf3f4b754dc72264b2f0974b1a6Akira Hatanaka  : MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS,
58101771ba4d9c2421f836069fcedf9ddc8a0c9dc7Jack Carter                            /*HasRelocationAddend*/ (_isN64) ? true : false,
5993ee286e8d949147f8df7f093c9bd8529a99102dJack Carter                            /*IsN64*/ _isN64) {}
60090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
61090445967f0b5988446faffefd1d0722f982bc7aRafael EspindolaMipsELFObjectWriter::~MipsELFObjectWriter() {}
62090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
63090445967f0b5988446faffefd1d0722f982bc7aRafael Espindolaconst MCSymbol *MipsELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
64090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                                    const MCValue &Target,
65090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                                    const MCFragment &F,
66090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                                    const MCFixup &Fixup,
67090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                                    bool IsPCRel) const {
68090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  assert(Target.getSymA() && "SymA cannot be 0.");
692d8955a77c6920d1a50de5ec9094faaa1b2f4e88James Molloy  const MCSymbol &Sym = Target.getSymA()->getSymbol().AliasedSymbol();
70090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
71090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  if (Sym.getSection().getKind().isMergeableCString() ||
72090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola      Sym.getSection().getKind().isMergeableConst())
73090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    return &Sym;
74090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
75090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  return NULL;
76090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola}
77090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
78090445967f0b5988446faffefd1d0722f982bc7aRafael Espindolaunsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target,
79090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           const MCFixup &Fixup,
80090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           bool IsPCRel,
81090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           bool IsRelocWithSymbol,
82090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola                                           int64_t Addend) const {
83090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  // determine the type of the relocation
84090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  unsigned Type = (unsigned)ELF::R_MIPS_NONE;
85090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  unsigned Kind = (unsigned)Fixup.getKind();
86090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
87090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  switch (Kind) {
88090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  default:
89090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    llvm_unreachable("invalid fixup kind!");
90090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case FK_Data_4:
91090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_32;
92090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
93e2245bab3ca29dc2142d8f254005f4ae7c40cde2Jack Carter  case FK_Data_8:
94e2245bab3ca29dc2142d8f254005f4ae7c40cde2Jack Carter    Type = ELF::R_MIPS_64;
95e2245bab3ca29dc2142d8f254005f4ae7c40cde2Jack Carter    break;
96090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case FK_GPRel_4:
97096d617796228293810cb0443c6617b33c5afdc5Jack Carter    if (isN64()) {
98096d617796228293810cb0443c6617b33c5afdc5Jack Carter      Type = setRType((unsigned)ELF::R_MIPS_GPREL32, Type);
99096d617796228293810cb0443c6617b33c5afdc5Jack Carter      Type = setRType2((unsigned)ELF::R_MIPS_64, Type);
100096d617796228293810cb0443c6617b33c5afdc5Jack Carter      Type = setRType3((unsigned)ELF::R_MIPS_NONE, Type);
101096d617796228293810cb0443c6617b33c5afdc5Jack Carter    }
102096d617796228293810cb0443c6617b33c5afdc5Jack Carter    else
103096d617796228293810cb0443c6617b33c5afdc5Jack Carter      Type = ELF::R_MIPS_GPREL32;
104090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
105090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_GPREL16:
106090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_GPREL16;
107090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
108090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_26:
109090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_26;
110090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
111090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_CALL16:
112090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_CALL16;
113090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
114090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_GOT_Global:
115090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_GOT_Local:
116090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_GOT16;
117090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
118090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_HI16:
119090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_HI16;
120090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
121090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_LO16:
122090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_LO16;
123090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
124090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_TLSGD:
125090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_TLS_GD;
126090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
127090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_GOTTPREL:
128090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_TLS_GOTTPREL;
129090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
130090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_TPREL_HI:
131090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_TLS_TPREL_HI16;
132090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
133090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_TPREL_LO:
134090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_TLS_TPREL_LO16;
135090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
136090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_TLSLDM:
137090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_TLS_LDM;
138090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
139090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_DTPREL_HI:
140090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_TLS_DTPREL_HI16;
141090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
142090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_DTPREL_LO:
143090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_TLS_DTPREL_LO16;
144090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
145090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_Branch_PCRel:
146090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  case Mips::fixup_Mips_PC16:
147090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    Type = ELF::R_MIPS_PC16;
148090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola    break;
1490140e55393c4403ab240c386501cdc5e438dcc0eJack Carter  case Mips::fixup_Mips_GOT_PAGE:
1500140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = ELF::R_MIPS_GOT_PAGE;
1510140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    break;
1520140e55393c4403ab240c386501cdc5e438dcc0eJack Carter  case Mips::fixup_Mips_GOT_OFST:
1530140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = ELF::R_MIPS_GOT_OFST;
1540140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    break;
155fd506efec628819f7e6fad8016a9dbb5d8612b8bJack Carter  case Mips::fixup_Mips_GOT_DISP:
156fd506efec628819f7e6fad8016a9dbb5d8612b8bJack Carter    Type = ELF::R_MIPS_GOT_DISP;
157fd506efec628819f7e6fad8016a9dbb5d8612b8bJack Carter    break;
1580140e55393c4403ab240c386501cdc5e438dcc0eJack Carter  case Mips::fixup_Mips_GPOFF_HI:
1590140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type);
1600140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type);
1610140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = setRType3((unsigned)ELF::R_MIPS_HI16, Type);
1620140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    break;
1630140e55393c4403ab240c386501cdc5e438dcc0eJack Carter  case Mips::fixup_Mips_GPOFF_LO:
1640140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type);
1650140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type);
1660140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    Type = setRType3((unsigned)ELF::R_MIPS_LO16, Type);
1670140e55393c4403ab240c386501cdc5e438dcc0eJack Carter    break;
168fc54d9e47a1276650f14f38e7d037c9b58c8dc2dJack Carter  case Mips::fixup_Mips_HIGHER:
169fc54d9e47a1276650f14f38e7d037c9b58c8dc2dJack Carter    Type = ELF::R_MIPS_HIGHER;
170fc54d9e47a1276650f14f38e7d037c9b58c8dc2dJack Carter    break;
171fc54d9e47a1276650f14f38e7d037c9b58c8dc2dJack Carter  case Mips::fixup_Mips_HIGHEST:
172fc54d9e47a1276650f14f38e7d037c9b58c8dc2dJack Carter    Type = ELF::R_MIPS_HIGHEST;
173fc54d9e47a1276650f14f38e7d037c9b58c8dc2dJack Carter    break;
174198ad916d736047f8a439f19dee25cee917df8a9Jack Carter  case Mips::fixup_Mips_GOT_HI16:
175198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    Type = ELF::R_MIPS_GOT_HI16;
176198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    break;
177198ad916d736047f8a439f19dee25cee917df8a9Jack Carter  case Mips::fixup_Mips_GOT_LO16:
178198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    Type = ELF::R_MIPS_GOT_LO16;
179198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    break;
180198ad916d736047f8a439f19dee25cee917df8a9Jack Carter  case Mips::fixup_Mips_CALL_HI16:
181198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    Type = ELF::R_MIPS_CALL_HI16;
182198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    break;
183198ad916d736047f8a439f19dee25cee917df8a9Jack Carter  case Mips::fixup_Mips_CALL_LO16:
184198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    Type = ELF::R_MIPS_CALL_LO16;
185198ad916d736047f8a439f19dee25cee917df8a9Jack Carter    break;
186090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  }
187090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  return Type;
188090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola}
189090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola
19037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka// Return true if R is either a GOT16 against a local symbol or HI16.
19137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanakastatic bool NeedsMatchingLo(const MCAssembler &Asm, const RelEntry &R) {
19237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  if (!R.Sym)
19337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    return false;
19437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
19537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  MCSymbolData &SD = Asm.getSymbolData(R.Sym->AliasedSymbol());
19637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
19737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  return ((R.Reloc.Type == ELF::R_MIPS_GOT16) && !SD.isExternal()) ||
19837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    (R.Reloc.Type == ELF::R_MIPS_HI16);
19937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka}
20037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
20137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanakastatic bool HasMatchingLo(const MCAssembler &Asm, RelLsIter I, RelLsIter Last) {
20237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  if (I == Last)
20337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    return false;
20437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
20537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  RelLsIter Hi = I++;
20637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
20737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  return (I->Reloc.Type == ELF::R_MIPS_LO16) && (Hi->Sym == I->Sym) &&
20837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    (Hi->Offset == I->Offset);
20937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka}
21037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
21137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanakastatic bool HasSameSymbol(const RelEntry &R0, const RelEntry &R1) {
21237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  return R0.Sym == R1.Sym;
21337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka}
21437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
21537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanakastatic int CompareOffset(const RelEntry &R0, const RelEntry &R1) {
21637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  return (R0.Offset > R1.Offset) ? 1 : ((R0.Offset == R1.Offset) ? 0 : -1);
21737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka}
21837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
21937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanakavoid MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
22037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka                                     std::vector<ELFRelocationEntry> &Relocs) {
22193ee286e8d949147f8df7f093c9bd8529a99102dJack Carter  // Call the default function first. Relocations are sorted in descending
22237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  // order of r_offset.
22337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  MCELFObjectTargetWriter::sortRelocs(Asm, Relocs);
224864f66085cd9543070ef01b9f7371c110ecd7898Akira Hatanaka
22537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  RelLs RelocLs;
22637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  std::vector<RelLsIter> Unmatched;
22737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
22837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  // Fill RelocLs. Traverse Relocs backwards so that relocations in RelocLs
22937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  // are in ascending order of r_offset.
23037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  for (std::vector<ELFRelocationEntry>::reverse_iterator R = Relocs.rbegin();
23137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka       R != Relocs.rend(); ++R) {
23237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka     std::pair<const MCSymbolRefExpr*, int64_t> P =
23337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka       MipsGetSymAndOffset(*R->Fixup);
23437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka     RelocLs.push_back(RelEntry(*R, P.first ? &P.first->getSymbol() : 0,
23537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka                                P.second));
23637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  }
23737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
23837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  // Get list of unmatched HI16 and GOT16.
23937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R)
24037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    if (NeedsMatchingLo(Asm, *R) && !HasMatchingLo(Asm, R, --RelocLs.end()))
24137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka      Unmatched.push_back(R);
24237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
24337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  // Insert unmatched HI16 and GOT16 immediately before their matching LO16.
24437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  for (std::vector<RelLsIter>::iterator U = Unmatched.begin();
24537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka       U != Unmatched.end(); ++U) {
24637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    RelLsIter LoPos = RelocLs.end(), HiPos = *U;
24737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    bool MatchedLo = false;
24837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
24937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) {
25037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka      if ((R->Reloc.Type == ELF::R_MIPS_LO16) && HasSameSymbol(*HiPos, *R) &&
25137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka          (CompareOffset(*R, *HiPos) >= 0) &&
25237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka          ((LoPos == RelocLs.end()) || ((CompareOffset(*R, *LoPos) < 0)) ||
25337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka           (!MatchedLo && !CompareOffset(*R, *LoPos))))
25437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka        LoPos = R;
25537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
25637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka      MatchedLo = NeedsMatchingLo(Asm, *R) &&
25737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka        HasMatchingLo(Asm, R, --RelocLs.end());
25837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    }
25937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
26037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    // If a matching LoPos was found, move HiPos and insert it before LoPos.
26137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    // Make the offsets of HiPos and LoPos match.
26237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    if (LoPos != RelocLs.end()) {
26337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka      HiPos->Offset = LoPos->Offset;
26437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka      RelocLs.insert(LoPos, *HiPos);
26537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka      RelocLs.erase(HiPos);
26637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    }
26737ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  }
26837ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
26937ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  // Put the sorted list back in reverse order.
27037ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  assert(Relocs.size() == RelocLs.size());
27137ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  unsigned I = RelocLs.size();
27237ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
27337ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka  for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R)
27437ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka    Relocs[--I] = R->Reloc;
27537ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka}
27637ac18ef2f13a8060b745e6d3c4622bafdd4f47bAkira Hatanaka
277a551a48402385cf3f4b754dc72264b2f0974b1a6Akira HatanakaMCObjectWriter *llvm::createMipsELFObjectWriter(raw_ostream &OS,
278a551a48402385cf3f4b754dc72264b2f0974b1a6Akira Hatanaka                                                uint8_t OSABI,
279a551a48402385cf3f4b754dc72264b2f0974b1a6Akira Hatanaka                                                bool IsLittleEndian,
280a551a48402385cf3f4b754dc72264b2f0974b1a6Akira Hatanaka                                                bool Is64Bit) {
28193ee286e8d949147f8df7f093c9bd8529a99102dJack Carter  MCELFObjectTargetWriter *MOTW = new MipsELFObjectWriter(Is64Bit, OSABI,
282b889e0cd2fea4afee623d5be603b912b955a2ecaAkira Hatanaka                                                (Is64Bit) ? true : false,
283b889e0cd2fea4afee623d5be603b912b955a2ecaAkira Hatanaka                                                IsLittleEndian);
284090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola  return createELFObjectWriter(MOTW, OS, IsLittleEndian);
285090445967f0b5988446faffefd1d0722f982bc7aRafael Espindola}
286