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