MipsRelocator.cpp revision d0fbbb227051be16931a1aa9b4a7722ac039c698
1d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao//===- MipsRelocator.cpp  -----------------------------------------===//
25460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//
35460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//                     The MCLinker Project
45460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//
55460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// This file is distributed under the University of Illinois Open Source
65460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// License. See LICENSE.TXT for details.
75460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//
85460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//===----------------------------------------------------------------------===//
95460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <llvm/ADT/Twine.h>
115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <llvm/Support/ELF.h>
1222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <mcld/Fragment/FragmentLinker.h>
13affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include <mcld/Support/MsgHandling.h>
1422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include <mcld/Target/OutputRelocSection.h>
155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
16d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao#include "MipsRelocator.h"
175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "MipsRelocationFunctions.h"
185460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaousing namespace mcld;
205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2167e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao//===----------------------------------------------------------------------===//
2267e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao// Relocation Functions and Tables
2367e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao//===----------------------------------------------------------------------===//
245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei LiaoDECL_MIPS_APPLY_RELOC_FUNCS
255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2667e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao/// the prototype of applying function
27d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liaotypedef Relocator::Result (*ApplyFunctionType)(Relocation&, MipsRelocator&);
2867e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao
2967e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao// the table entry of applying functions
3067e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liaostruct ApplyFunctionTriple
3167e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao{
3267e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  ApplyFunctionType func;
3367e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  unsigned int type;
3467e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  const char* name;
3567e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao};
3667e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao
3767e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao// declare the table of applying functions
3867e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liaostatic const ApplyFunctionTriple ApplyFunctions[] = {
3967e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  DECL_MIPS_APPLY_RELOC_FUNC_PTRS
4067e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao};
4167e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao
4267e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao//===----------------------------------------------------------------------===//
43d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao// MipsRelocator
4467e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao//===----------------------------------------------------------------------===//
45d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::MipsRelocator(MipsGNULDBackend& pParent)
46d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  : Relocator(),
475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    m_Target(pParent),
485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    m_AHL(0)
495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
52d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoRelocator::Result
53d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::applyRelocation(Relocation& pRelocation)
545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  Relocation::Type type = pRelocation.type();
575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
5867e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  if (type >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) {
5967e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao    return Unknown;
605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // apply the relocation
6322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return ApplyFunctions[type].func(pRelocation, *this);
6467e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao}
655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
66d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liaoconst char* MipsRelocator::getName(Relocation::Type pType) const
6767e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao{
6867e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao  return ApplyFunctions[pType].name;
695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
7167e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao//===----------------------------------------------------------------------===//
7267e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao// Relocation helper function
735460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
7467e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao//===----------------------------------------------------------------------===//
755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic const char * const GP_DISP_NAME = "_gp_disp";
765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// Find next R_MIPS_LO16 relocation paired to pReloc.
785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei LiaoRelocation* helper_FindLo16Reloc(Relocation& pReloc)
805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode());
825460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  while (NULL != reloc)
835460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  {
845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (llvm::ELF::R_MIPS_LO16 == reloc->type() &&
855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        reloc->symInfo() == pReloc.symInfo())
865460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      return reloc;
875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    reloc = static_cast<Relocation*>(reloc->getNextNode());
895460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  return NULL;
915460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// Check the symbol is _gp_disp.
945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaobool helper_isGpDisp(const Relocation& pReloc)
965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  const ResolveInfo* rsym = pReloc.symInfo();
985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  return 0 == strcmp(GP_DISP_NAME, rsym->name());
995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1005460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1015460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
102d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoRelocator::Address helper_GetGP(MipsRelocator& pParent)
1035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
10422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return pParent.getTarget().getGOT().addr() + 0x7FF0;
1055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1075460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
108d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsGOTEntry& helper_GetGOTEntry(Relocation& pReloc,
109d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao                                 MipsRelocator& pParent,
110d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao                                 bool& pExist, int32_t value)
1115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
1125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // rsym - The relocation target symbol
1135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
1145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  MipsGNULDBackend& ld_backend = pParent.getTarget();
115affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  MipsGOT& got = ld_backend.getGOT();
1165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
11722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (got.isLocal(rsym) && ResolveInfo::Section == rsym->type()) {
11822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // Local section symbols consume local got entries.
11922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    return *got.consumeLocal();
12022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
12122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
122d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  MipsGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
12322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (NULL != got_entry) {
12422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    // found a mapping, then return the mapped entry immediately
12522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    return *got_entry;
12622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
1275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
12822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  // not found
12922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (got.isLocal(rsym))
13022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    got_entry = got.consumeLocal();
13122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  else
13222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    got_entry = got.consumeGlobal();
13322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
13422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  pParent.getSymGOTMap().record(*rsym, *got_entry);
1355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1365460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // If we first get this GOT entry, we should initialize it.
13722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
138d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao    got_entry->setValue(pReloc.symValue());
13922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  }
14022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  else {
14122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    fatal(diag::reserve_entry_number_mismatch_got);
1425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
1435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
14422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return *got_entry;
1455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
148d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoRelocator::Address helper_GetGOTOffset(Relocation& pReloc,
149d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao                                       MipsRelocator& pParent)
1505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
151affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  bool exist;
152d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, 0);
15322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return got_entry.getOffset() - 0x7FF0;
1545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
1575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaoint32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc)
1585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
1595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 ||
1605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao          pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) &&
1615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao         pLoReloc.type() == llvm::ELF::R_MIPS_LO16 &&
1625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao         "Incorrect type of relocation for AHL calculation");
1635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // Note the addend is section symbol offset here
1655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  assert (pHiReloc.addend() == pLoReloc.addend());
1665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  int32_t AHI = pHiReloc.target();
1685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  int32_t ALO = pLoReloc.target();
16922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) +
17022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao                 pLoReloc.addend();
1715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  return AHL;
1725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1735460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1745460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
175d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liaovoid helper_DynRel(Relocation& pReloc, MipsRelocator& pParent)
1765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
1775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
1785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  MipsGNULDBackend& ld_backend = pParent.getTarget();
179affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  MipsGOT& got = ld_backend.getGOT();
1805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
18122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
1825460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1835460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  rel_entry.setType(llvm::ELF::R_MIPS_REL32);
1845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  rel_entry.targetRef() = pReloc.targetRef();
185affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
186d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::DWord A = pReloc.target() + pReloc.addend();
187d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::DWord S = pReloc.symValue();
188affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
189affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (got.isLocal(rsym)) {
190affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    rel_entry.setSymInfo(NULL);
191affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    pReloc.target() = A + S;
192affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
193affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  else {
194affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    rel_entry.setSymInfo(rsym);
195affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // Don't add symbol value that will be resolved by the dynamic linker
196affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    pReloc.target() = A;
197affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
1985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2005460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//=========================================//
2015460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// Relocation functions implementation     //
2025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//=========================================//
2035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_MIPS_NONE and those unsupported/deprecated relocation type
2055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
206d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result none(Relocation& pReloc, MipsRelocator& pParent)
2075460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
208d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
2095460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_MIPS_32: S + A
2125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
213d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result abs32(Relocation& pReloc, MipsRelocator& pParent)
2145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
2155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
2165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
217d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::DWord A = pReloc.target() + pReloc.addend();
218d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::DWord S = pReloc.symValue();
219affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
22022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
221affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // If the flag of target section is not ALLOC, we will not scan this relocation
222affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // but perform static relocation. (e.g., applying .debug section)
22322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
224affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    pReloc.target() = S + A;
225d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao    return MipsRelocator::OK;
226affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
227affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
2285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
2295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    helper_DynRel(pReloc, pParent);
2305460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
231d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao    return MipsRelocator::OK;
232affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
2335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
234affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  pReloc.target() = (S + A);
2355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
236d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
2375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2385460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2395460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_MIPS_HI16:
2405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//   local/external: ((AHL + S) - (short)(AHL + S)) >> 16
2415460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//   _gp_disp      : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
2425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
243d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result hi16(Relocation& pReloc, MipsRelocator& pParent)
2445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
2455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
2465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16");
2475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
2495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  int32_t res = 0;
2505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pParent.setAHL(AHL);
2525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  if (helper_isGpDisp(pReloc)) {
25422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    int32_t P = pReloc.place();
2555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t GP = helper_GetGP(pParent);
2565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
2575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
2585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  else {
2595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t S = pReloc.symValue();
2605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    res = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
2615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
2625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() &= 0xFFFF0000;
2645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() |= (res & 0xFFFF);
2655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
266d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
2675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_MIPS_LO16:
2705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//   local/external: AHL + S
2715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//   _gp_disp      : AHL + GP - P + 4
2725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
273d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result lo16(Relocation& pReloc, MipsRelocator& pParent)
2745460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
2755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  int32_t res = 0;
2765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  if (helper_isGpDisp(pReloc)) {
27822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    int32_t P = pReloc.place();
2795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t GP = helper_GetGP(pParent);
280affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    int32_t AHL = pParent.getAHL();
2815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    res = AHL + GP - P + 4;
2825460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
2835460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  else {
2845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t S = pReloc.symValue();
285affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // The previous AHL may be for other hi/lo pairs.
286affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // We need to calcuate the lo part now.  It is easy.
287affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    // Remember to add the section offset to ALO.
288affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend();
289affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    res = ALO + S;
2905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
2915460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() &= 0xFFFF0000;
2935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() |= (res & 0xFFFF);
2945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
295d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
2965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_MIPS_GOT16:
2995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//   local   : G (calculate AHL and put high 16 bit to GOT)
3005460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao//   external: G
3015460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
302d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result got16(Relocation& pReloc, MipsRelocator& pParent)
3035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
3045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  ResolveInfo* rsym = pReloc.symInfo();
305d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::Address G = 0;
3065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3075460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  if (rsym->isLocal()) {
3085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
3095460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16");
3105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
3125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t S = pReloc.symValue();
3135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    pParent.setAHL(AHL);
3155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
317affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    bool exist;
318d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao    MipsGOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, res);
319affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
320d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao    got_entry.setValue(res);
32122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao    G = got_entry.getOffset() - 0x7FF0;
322affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  }
323affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  else {
324affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    G = helper_GetGOTOffset(pReloc, pParent);
3255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
3265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() &= 0xFFFF0000;
3285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() |= (G & 0xFFFF);
3295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
330d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
331d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao}
332d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
333d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao// R_MIPS_GOTHI16:
334d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao//   external: (G - (short)G) >> 16 + A
335d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liaostatic
336d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result gothi16(Relocation& pReloc, MipsRelocator& pParent)
337d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao{
338d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  int32_t res = 0;
339d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
340d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
341d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  int32_t A = pReloc.target() + pReloc.addend();
342d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
343d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  res = (G - (int16_t)G) >> (16 + A);
344d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
345d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  pReloc.target() &= 0xFFFF0000;
346d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  pReloc.target() |= (res & 0xFFFF);
347d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
348d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
349d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao}
350d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
351d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao// R_MIPS_GOTLO16:
352d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao//   external: G & 0xffff
353d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liaostatic
354d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result gotlo16(Relocation& pReloc, MipsRelocator& pParent)
355d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao{
356d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
357d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
358d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  pReloc.target() &= 0xFFFF0000;
359d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  pReloc.target() |= (G & 0xFFFF);
360d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
361d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
3625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
3635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_MIPS_CALL16: G
3655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
366d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result call16(Relocation& pReloc, MipsRelocator& pParent)
3675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
368d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  Relocator::Address G = helper_GetGOTOffset(pReloc, pParent);
3695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() &= 0xFFFF0000;
3715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() |= (G & 0xFFFF);
3725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
373d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
3745460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
3755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// R_MIPS_GPREL32: A + S + GP0 - GP
3775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic
378d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei LiaoMipsRelocator::Result gprel32(Relocation& pReloc, MipsRelocator& pParent)
3795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao{
380affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // Remember to add the section offset to A.
381affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  int32_t A = pReloc.target() + pReloc.addend();
3825460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  int32_t S = pReloc.symValue();
3835460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  int32_t GP = helper_GetGP(pParent);
3845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
3855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // llvm does not emits SHT_MIPS_REGINFO section.
3865460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  // Assume that GP0 is zero.
3875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  pReloc.target() = (A + S - GP) & 0xFFFFFFFF;
3885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
389d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao  return MipsRelocator::OK;
3905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
391d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao
392