Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 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 | //===----------------------------------------------------------------------===// |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 9 | #include <mcld/Fragment/Relocation.h> |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 10 | #include <mcld/LD/EhFrame.h> |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 11 | #include <mcld/LD/LDContext.h> |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 12 | #include <mcld/LD/LDSection.h> |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 13 | #include <mcld/LD/LDSymbol.h> |
| 14 | #include <mcld/LD/RelocData.h> |
| 15 | #include <mcld/LD/ResolveInfo.h> |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 16 | #include <mcld/LD/SectionData.h> |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 17 | #include <mcld/MC/Input.h> |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 18 | #include <mcld/Object/ObjectBuilder.h> |
Stephen Hines | 6f75755 | 2013-03-04 19:51:03 -0800 | [diff] [blame] | 19 | #include <mcld/Support/GCFactory.h> |
| 20 | |
| 21 | #include <llvm/Support/ManagedStatic.h> |
Shih-wei Liao | cedee4b | 2012-08-02 23:13:03 -0700 | [diff] [blame] | 22 | |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 23 | using namespace mcld; |
| 24 | |
Stephen Hines | 6f75755 | 2013-03-04 19:51:03 -0800 | [diff] [blame] | 25 | typedef GCFactory<EhFrame, MCLD_SECTIONS_PER_INPUT> EhFrameFactory; |
| 26 | |
| 27 | static llvm::ManagedStatic<EhFrameFactory> g_EhFrameFactory; |
| 28 | |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 29 | //===----------------------------------------------------------------------===// |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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 | //===----------------------------------------------------------------------===// |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 42 | // EhFrame::CIE |
| 43 | //===----------------------------------------------------------------------===// |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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 | { |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 51 | } |
| 52 | |
| 53 | //===----------------------------------------------------------------------===// |
| 54 | // EhFrame::FDE |
| 55 | //===----------------------------------------------------------------------===// |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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 | { |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | //===----------------------------------------------------------------------===// |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 93 | // EhFrame |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 94 | //===----------------------------------------------------------------------===// |
Stephen Hines | 6f75755 | 2013-03-04 19:51:03 -0800 | [diff] [blame] | 95 | EhFrame::EhFrame() |
| 96 | : m_pSection(NULL), m_pSectionData(NULL) { |
| 97 | } |
| 98 | |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 99 | EhFrame::EhFrame(LDSection& pSection) |
Stephen Hines | 6f75755 | 2013-03-04 19:51:03 -0800 | [diff] [blame] | 100 | : m_pSection(&pSection), |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 101 | m_pSectionData(NULL) { |
| 102 | m_pSectionData = SectionData::Create(pSection); |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 103 | } |
| 104 | |
| 105 | EhFrame::~EhFrame() |
| 106 | { |
| 107 | } |
| 108 | |
Stephen Hines | 6f75755 | 2013-03-04 19:51:03 -0800 | [diff] [blame] | 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 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 140 | void EhFrame::addFragment(Fragment& pFrag) |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 141 | { |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 142 | uint32_t offset = 0; |
| 143 | if (!m_pSectionData->empty()) |
| 144 | offset = m_pSectionData->back().getOffset() + m_pSectionData->back().size(); |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 145 | |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 146 | m_pSectionData->getFragmentList().push_back(&pFrag); |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 147 | pFrag.setParent(m_pSectionData); |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 148 | pFrag.setOffset(offset); |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 149 | } |
| 150 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 151 | void EhFrame::addCIE(EhFrame::CIE& pCIE, bool pAlsoAddFragment) |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 152 | { |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 153 | m_CIEs.push_back(&pCIE); |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 154 | if (pAlsoAddFragment) |
| 155 | addFragment(pCIE); |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 156 | } |
| 157 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 158 | void EhFrame::addFDE(EhFrame::FDE& pFDE, bool pAlsoAddFragment) |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 159 | { |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 160 | pFDE.getCIE().add(pFDE); |
| 161 | if (pAlsoAddFragment) |
| 162 | addFragment(pFDE); |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 163 | } |
| 164 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 165 | size_t EhFrame::numOfFDEs() const |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 166 | { |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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 | } |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 174 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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 | } |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 184 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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); |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 195 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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 | } |
Shih-wei Liao | 22add6f | 2012-12-15 17:21:00 -0800 | [diff] [blame] | 221 | return *this; |
Zonr Chang | affc150 | 2012-07-16 14:28:23 +0800 | [diff] [blame] | 222 | } |
| 223 | |
Stephen Hines | 87f3465 | 2014-02-14 18:00:16 -0800 | [diff] [blame^] | 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 | } |