Home | History | Annotate | Download | only in LD
      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