1 //===- EhFrameHdr.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/EhFrameHdr.h> 10 11 #include <mcld/LD/EhFrame.h> 12 #include <mcld/LD/LDSection.h> 13 14 #include <llvm/Support/Dwarf.h> 15 #include <llvm/Support/DataTypes.h> 16 17 #include <algorithm> 18 #include <cstring> 19 20 using namespace mcld; 21 using namespace llvm::dwarf; 22 23 //===----------------------------------------------------------------------===// 24 // Helper Function 25 //===----------------------------------------------------------------------===// 26 namespace bit32 { 27 28 typedef std::pair<SizeTraits<32>::Address, SizeTraits<32>::Address> Entry; 29 30 bool EntryCompare(const Entry& pX, const Entry& pY) 31 { return (pX.first < pY.first); } 32 33 } // bit32 namespace 34 35 //===----------------------------------------------------------------------===// 36 // Template Specification Functions 37 //===----------------------------------------------------------------------===// 38 /// emitOutput<32> - write out eh_frame_hdr 39 template<> 40 void EhFrameHdr::emitOutput<32>(FileOutputBuffer& pOutput) 41 { 42 MemoryRegion ehframehdr_region = pOutput.request(m_EhFrameHdr.offset(), 43 m_EhFrameHdr.size()); 44 45 MemoryRegion ehframe_region = pOutput.request(m_EhFrame.offset(), 46 m_EhFrame.size()); 47 48 uint8_t* data = ehframehdr_region.begin(); 49 // version 50 data[0] = 1; 51 // eh_frame_ptr_enc 52 data[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; 53 54 // eh_frame_ptr 55 uint32_t* eh_frame_ptr = (uint32_t*)(data + 4); 56 *eh_frame_ptr = m_EhFrame.addr() - (m_EhFrameHdr.addr() + 4); 57 58 // fde_count 59 uint32_t* fde_count = (uint32_t*)(data + 8); 60 if (m_EhFrame.hasEhFrame()) 61 *fde_count = m_EhFrame.getEhFrame()->numOfFDEs(); 62 else 63 *fde_count = 0; 64 65 if (0 == *fde_count) { 66 // fde_count_enc 67 data[2] = DW_EH_PE_omit; 68 // table_enc 69 data[3] = DW_EH_PE_omit; 70 } 71 else { 72 // fde_count_enc 73 data[2] = DW_EH_PE_udata4; 74 // table_enc 75 data[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; 76 77 // prepare the binary search table 78 typedef std::vector<bit32::Entry> SearchTableType; 79 SearchTableType search_table; 80 81 for (EhFrame::const_cie_iterator i = m_EhFrame.getEhFrame()->cie_begin(), 82 e = m_EhFrame.getEhFrame()->cie_end(); i != e; ++i) { 83 EhFrame::CIE& cie = **i; 84 for (EhFrame::const_fde_iterator fi = cie.begin(), fe = cie.end(); 85 fi != fe; ++fi) { 86 EhFrame::FDE& fde = **fi; 87 SizeTraits<32>::Offset offset; 88 SizeTraits<32>::Address fde_pc; 89 SizeTraits<32>::Address fde_addr; 90 offset = fde.getOffset(); 91 fde_pc = computePCBegin(fde, ehframe_region); 92 fde_addr = m_EhFrame.addr() + offset; 93 search_table.push_back(std::make_pair(fde_pc, fde_addr)); 94 } 95 } 96 97 std::sort(search_table.begin(), search_table.end(), bit32::EntryCompare); 98 99 // write out the binary search table 100 uint32_t* bst = (uint32_t*)(data + 12); 101 SearchTableType::const_iterator entry, entry_end = search_table.end(); 102 size_t id = 0; 103 for (entry = search_table.begin(); entry != entry_end; ++entry) { 104 bst[id++] = (*entry).first - m_EhFrameHdr.addr(); 105 bst[id++] = (*entry).second - m_EhFrameHdr.addr(); 106 } 107 } 108 } 109 110 //===----------------------------------------------------------------------===// 111 // EhFrameHdr 112 //===----------------------------------------------------------------------===// 113 114 EhFrameHdr::EhFrameHdr(LDSection& pEhFrameHdr, const LDSection& pEhFrame) 115 : m_EhFrameHdr(pEhFrameHdr), m_EhFrame(pEhFrame) { 116 } 117 118 EhFrameHdr::~EhFrameHdr() 119 { 120 } 121 122 /// @ref lsb core generic 4.1 123 /// .eh_frame_hdr section format 124 /// uint8_t : version 125 /// uint8_t : eh_frame_ptr_enc 126 /// uint8_t : fde_count_enc 127 /// uint8_t : table_enc 128 /// uint32_t : eh_frame_ptr 129 /// uint32_t : fde_count 130 /// __________________________ when fde_count > 0 131 /// <uint32_t, uint32_t>+ : binary search table 132 /// sizeOutput - base on the fde count to size output 133 void EhFrameHdr::sizeOutput() 134 { 135 size_t size = 12; 136 if (m_EhFrame.hasEhFrame()) 137 size += 8 * m_EhFrame.getEhFrame()->numOfFDEs(); 138 m_EhFrameHdr.setSize(size); 139 } 140 141 /// computePCBegin - return the address of FDE's pc 142 /// @ref binutils gold: ehframe.cc:222 143 uint32_t EhFrameHdr::computePCBegin(const EhFrame::FDE& pFDE, 144 const MemoryRegion& pEhFrameRegion) 145 { 146 uint8_t fde_encoding = pFDE.getCIE().getFDEEncode(); 147 unsigned int eh_value = fde_encoding & 0x7; 148 149 // check the size to read in 150 if (eh_value == llvm::dwarf::DW_EH_PE_absptr) { 151 eh_value = DW_EH_PE_udata4; 152 } 153 154 size_t pc_size = 0x0; 155 switch (eh_value) { 156 case DW_EH_PE_udata2: 157 pc_size = 2; 158 break; 159 case DW_EH_PE_udata4: 160 pc_size = 4; 161 break; 162 case DW_EH_PE_udata8: 163 pc_size = 8; 164 break; 165 default: 166 // TODO 167 break; 168 } 169 170 SizeTraits<32>::Address pc = 0x0; 171 const uint8_t* offset = (const uint8_t*) pEhFrameRegion.begin() + 172 pFDE.getOffset() + 173 EhFrame::getDataStartOffset<32>(); 174 std::memcpy(&pc, offset, pc_size); 175 176 // adjust the signed value 177 bool is_signed = (fde_encoding & llvm::dwarf::DW_EH_PE_signed) != 0x0; 178 if (DW_EH_PE_udata2 == eh_value && is_signed) 179 pc = (pc ^ 0x8000) - 0x8000; 180 181 // handle eh application 182 switch (fde_encoding & 0x70) 183 { 184 case DW_EH_PE_absptr: 185 break; 186 case DW_EH_PE_pcrel: 187 pc += m_EhFrame.addr() + pFDE.getOffset() + 188 EhFrame::getDataStartOffset<32>(); 189 break; 190 case DW_EH_PE_datarel: 191 // TODO 192 break; 193 default: 194 // TODO 195 break; 196 } 197 return pc; 198 } 199