1//===- Relocation.cpp -----------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "mcld/Fragment/Relocation.h"
10
11#include "mcld/LD/LDSection.h"
12#include "mcld/LD/LDSymbol.h"
13#include "mcld/LD/RelocationFactory.h"
14#include "mcld/LD/Relocator.h"
15#include "mcld/LD/ResolveInfo.h"
16#include "mcld/LD/SectionData.h"
17#include "mcld/Support/MsgHandling.h"
18
19#include <llvm/Support/ManagedStatic.h>
20
21namespace mcld {
22
23static llvm::ManagedStatic<RelocationFactory> g_RelocationFactory;
24
25//===----------------------------------------------------------------------===//
26// Relocation Factory Methods
27//===----------------------------------------------------------------------===//
28/// Initialize - set up the relocation factory
29void Relocation::SetUp(const LinkerConfig& pConfig) {
30  g_RelocationFactory->setConfig(pConfig);
31}
32
33/// Clear - Clean up the relocation factory
34void Relocation::Clear() {
35  g_RelocationFactory->clear();
36}
37
38/// Create - produce an empty relocation entry
39Relocation* Relocation::Create() {
40  return g_RelocationFactory->produceEmptyEntry();
41}
42
43/// Create - produce a relocation entry
44/// @param pType    [in] the type of the relocation entry
45/// @param pFragRef [in] the place to apply the relocation
46/// @param pAddend  [in] the addend of the relocation entry
47Relocation* Relocation::Create(Type pType,
48                               FragmentRef& pFragRef,
49                               Address pAddend) {
50  return g_RelocationFactory->produce(pType, pFragRef, pAddend);
51}
52
53/// Destroy - destroy a relocation entry
54void Relocation::Destroy(Relocation*& pRelocation) {
55  g_RelocationFactory->destroy(pRelocation);
56  pRelocation = NULL;
57}
58
59//===----------------------------------------------------------------------===//
60// Relocation
61//===----------------------------------------------------------------------===//
62Relocation::Relocation()
63    : m_Type(0x0), m_TargetData(0x0), m_pSymInfo(NULL), m_Addend(0x0) {
64}
65
66Relocation::Relocation(Relocation::Type pType,
67                       FragmentRef* pTargetRef,
68                       Relocation::Address pAddend,
69                       Relocation::DWord pTargetData)
70    : m_Type(pType),
71      m_TargetData(pTargetData),
72      m_pSymInfo(NULL),
73      m_Addend(pAddend) {
74  if (pTargetRef != NULL)
75    m_TargetAddress.assign(*pTargetRef->frag(), pTargetRef->offset());
76}
77
78Relocation::~Relocation() {
79}
80
81Relocation::Address Relocation::place() const {
82  Address sect_addr = m_TargetAddress.frag()->getParent()->getSection().addr();
83  return sect_addr + m_TargetAddress.getOutputOffset();
84}
85
86Relocation::Address Relocation::symValue() const {
87  if (m_pSymInfo->type() == ResolveInfo::Section &&
88      m_pSymInfo->outSymbol()->hasFragRef()) {
89    const FragmentRef* fragRef = m_pSymInfo->outSymbol()->fragRef();
90    return fragRef->frag()->getParent()->getSection().addr() +
91           fragRef->getOutputOffset();
92  }
93  return m_pSymInfo->outSymbol()->value();
94}
95
96void Relocation::apply(Relocator& pRelocator) {
97  Relocator::Result result = pRelocator.applyRelocation(*this);
98
99  switch (result) {
100    case Relocator::OK: {
101      // do nothing
102      return;
103    }
104    case Relocator::Overflow: {
105      error(diag::result_overflow) << pRelocator.getName(type())
106                                   << symInfo()->name();
107      return;
108    }
109    case Relocator::BadReloc: {
110      error(diag::result_badreloc) << pRelocator.getName(type())
111                                   << symInfo()->name();
112      return;
113    }
114    case Relocator::Unsupported: {
115      fatal(diag::unsupported_relocation) << type()
116                                          << "mclinker@googlegroups.com";
117      return;
118    }
119    case Relocator::Unknown: {
120      fatal(diag::unknown_relocation) << type() << symInfo()->name();
121      return;
122    }
123  }  // end of switch
124}
125
126void Relocation::setType(Type pType) {
127  m_Type = pType;
128}
129
130void Relocation::setAddend(Address pAddend) {
131  m_Addend = pAddend;
132}
133
134void Relocation::setSymInfo(ResolveInfo* pSym) {
135  m_pSymInfo = pSym;
136}
137
138Relocation::Size Relocation::size(Relocator& pRelocator) const {
139  return pRelocator.getSize(m_Type);
140}
141
142void Relocation::updateAddend() {
143  // Update value keep in addend if we meet a section symbol
144  if (m_pSymInfo->type() == ResolveInfo::Section) {
145    uint32_t offset = m_pSymInfo->outSymbol()->fragRef()->getOutputOffset();
146    m_Addend += offset;
147  }
148}
149
150}  // namespace mcld
151