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