/// computePCBegin - return the address of FDE's pc /// @ref binutils gold: ehframe.cc:222 uint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE, const MemoryRegion& pEhFrameRegion) { uint8_t fde_encoding = pFDE.getCIE().getFDEEncode(); unsigned int eh_value = fde_encoding & 0x7; // check the size to read in if (eh_value == llvm::dwarf::DW_EH_PE_absptr) { eh_value = DW_EH_PE_udata4; } size_t pc_size = 0x0; switch (eh_value) { case DW_EH_PE_udata2: pc_size = 2; break; case DW_EH_PE_udata4: pc_size = 4; break; case DW_EH_PE_udata8: pc_size = 8; break; default: // TODO break; } SizeTraits<32>::Address pc = 0x0; const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() + pFDE.getOffset() + pFDE.getDataStart(); std::memcpy(&pc, offset, pc_size); // adjust the signed value bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0; if (DW_EH_PE_udata2 == eh_value && is_signed) pc = (pc ^ 0x8000) - 0x8000; // handle eh application switch (fde_encoding & 0x70) { case DW_EH_PE_absptr: break; case DW_EH_PE_pcrel: pc += m_EhFrame.addr() + pFDE.getOffset() + pFDE.getDataStart(); break; case DW_EH_PE_datarel: // TODO break; default: // TODO break; } return pc; }
void X86GNULDBackend::addEhFrameForPLT(Module& pModule) { LDSection* plt_sect = pModule.getSection(".plt"); if (!plt_sect || plt_sect->size() == 0u) return; LDSection* eh_sect = pModule.getSection(".eh_frame"); if (!eh_sect || !eh_sect->hasEhFrame()) return; EhFrame* eh_frame = eh_sect->getEhFrame(); SectionData::FragmentListType& frag_list = eh_frame->getSectionData()->getFragmentList(); llvm::StringRef cie_region = createCIERegionForPLT(); llvm::StringRef fde_region = createFDERegionForPLT(); EhFrame::CIE* cie = new EhFrame::GeneratedCIE(cie_region); EhFrame::FDE* fde = new EhFrame::GeneratedFDE(fde_region, *cie); // Augmentation data only contains FDE encoding. uint8_t aug_data = (uint8_t)(llvm::dwarf::DW_EH_PE_pcrel | llvm::dwarf::DW_EH_PE_sdata4); cie->setFDEEncode(aug_data); cie->setAugmentationData(std::string(1, aug_data)); EhFrame::cie_iterator i = eh_frame->cie_begin(); for (EhFrame::cie_iterator e = eh_frame->cie_end(); i != e; ++i) { EhFrame::CIE& exist_cie = **i; if (exist_cie == *cie) { // Insert the FDE fragment SectionData::iterator cur_iter(exist_cie); frag_list.insertAfter(cur_iter, fde); fde->setCIE(exist_cie); // Cleanup the CIE we created cie->clearFDEs(); delete cie; break; } } if (i == eh_frame->cie_end()) { // Newly insert eh_frame->addCIE(*cie); eh_frame->addFDE(*fde); } }
void EhFrame::addFDE(EhFrame::FDE& pFDE, bool pAlsoAddFragment) { pFDE.getCIE().add(pFDE); if (pAlsoAddFragment) addFragment(pFDE); }