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
22static const char g_CantUnwindEntry[8] = {
23  // Relocation to text section.
24  0, 0, 0, 0,
25  // EXIDX_CANTUNWIND (little endian.)
26  1, 0, 0, 0,
27};
28
29namespace mcld {
30
31void ARMExData::addInputMap(Input* pInput,
32                            std::unique_ptr<ARMInputExMap>&& pExMap) {
33  assert(m_Inputs.find(pInput) == m_Inputs.end() &&
34         "multiple maps for an input");
35
36  ARMInputExMap* exMap = pExMap.get();
37
38  // Add mapping to the input-to-exdata map.
39  m_Inputs.insert(std::make_pair(pInput, std::move(pExMap)));
40
41  // Add mapping to the fragment-to-exdata map.
42  for (ARMInputExMap::iterator it = exMap->begin(), end = exMap->end();
43       it != end; ++it) {
44    ARMExSectionTuple* exTuple = it->second.get();
45    m_ExIdxToTuple[exTuple->getExIdxFragment()] = exTuple;
46  }
47}
48
49void ARMGNULDBackend::scanInputExceptionSections(Module& pModule) {
50  for (Module::obj_iterator it = pModule.obj_begin(),
51                            end = pModule.obj_end(); it != end; ++it) {
52    Input* input = *it;
53    scanInputExceptionSections(pModule, *input);
54  }
55}
56
57static RegionFragment* findRegionFragment(LDSection& pSection) {
58  SectionData* sectData = pSection.getSectionData();
59  for (SectionData::iterator it = sectData->begin(),
60                             end = sectData->end(); it != end; ++it) {
61    if (it->getKind() == Fragment::Region) {
62      return static_cast<RegionFragment*>(&*it);
63    }
64  }
65  return NULL;
66}
67
68void ARMGNULDBackend::scanInputExceptionSections(Module& pModule,
69                                                 Input& pInput) {
70  std::unique_ptr<ARMInputExMap> exMap(new ARMInputExMap());
71
72  // Scan the input and collect all related sections.
73  LDContext* ctx = pInput.context();
74  for (LDContext::sect_iterator it = ctx->sectBegin(),
75                                end = ctx->sectEnd(); it != end; ++it) {
76    LDSection* sect = *it;
77    llvm::StringRef name(sect->name());
78
79    if (name.startswith(".ARM.exidx")) {
80      ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(name);
81      exTuple->setExIdxSection(sect);
82      exTuple->setTextSection(sect->getLink());
83    } else if (name.startswith(".ARM.extab")) {
84      ARMExSectionTuple* exTuple = exMap->getOrCreateByExSection(name);
85      exTuple->setExTabSection(sect);
86    } else if (name.startswith(".rel.ARM.exidx")) {
87      ARMExSectionTuple* exTuple = exMap->getOrCreateByRelExSection(name);
88      exTuple->setRelExIdxSection(sect);
89    } else if (name.startswith(".rel.ARM.extab")) {
90      ARMExSectionTuple* exTuple = exMap->getOrCreateByRelExSection(name);
91      exTuple->setRelExIdxSection(sect);
92    }
93  }
94
95  // Remove the invalid exception tuples and convert LDSection to RegionFragment
96  // or RelocData.
97  ARMInputExMap::iterator it = exMap->begin();
98  ARMInputExMap::iterator end = exMap->end();
99  while (it != end) {
100    ARMExSectionTuple* exTuple = it->second.get();
101    LDSection* const text = exTuple->getTextSection();
102    LDSection* const exIdx = exTuple->getExIdxSection();
103    LDSection* const exTab = exTuple->getExTabSection();
104    LDSection* const relExIdx = exTuple->getRelExIdxSection();
105    LDSection* const relExTab = exTuple->getRelExTabSection();
106
107    // Check the .ARM.exidx section.
108    if (!exIdx) {
109      if (exTab) {
110        fatal(diag::eh_missing_exidx_section) << exTab->name() << pInput.name();
111      } else if (relExIdx) {
112        fatal(diag::eh_missing_exidx_section) << relExIdx->name()
113                                              << pInput.name();
114      } else if (relExTab) {
115        fatal(diag::eh_missing_exidx_section) << relExTab->name()
116                                              << pInput.name();
117      } else {
118        llvm_unreachable("unexpected bad exception tuple");
119      }
120    }
121
122    // Check the text section.
123    if (!text) {
124      fatal(diag::eh_missing_text_section) << exIdx->name() << pInput.name();
125    }
126
127    // Ignore the exception section if the text section is ignored.
128    if ((text->kind() == LDFileFormat::Ignore) ||
129        (text->kind() == LDFileFormat::Folded)) {
130      // Set the related exception sections as LDFileFormat::Ignore.
131      exIdx->setKind(LDFileFormat::Ignore);
132      if (exTab) {
133        exTab->setKind(LDFileFormat::Ignore);
134      }
135      // Remove this tuple from the input exception map.
136      exMap->erase(it++);
137      continue;
138    }
139
140    // Get RegionFragment from ".text", ".ARM.exidx", and ".ARM.extab" sections.
141    RegionFragment* textFrag = findRegionFragment(*text);
142    RegionFragment* exIdxFrag = findRegionFragment(*exIdx);
143    RegionFragment* exTabFrag = exTab ? findRegionFragment(*exTab) : NULL;
144
145    exTuple->setTextFragment(textFrag);
146    exTuple->setExIdxFragment(exIdxFrag);
147    exTuple->setExTabFragment(exTabFrag);
148
149    // Get the RelocData from ".rel.ARM.exidx" and ".rel.ARM.extab" sections.
150    RelocData* exIdxRD = relExIdx ? relExIdx->getRelocData() : NULL;
151    RelocData* exTabRD = relExTab ? relExTab->getRelocData() : NULL;
152
153    exTuple->setExIdxRelocData(exIdxRD);
154    exTuple->setExTabRelocData(exTabRD);
155
156    // If there is no region fragment in the .ARM.extab section, then we can
157    // skip this tuple.
158    if (!exIdxFrag) {
159      exMap->erase(it++);
160      continue;
161    }
162
163    // TODO: Sort the RelocData w.r.t. the fixup offset.
164
165    // Check next tuple
166    ++it;
167  }
168
169  // Add input map
170  m_ExData.addInputMap(&pInput, std::move(exMap));
171}
172
173class ExIdxFragmentComparator {
174 private:
175  const ARMExData& m_ExData;
176
177 public:
178  explicit ExIdxFragmentComparator(const ARMExData& pExData)
179      : m_ExData(pExData) {
180  }
181
182  bool operator()(const Fragment& a, const Fragment& b) {
183    ARMExSectionTuple* tupleA = m_ExData.getTupleByExIdx(&a);
184    ARMExSectionTuple* tupleB = m_ExData.getTupleByExIdx(&b);
185
186    Fragment* textFragA = tupleA->getTextFragment();
187    Fragment* textFragB = tupleB->getTextFragment();
188
189    uint64_t addrA = textFragA->getParent()->getSection().addr() +
190                     textFragA->getOffset();
191    uint64_t addrB = textFragB->getParent()->getSection().addr() +
192                     textFragB->getOffset();
193    return (addrA < addrB);
194  }
195};
196
197static mcld::ResolveInfo*
198CreateLocalSymbolToFragmentEnd(mcld::Module& pModule, mcld::Fragment& pFrag) {
199  // Create and add symbol to the name pool.
200  mcld::ResolveInfo* resolveInfo =
201      pModule.getNamePool().createSymbol(/* pName */"",
202                                         /* pIsDyn */false,
203                                         mcld::ResolveInfo::Section,
204                                         mcld::ResolveInfo::Define,
205                                         mcld::ResolveInfo::Local,
206                                         /* pSize */0,
207                                         mcld::ResolveInfo::Hidden);
208  if (resolveInfo == nullptr) {
209    return nullptr;
210  }
211
212  // Create input symbol.
213  mcld::LDSymbol* inputSym = mcld::LDSymbol::Create(*resolveInfo);
214  if (inputSym == nullptr) {
215    return nullptr;
216  }
217
218  inputSym->setFragmentRef(mcld::FragmentRef::Create(pFrag, pFrag.size()));
219  inputSym->setValue(/* pValue */0);
220
221  // The output symbol is simply an alias to the input symbol.
222  resolveInfo->setSymPtr(inputSym);
223
224  return resolveInfo;
225}
226
227void ARMGNULDBackend::rewriteARMExIdxSection(Module& pModule) {
228  if (!m_pEXIDX->hasSectionData()) {
229    // Return if this is empty section.
230    return;
231  }
232
233  SectionData* sectData = m_pEXIDX->getSectionData();
234  SectionData::FragmentListType& list = sectData->getFragmentList();
235
236  // Move the first fragment (align fragment) and last fragment (null fragment)
237  // to temporary list because we would only like to sort the region fragment.
238  SectionData::FragmentListType tmp;
239  {
240    SectionData::iterator first = sectData->begin();
241    SectionData::iterator last = sectData->end();
242    --last;
243
244    assert(first->getKind() == Fragment::Alignment);
245    assert(last->getKind() == Fragment::Null);
246
247    tmp.splice(tmp.end(), list, first);
248    tmp.splice(tmp.end(), list, last);
249  }
250
251  // Sort the region fragments in the .ARM.exidx output section.
252  sort(list, ExIdxFragmentComparator(m_ExData));
253
254  // Fix the coverage of the .ARM.exidx table.
255  llvm::StringRef cantUnwindRegion(g_CantUnwindEntry,
256                                   sizeof(g_CantUnwindEntry));
257
258  SectionData::FragmentListType::iterator it = list.begin();
259  if (it != list.end()) {
260    Fragment* prevTextFrag = m_ExData.getTupleByExIdx(it)->getTextFragment();
261    uint64_t prevTextEnd = prevTextFrag->getParent()->getSection().addr() +
262                           prevTextFrag->getOffset() +
263                           prevTextFrag->size();
264    ++it;
265    while (it != list.end()) {
266      Fragment* currTextFrag = m_ExData.getTupleByExIdx(it)->getTextFragment();
267      uint64_t currTextBegin = currTextFrag->getParent()->getSection().addr() +
268                               currTextFrag->getOffset();
269
270      if (currTextBegin > prevTextEnd) {
271        // Found a gap. Insert a can't unwind entry.
272        RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr);
273        frag->setParent(sectData);
274        list.insert(it, frag);
275
276        // Add PREL31 reference to the beginning of the uncovered region.
277        Relocation* reloc =
278            Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31),
279                               *FragmentRef::Create(*frag, /* pOffset */0),
280                               /* pAddend */0);
281        reloc->setSymInfo(
282            CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag));
283        addExtraRelocation(reloc);
284      }
285
286      prevTextEnd = currTextBegin + currTextFrag->size();
287      prevTextFrag = currTextFrag;
288      ++it;
289    }
290
291    // Add a can't unwind entry to terminate .ARM.exidx section.
292    RegionFragment* frag = new RegionFragment(cantUnwindRegion, nullptr);
293    frag->setParent(sectData);
294    list.push_back(frag);
295
296    // Add PREL31 reference to the end of the .text section.
297    Relocation* reloc =
298        Relocation::Create(static_cast<uint32_t>(llvm::ELF::R_ARM_PREL31),
299                           *FragmentRef::Create(*frag, /* pOffset */0),
300                           /* pAddend */0);
301    reloc->setSymInfo(CreateLocalSymbolToFragmentEnd(pModule, *prevTextFrag));
302    addExtraRelocation(reloc);
303  }
304
305  // Add the first and the last fragment back.
306  list.splice(list.begin(), tmp, tmp.begin());
307  list.splice(list.end(), tmp, tmp.begin());
308
309  // Update the fragment offsets.
310  uint64_t offset = 0;
311  for (SectionData::iterator it = sectData->begin(), end = sectData->end();
312       it != end; ++it) {
313    it->setOffset(offset);
314    offset += it->size();
315  }
316
317  // Update the section size.
318  m_pEXIDX->setSize(offset);
319
320  // Rebuild the section header.
321  setOutputSectionAddress(pModule);
322}
323
324}  // namespace mcld
325