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