1 //===- EhFrameHdr.tcc -----------------------------------------------------===// 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 <vector> 11 12 using namespace mcld; 13 using namespace llvm::dwarf; 14 15 /// emitOutput - write out eh_frame_hdr 16 template<size_t size> 17 void EhFrameHdr::emitOutput(Output& pOutput, MCLinker& pLinker) 18 { 19 MemoryRegion* ehframe_region = 20 pOutput.memArea()->request(m_EhFrameSect.offset(), m_EhFrameSect.size()); 21 22 MemoryRegion* ehframehdr_region = 23 pOutput.memArea()->request(m_EhFrameHdrSect.offset(), 24 m_EhFrameHdrSect.size()); 25 26 uint8_t* data = (uint8_t*)ehframehdr_region->start(); 27 // version 28 data[0] = 1; 29 // eh_frame_ptr_enc 30 data[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; 31 32 // eh_frame_ptr 33 uint32_t* eh_frame_ptr = (uint32_t*)(data + 4); 34 *eh_frame_ptr = m_EhFrameSect.addr() - (m_EhFrameHdrSect.addr() + 4); 35 36 // fde_count 37 uint32_t* fde_count = (uint32_t*)(data + 8); 38 *fde_count = m_EhFrameData.getFDECount(); 39 40 if (m_EhFrameData.getFDECount() != 0 && 41 m_EhFrameData.canRecognizeAllEhFrame()) { 42 // fde_count_enc 43 data[2] = DW_EH_PE_udata4; 44 // table_enc 45 data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; 46 47 // prepare the binary search table 48 typedef std::vector<typename BSTEntry<size>::EntryType> SearchTableType; 49 SearchTableType search_table; 50 EhFrame::const_fde_iterator fde = m_EhFrameData.fde_begin(), 51 fde_end = m_EhFrameData.fde_end(); 52 for(; fde != fde_end; ++fde) { 53 assert(*fde != NULL); 54 typename SizeTraits<size>::Offset offset; 55 typename SizeTraits<size>::Address fde_pc; 56 typename SizeTraits<size>::Address fde_addr; 57 offset = pLinker.getLayout().getOutputOffset(**fde); 58 fde_pc = getFDEPC<size>(**fde, offset, *ehframe_region); 59 fde_addr = m_EhFrameSect.addr() + offset; 60 search_table.push_back(std::make_pair(fde_pc, fde_addr)); 61 } 62 63 std::sort(search_table.begin(), search_table.end(), BSTEntryCompare<size>()); 64 65 // write out the binary search table 66 uint32_t* bst = (uint32_t*)(data + 12); 67 typename SearchTableType::const_iterator entry = search_table.begin(), 68 entry_end = search_table.end(); 69 for (size_t id = 0; entry != entry_end; ++entry) { 70 bst[id++] = (*entry).first - m_EhFrameHdrSect.addr(); 71 bst[id++] = (*entry).second - m_EhFrameHdrSect.addr(); 72 } 73 } else { 74 // fde_count_enc 75 data[2] = DW_EH_PE_omit; 76 // table_enc 77 data[3] = DW_EH_PE_omit; 78 } 79 80 pOutput.memArea()->release(ehframe_region); 81 pOutput.memArea()->release(ehframehdr_region); 82 } 83 84 /// getFDEPC - return the address of FDE's pc 85 /// @ref binutils gold: ehframe.cc:222 86 template<size_t size> 87 typename SizeTraits<size>::Address 88 EhFrameHdr::getFDEPC(const FDE& pFDE, 89 typename SizeTraits<size>::Offset pOffset, 90 const MemoryRegion& pEhFrameRegion) 91 { 92 uint8_t fde_encoding = pFDE.getCIE().getFDEEncode(); 93 unsigned int eh_value = fde_encoding & 0x7; 94 95 // check the size to read in 96 if (eh_value == llvm::dwarf::DW_EH_PE_absptr) { 97 if (size == 32) 98 eh_value = DW_EH_PE_udata4; 99 else if (size == 64) 100 eh_value = DW_EH_PE_udata8; 101 } 102 103 size_t pc_size = 0x0; 104 switch (eh_value) { 105 case DW_EH_PE_udata2: 106 pc_size = 2; 107 break; 108 case DW_EH_PE_udata4: 109 pc_size = 4; 110 break; 111 case DW_EH_PE_udata8: 112 pc_size = 8; 113 break; 114 default: 115 // TODO 116 break; 117 } 118 119 typename SizeTraits<size>::Address pc = 0x0; 120 const uint8_t* offset = (const uint8_t*) pEhFrameRegion.start() + 121 pOffset + 122 pFDE.getPCBeginOffset(); 123 std::memcpy(&pc, offset, pc_size); 124 125 // adjust the signed value 126 bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0; 127 switch (eh_value) { 128 case DW_EH_PE_udata2: 129 if (is_signed) 130 pc = (pc ^ 0x8000) - 0x8000; 131 break; 132 case DW_EH_PE_udata4: 133 if (is_signed && size > 32) 134 pc = (pc ^ 0x80000000) - 0x80000000; 135 break; 136 case DW_EH_PE_udata8: 137 break; 138 default: 139 // TODO 140 break; 141 } 142 143 // handle eh application 144 switch (fde_encoding & 0x70) 145 { 146 case DW_EH_PE_absptr: 147 break; 148 case DW_EH_PE_pcrel: 149 pc += m_EhFrameSect.addr() + 150 pOffset + 151 pFDE.getPCBeginOffset(); 152 break; 153 case DW_EH_PE_datarel: 154 // TODO 155 break; 156 default: 157 // TODO 158 break; 159 } 160 161 return pc; 162 } 163 164