ARMException.cpp revision a6c24dff8b7fa2551a3a885e77a2e814f5b764a2
1//===- ARMException.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
10#include "ARMException.h"
11
12#include "ARMLDBackend.h"
13
14#include "mcld/ADT/ilist_sort.h"
15#include "mcld/Fragment/RegionFragment.h"
16#include "mcld/LD/ELFFileFormat.h"
17#include "mcld/LD/LDContext.h"
18#include "mcld/Support/MsgHandling.h"
19
20#include <memory>
21
22namespace mcld {
23
24void ARMExData::addInputMap(Input* pInput,
25                            std::unique_ptr<ARMInputExMap>&& pExMap) {
26  assert(m_Inputs.find(pInput) == m_Inputs.end() &&
27         "multiple maps for an input");
28
29  ARMInputExMap* exMap = pExMap.get();
30
31  // Add mapping to the input-to-exdata map.
32  m_Inputs.insert(std::make_pair(pInput, std::move(pExMap)));
33
34  // Add mapping to the fragment-to-exdata map.
35  for (ARMInputExMap::iterator it = exMap->begin(), end = exMap->end();
36       it != end; ++it) {
37    ARMExSectionTuple* exTuple = it->second.get();
38    m_ExIdxToTuple[exTuple->getExIdxFragment()] = exTuple;
39  }
40}
41
42void ARMGNULDBackend::scanInputExceptionSections(Module& pModule) {
43  for (Module::obj_iterator it = pModule.obj_begin(),
44                            end = pModule.obj_end(); it != end; ++it) {
45    Input* input = *it;
46    scanInputExceptionSections(pModule, *input);
47  }
48}
49
50static RegionFragment* findRegionFragment(LDSection& pSection) {
51  SectionData* sectData = pSection.getSectionData();
52  for (SectionData::iterator it = sectData->begin(),
53                             end = sectData->end(); it != end; ++it) {
54    if (it->getKind() == Fragment::Region) {
55      return static_cast<RegionFragment*>(&*it);
56    }
57  }
58  return NULL;
59}
60
61void ARMGNULDBackend::scanInputExceptionSections(Module& pModule,
62                                                 Input& pInput) {
63  std::unique_ptr<ARMInputExMap> exMap(new ARMInputExMap());
64
65  // Scan the input and collect all related sections.
66  LDContext* ctx = pInput.context();
67  for (LDContext::sect_iterator it = ctx->sectBegin(),
68                                end = ctx->sectEnd(); it != end; ++it) {
69    LDSection* sect = *it;
70    llvm::StringRef name(sect->name());
71
72    if (name.startswith(".ARM.exidx")) {
73      ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(name);
74      exTuple->setExIdxSection(sect);
75      exTuple->setTextSection(sect->getLink());
76    } else if (name.startswith(".ARM.extab")) {
77      ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(name);
78      exTuple->setExTabSection(sect);
79    } else if (name.startswith(".rel.ARM.exidx")) {
80      ARMExSectionTuple* exTuple = exMap->getOrCreateByRelExSection(name);
81      exTuple->setRelExIdxSection(sect);
82    } else if (name.startswith(".rel.ARM.extab")) {
83      ARMExSectionTuple* exTuple = exMap->getOrCreateByRelExSection(name);
84      exTuple->setRelExIdxSection(sect);
85    }
86  }
87
88  // Remove the invalid exception tuples and convert LDSection to RegionFragment
89  // or RelocData.
90  ARMInputExMap::iterator it = exMap->begin();
91  ARMInputExMap::iterator end = exMap->end();
92  while (it != end) {
93    ARMExSectionTuple* exTuple = it->second.get();
94    LDSection* const text = exTuple->getTextSection();
95    LDSection* const exIdx = exTuple->getExIdxSection();
96    LDSection* const exTab = exTuple->getExTabSection();
97    LDSection* const relExIdx = exTuple->getRelExIdxSection();
98    LDSection* const relExTab = exTuple->getRelExTabSection();
99
100    // Check the .ARM.exidx section.
101    if (!exIdx) {
102      if (exTab) {
103        fatal(diag::eh_missing_exidx_section) << exTab->name() << pInput.name();
104      } else if (relExIdx) {
105        fatal(diag::eh_missing_exidx_section) << relExIdx->name()
106                                              << pInput.name();
107      } else if (relExTab) {
108        fatal(diag::eh_missing_exidx_section) << relExTab->name()
109                                              << pInput.name();
110      } else {
111        llvm_unreachable("unexpected bad exception tuple");
112      }
113    }
114
115    // Check the text section.
116    if (!text) {
117      fatal(diag::eh_missing_text_section) << exIdx->name() << pInput.name();
118    }
119
120    // Ignore the exception section if the text section is ignored.
121    if ((text->kind() == LDFileFormat::Ignore) ||
122        (text->kind() == LDFileFormat::Folded)) {
123      // Set the related exception sections as LDFileFormat::Ignore.
124      exIdx->setKind(LDFileFormat::Ignore);
125      if (exTab) {
126        exTab->setKind(LDFileFormat::Ignore);
127      }
128      // Remove this tuple from the input exception map.
129      exMap->erase(it++);
130      continue;
131    }
132
133    // Get RegionFragment from ".text", ".ARM.exidx", and ".ARM.extab" sections.
134    RegionFragment* textFrag = findRegionFragment(*text);
135    RegionFragment* exIdxFrag = findRegionFragment(*exIdx);
136    RegionFragment* exTabFrag = exTab ? findRegionFragment(*exTab) : NULL;
137
138    exTuple->setTextFragment(textFrag);
139    exTuple->setExIdxFragment(exIdxFrag);
140    exTuple->setExTabFragment(exTabFrag);
141
142    // Get the RelocData from ".rel.ARM.exidx" and ".rel.ARM.extab" sections.
143    RelocData* exIdxRD = relExIdx ? relExIdx->getRelocData() : NULL;
144    RelocData* exTabRD = relExTab ? relExTab->getRelocData() : NULL;
145
146    exTuple->setExIdxRelocData(exIdxRD);
147    exTuple->setExTabRelocData(exTabRD);
148
149    // If there is no region fragment in the .ARM.extab section, then we can
150    // skip this tuple.
151    if (!exIdxFrag) {
152      exMap->erase(it++);
153      continue;
154    }
155
156    // TODO: Sort the RelocData w.r.t. the fixup offset.
157
158    // Check next tuple
159    ++it;
160  }
161
162  // Add input map
163  m_ExData.addInputMap(&pInput, std::move(exMap));
164}
165
166class ExIdxFragmentComparator {
167 private:
168  const ARMExData& m_ExData;
169
170 public:
171  ExIdxFragmentComparator(const ARMExData& pExData)
172      : m_ExData(pExData) {
173  }
174
175  bool operator()(const Fragment& a, const Fragment& b) {
176    ARMExSectionTuple* tupleA = m_ExData.getTupleByExIdx(&a);
177    ARMExSectionTuple* tupleB = m_ExData.getTupleByExIdx(&b);
178
179    Fragment* textFragA = tupleA->getTextFragment();
180    Fragment* textFragB = tupleB->getTextFragment();
181
182    uint64_t addrA = textFragA->getParent()->getSection().addr() +
183                     textFragA->getOffset();
184    uint64_t addrB = textFragB->getParent()->getSection().addr() +
185                     textFragB->getOffset();
186    return (addrA < addrB);
187  }
188};
189
190void ARMGNULDBackend::rewriteARMExIdxSection(Module& pModule) {
191  if (!m_pEXIDX->hasSectionData()) {
192    // Return if this is empty section.
193    return;
194  }
195
196  SectionData* sectData = m_pEXIDX->getSectionData();
197  SectionData::FragmentListType& list = sectData->getFragmentList();
198
199  // Move the first and last fragment to temporary list.
200  SectionData::FragmentListType tmp;
201  {
202    SectionData::iterator first = sectData->begin();
203    SectionData::iterator last = sectData->end();
204    --last;
205
206    assert(first->getKind() == Fragment::Alignment);
207    assert(last->getKind() == Fragment::Null);
208
209    tmp.splice(tmp.end(), list, first);
210    tmp.splice(tmp.end(), list, last);
211  }
212
213  // Sort the region fragments in the .ARM.exidx output section.
214  sort(list, ExIdxFragmentComparator(m_ExData));
215
216  // Add the first and last fragment back.
217  list.splice(list.begin(), tmp, tmp.begin());
218  list.splice(list.end(), tmp, tmp.begin());
219
220  // Update the fragment offsets.
221  uint64_t offset = 0;
222  for (SectionData::iterator it = sectData->begin(), end = sectData->end();
223       it != end; ++it) {
224    it->setOffset(offset);
225    offset += it->size();
226  }
227
228  // Rebuild the section header.
229  setOutputSectionAddress(pModule);
230}
231
232}  // namespace mcld
233