1 //===- EhFrame.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 #include <mcld/Fragment/Relocation.h> 10 #include <mcld/LD/EhFrame.h> 11 #include <mcld/LD/LDContext.h> 12 #include <mcld/LD/LDSection.h> 13 #include <mcld/LD/LDSymbol.h> 14 #include <mcld/LD/RelocData.h> 15 #include <mcld/LD/ResolveInfo.h> 16 #include <mcld/LD/SectionData.h> 17 #include <mcld/MC/Input.h> 18 #include <mcld/Object/ObjectBuilder.h> 19 #include <mcld/Support/GCFactory.h> 20 21 #include <llvm/Support/ManagedStatic.h> 22 23 using namespace mcld; 24 25 typedef GCFactory<EhFrame, MCLD_SECTIONS_PER_INPUT> EhFrameFactory; 26 27 static llvm::ManagedStatic<EhFrameFactory> g_EhFrameFactory; 28 29 //===----------------------------------------------------------------------===// 30 // EhFrame::Record 31 //===----------------------------------------------------------------------===// 32 EhFrame::Record::Record(llvm::StringRef pRegion) 33 : RegionFragment(pRegion) { 34 } 35 36 EhFrame::Record::~Record() 37 { 38 // llvm::iplist will manage and delete the fragments 39 } 40 41 //===----------------------------------------------------------------------===// 42 // EhFrame::CIE 43 //===----------------------------------------------------------------------===// 44 EhFrame::CIE::CIE(llvm::StringRef pRegion) 45 : EhFrame::Record(pRegion), 46 m_FDEEncode(0u), m_Mergeable(false), m_pReloc(0), m_PersonalityOffset(0) { 47 } 48 49 EhFrame::CIE::~CIE() 50 { 51 } 52 53 //===----------------------------------------------------------------------===// 54 // EhFrame::FDE 55 //===----------------------------------------------------------------------===// 56 EhFrame::FDE::FDE(llvm::StringRef pRegion, EhFrame::CIE& pCIE) 57 : EhFrame::Record(pRegion), m_pCIE(&pCIE) { 58 } 59 60 EhFrame::FDE::~FDE() 61 { 62 } 63 64 void EhFrame::FDE::setCIE(EhFrame::CIE& pCIE) 65 { 66 m_pCIE = &pCIE; 67 m_pCIE->add(*this); 68 } 69 70 //===----------------------------------------------------------------------===// 71 // EhFrame::GeneratedCIE 72 //===----------------------------------------------------------------------===// 73 EhFrame::GeneratedCIE::GeneratedCIE(llvm::StringRef pRegion) 74 : EhFrame::CIE(pRegion) { 75 } 76 77 EhFrame::GeneratedCIE::~GeneratedCIE() 78 { 79 } 80 81 //===----------------------------------------------------------------------===// 82 // EhFrame::GeneratedFDE 83 //===----------------------------------------------------------------------===// 84 EhFrame::GeneratedFDE::GeneratedFDE(llvm::StringRef pRegion, CIE &pCIE) 85 : EhFrame::FDE(pRegion, pCIE) { 86 } 87 88 EhFrame::GeneratedFDE::~GeneratedFDE() 89 { 90 } 91 92 //===----------------------------------------------------------------------===// 93 // EhFrame 94 //===----------------------------------------------------------------------===// 95 EhFrame::EhFrame() 96 : m_pSection(NULL), m_pSectionData(NULL) { 97 } 98 99 EhFrame::EhFrame(LDSection& pSection) 100 : m_pSection(&pSection), 101 m_pSectionData(NULL) { 102 m_pSectionData = SectionData::Create(pSection); 103 } 104 105 EhFrame::~EhFrame() 106 { 107 } 108 109 EhFrame* EhFrame::Create(LDSection& pSection) 110 { 111 EhFrame* result = g_EhFrameFactory->allocate(); 112 new (result) EhFrame(pSection); 113 return result; 114 } 115 116 void EhFrame::Destroy(EhFrame*& pSection) 117 { 118 pSection->~EhFrame(); 119 g_EhFrameFactory->deallocate(pSection); 120 pSection = NULL; 121 } 122 123 void EhFrame::Clear() 124 { 125 g_EhFrameFactory->clear(); 126 } 127 128 const LDSection& EhFrame::getSection() const 129 { 130 assert(NULL != m_pSection); 131 return *m_pSection; 132 } 133 134 LDSection& EhFrame::getSection() 135 { 136 assert(NULL != m_pSection); 137 return *m_pSection; 138 } 139 140 void EhFrame::addFragment(Fragment& pFrag) 141 { 142 uint32_t offset = 0; 143 if (!m_pSectionData->empty()) 144 offset = m_pSectionData->back().getOffset() + m_pSectionData->back().size(); 145 146 m_pSectionData->getFragmentList().push_back(&pFrag); 147 pFrag.setParent(m_pSectionData); 148 pFrag.setOffset(offset); 149 } 150 151 void EhFrame::addCIE(EhFrame::CIE& pCIE, bool pAlsoAddFragment) 152 { 153 m_CIEs.push_back(&pCIE); 154 if (pAlsoAddFragment) 155 addFragment(pCIE); 156 } 157 158 void EhFrame::addFDE(EhFrame::FDE& pFDE, bool pAlsoAddFragment) 159 { 160 pFDE.getCIE().add(pFDE); 161 if (pAlsoAddFragment) 162 addFragment(pFDE); 163 } 164 165 size_t EhFrame::numOfFDEs() const 166 { 167 // FDE number only used by .eh_frame_hdr computation, and the number of CIE 168 // is usually not too many. It is worthy to compromise space by time 169 size_t size = 0u; 170 for (const_cie_iterator i = cie_begin(), e = cie_end(); i != e; ++i) 171 size += (*i)->numOfFDEs(); 172 return size; 173 } 174 175 EhFrame& EhFrame::merge(const Input& pInput, EhFrame& pFrame) 176 { 177 assert (this != &pFrame); 178 if (pFrame.emptyCIEs()) { 179 // May be a partial linking, or the eh_frame has no data. 180 // Just append the fragments. 181 moveInputFragments(pFrame); 182 return *this; 183 } 184 185 const LDContext& ctx = *pInput.context(); 186 const LDSection* rel_sec = 0; 187 for (LDContext::const_sect_iterator ri = ctx.relocSectBegin(), 188 re = ctx.relocSectEnd(); ri != re; ++ri) { 189 if ((*ri)->getLink() == &pFrame.getSection()) { 190 rel_sec = *ri; 191 break; 192 } 193 } 194 pFrame.setupAttributes(rel_sec); 195 196 // Most CIE will be merged, so we don't reserve space first. 197 for (cie_iterator i = pFrame.cie_begin(), e = pFrame.cie_end(); i != e; ++i) { 198 CIE& input_cie = **i; 199 // CIE number is usually very few, so we just use vector sequential search. 200 if (!input_cie.getMergeable()) { 201 moveInputFragments(pFrame, input_cie); 202 addCIE(input_cie, /*AlsoAddFragment=*/false); 203 continue; 204 } 205 206 cie_iterator out_i = cie_begin(); 207 for (cie_iterator out_e = cie_end(); out_i != out_e; ++out_i) { 208 CIE& output_cie = **out_i; 209 if (output_cie == input_cie) { 210 // This input CIE can be merged 211 moveInputFragments(pFrame, input_cie, &output_cie); 212 removeAndUpdateCIEForFDE(pFrame, input_cie, output_cie, rel_sec); 213 break; 214 } 215 } 216 if (out_i == cie_end()) { 217 moveInputFragments(pFrame, input_cie); 218 addCIE(input_cie, /*AlsoAddFragment=*/false); 219 } 220 } 221 return *this; 222 } 223 224 void EhFrame::setupAttributes(const LDSection* rel_sec) 225 { 226 for (cie_iterator i = cie_begin(), e = cie_end(); i != e; ++i) { 227 CIE* cie = *i; 228 removeDiscardedFDE(*cie, rel_sec); 229 230 if (cie->getPersonalityName().size() == 0) { 231 // There's no personality data encoding inside augmentation string. 232 cie->setMergeable(); 233 } else { 234 if (!rel_sec) { 235 // No relocation to eh_frame section 236 assert (cie->getPersonalityName() != "" && 237 "PR name should be a symbol address or offset"); 238 continue; 239 } 240 const RelocData* reloc_data = rel_sec->getRelocData(); 241 for (RelocData::const_iterator ri = reloc_data->begin(), 242 re = reloc_data->end(); ri != re; ++ri) { 243 const Relocation& rel = *ri; 244 if (rel.targetRef().getOutputOffset() == cie->getOffset() + 245 cie->getPersonalityOffset()) { 246 cie->setMergeable(); 247 cie->setPersonalityName(rel.symInfo()->outSymbol()->name()); 248 cie->setRelocation(rel); 249 break; 250 } 251 } 252 253 assert (cie->getPersonalityName() != "" && 254 "PR name should be a symbol address or offset"); 255 } 256 } 257 } 258 259 void EhFrame::removeDiscardedFDE(CIE& pCIE, const LDSection* pRelocSect) 260 { 261 if (!pRelocSect) 262 return; 263 264 typedef std::vector<FDE*> FDERemoveList; 265 FDERemoveList to_be_removed_fdes; 266 const RelocData* reloc_data = pRelocSect->getRelocData(); 267 for (fde_iterator i = pCIE.begin(), e = pCIE.end(); i != e; ++i) { 268 FDE& fde = **i; 269 for (RelocData::const_iterator ri = reloc_data->begin(), 270 re = reloc_data->end(); ri != re; ++ri) { 271 const Relocation& rel = *ri; 272 if (rel.targetRef().getOutputOffset() == fde.getOffset() + 273 getDataStartOffset<32>()) { 274 bool has_section = rel.symInfo()->outSymbol()->hasFragRef(); 275 if (!has_section) 276 // The section was discarded, just ignore this FDE. 277 // This may happen when redundant group section was read. 278 to_be_removed_fdes.push_back(&fde); 279 break; 280 } 281 } 282 } 283 284 for (FDERemoveList::iterator i = to_be_removed_fdes.begin(), 285 e = to_be_removed_fdes.end(); i != e; ++i) { 286 FDE& fde = **i; 287 fde.getCIE().remove(fde); 288 289 // FIXME: This traverses relocations from the beginning on each FDE, which 290 // may cause performance degration. Actually relocations will be sequential 291 // order, so we can bookkeep the previously found relocation for next use. 292 // Note: We must ensure FDE order is ordered. 293 for (RelocData::const_iterator ri = reloc_data->begin(), 294 re = reloc_data->end(); ri != re; ) { 295 Relocation& rel = const_cast<Relocation&>(*ri++); 296 if (rel.targetRef().getOutputOffset() >= fde.getOffset() && 297 rel.targetRef().getOutputOffset() < fde.getOffset() + fde.size()) { 298 const_cast<RelocData*>(reloc_data)->remove(rel); 299 } 300 } 301 } 302 } 303 304 void EhFrame::removeAndUpdateCIEForFDE(EhFrame& pInFrame, CIE& pInCIE, 305 CIE& pOutCIE, const LDSection* rel_sect) 306 { 307 // Make this relocation to be ignored. 308 Relocation* rel = const_cast<Relocation*>(pInCIE.getRelocation()); 309 if (rel && rel_sect) 310 const_cast<RelocData*>(rel_sect->getRelocData())->remove(*rel); 311 312 // Update the CIE-pointed FDEs 313 for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) 314 (*i)->setCIE(pOutCIE); 315 316 // We cannot know whether there are references to this fragment, so just 317 // keep it in input fragment list instead of memory deallocation 318 pInCIE.clearFDEs(); 319 } 320 321 void EhFrame::moveInputFragments(EhFrame& pInFrame) 322 { 323 SectionData& in_sd = *pInFrame.getSectionData(); 324 SectionData::FragmentListType& in_frag_list = in_sd.getFragmentList(); 325 SectionData& out_sd = *getSectionData(); 326 SectionData::FragmentListType& out_frag_list = out_sd.getFragmentList(); 327 328 while (!in_frag_list.empty()) { 329 Fragment* frag = in_frag_list.remove(in_frag_list.begin()); 330 out_frag_list.push_back(frag); 331 frag->setParent(&out_sd); 332 } 333 } 334 335 void EhFrame::moveInputFragments(EhFrame& pInFrame, 336 CIE& pInCIE, CIE* pOutCIE) 337 { 338 SectionData& in_sd = *pInFrame.getSectionData(); 339 SectionData::FragmentListType& in_frag_list = in_sd.getFragmentList(); 340 SectionData& out_sd = *getSectionData(); 341 SectionData::FragmentListType& out_frag_list = out_sd.getFragmentList(); 342 343 if (!pOutCIE) { 344 // Newly inserted 345 Fragment* frag = in_frag_list.remove(SectionData::iterator(pInCIE)); 346 out_frag_list.push_back(frag); 347 frag->setParent(&out_sd); 348 for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) { 349 frag = in_frag_list.remove(SectionData::iterator(**i)); 350 out_frag_list.push_back(frag); 351 frag->setParent(&out_sd); 352 } 353 return; 354 } 355 356 SectionData::iterator cur_iter(*pOutCIE); 357 assert (cur_iter != out_frag_list.end()); 358 for (fde_iterator i = pInCIE.begin(), e = pInCIE.end(); i != e; ++i) { 359 Fragment* frag = in_frag_list.remove(SectionData::iterator(**i)); 360 cur_iter = out_frag_list.insertAfter(cur_iter, frag); 361 frag->setParent(&out_sd); 362 } 363 } 364 365 size_t EhFrame::computeOffsetSize() 366 { 367 size_t offset = 0u; 368 SectionData::FragmentListType& frag_list = getSectionData()->getFragmentList(); 369 for (SectionData::iterator i = frag_list.begin(), e = frag_list.end(); 370 i != e; ++i) { 371 Fragment& frag = *i; 372 frag.setOffset(offset); 373 offset += frag.size(); 374 } 375 getSection().setSize(offset); 376 return offset; 377 } 378 379 bool mcld::operator==(const EhFrame::CIE& p1, const EhFrame::CIE& p2) 380 { 381 return p1.getPersonalityName() == p2.getPersonalityName() && 382 p1.getAugmentationData() == p2.getAugmentationData(); 383 } 384