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 
22 static 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 
29 namespace mcld {
30 
addInputMap(Input * pInput,std::unique_ptr<ARMInputExMap> && pExMap)31 void 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 
scanInputExceptionSections(Module & pModule)49 void 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 
findRegionFragment(LDSection & pSection)57 static 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 
scanInputExceptionSections(Module & pModule,Input & pInput)68 void 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 
173 class ExIdxFragmentComparator {
174  private:
175   const ARMExData& m_ExData;
176 
177  public:
ExIdxFragmentComparator(const ARMExData & pExData)178   explicit ExIdxFragmentComparator(const ARMExData& pExData)
179       : m_ExData(pExData) {
180   }
181 
operator ()(const Fragment & a,const Fragment & b)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 
197 static mcld::ResolveInfo*
CreateLocalSymbolToFragmentEnd(mcld::Module & pModule,mcld::Fragment & pFrag)198 CreateLocalSymbolToFragmentEnd(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 
rewriteARMExIdxSection(Module & pModule)227 void 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