From bb2e98a91845d77ed655a0c187b870e93f9f8de8 Mon Sep 17 00:00:00 2001 From: jdh8d <jdh8d@git.zephyr-software.com> Date: Mon, 3 Apr 2017 14:58:33 +0000 Subject: [PATCH] First, working version of the EH-iR. enable with --step-option fill_in_indtargs:--split-eh-frame. --- .gitattributes | 2 + include/ehwrite.h | 131 ++++++++ include/elfwrite.h | 4 +- include/zipr_all.h | 1 + include/zipr_impl.h | 4 + src/SConscript | 3 +- src/ehwrite.cpp | 797 ++++++++++++++++++++++++++++++++++++++++++++ src/elfwrite.cpp | 41 --- src/zipr.cpp | 41 ++- 9 files changed, 976 insertions(+), 48 deletions(-) create mode 100644 include/ehwrite.h create mode 100644 src/ehwrite.cpp diff --git a/.gitattributes b/.gitattributes index 1c77dee..1f1c316 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,7 @@ /config.sub -text /configure -text /configure.in -text +include/ehwrite.h -text include/elfwrite.h -text include/plugin_man.h -text include/sled.h -text @@ -24,6 +25,7 @@ src/Makefile.in -text src/SConscript -text src/SConstruct -text src/dollop.cpp -text +src/ehwrite.cpp -text src/elfwrite.cpp -text src/main.cpp -text src/memory_space.cpp -text diff --git a/include/ehwrite.h b/include/ehwrite.h new file mode 100644 index 0000000..8a87636 --- /dev/null +++ b/include/ehwrite.h @@ -0,0 +1,131 @@ +#ifndef ElfWriter_h +#define ElfWriter_h + +#include <iostream> + +class EhWriter_t +{ + public: + virtual void GenerateNewEhInfo() =0; +}; + + +static const std::string ehframe_s_filename="ehframe.s"; +static const std::string ehframe_exe_filename="ehframe.exe"; + +template <int ptrsize> +class EhWriterImpl_t : public EhWriter_t +{ + private: + + class EhProgramListingManip_t : public libIRDB::EhProgramListing_t + { + public: + EhProgramListingManip_t(){} + EhProgramListingManip_t(const libIRDB::EhProgramListing_t &pgm) : libIRDB::EhProgramListing_t(pgm) { } + bool canExtend(const EhProgramListingManip_t &other); + void extend(const uint64_t inc_amt, const EhProgramListingManip_t &other); + private: + int getMergeIndex(const EhProgramListingManip_t &other); + bool isAdvanceDirective(const std::string &s); + + static const int DW_CFA_advance_loc1 = 0x02; + static const int DW_CFA_advance_loc2 = 0x03; + static const int DW_CFA_advance_loc4 = 0x04; + + }; + + class FDErepresentation_t; // forward decl + class CIErepresentation_t + { + public: + CIErepresentation_t(libIRDB::Instruction_t*, EhWriterImpl_t<ptrsize>* ehw); + void emitAssembly(std::ostream& out) {} + bool canSupport(libIRDB::Instruction_t* insn) const; + + private: + // need nothing? + + EhProgramListingManip_t pgm; + uint64_t code_alignment_factor; + int64_t data_alignment_factor; + uint64_t return_reg; + libIRDB::Relocation_t* personality_reloc; + + mutable bool has_been_output; + + friend class FDErepresentation_t; + friend EhWriterImpl_t<ptrsize>; + }; + + + class FDErepresentation_t + { + private: + + class LSDArepresentation_t + { + public: + LSDArepresentation_t(libIRDB::Instruction_t* insn); + void extend(libIRDB::Instruction_t* insn); + bool canExtend(libIRDB::Instruction_t* insn) const { (void)insn; return true; } + bool exists() const { return callsite_table.size() > 0; } + + struct call_site_t + { + libIRDB::Instruction_t* cs_insn_start; + libIRDB::Instruction_t* cs_insn_end; + libIRDB::Instruction_t* landing_pad; + int action_table_index; + std::set<libIRDB::Relocation_t*> actions; + }; + std::vector<call_site_t> callsite_table; + std::vector<std::set<libIRDB::Relocation_t*> > action_table; + std::vector<libIRDB::Relocation_t*> type_table; + + }; + + LSDArepresentation_t lsda; + CIErepresentation_t* cie; + libIRDB::virtual_offset_t start_addr; + libIRDB::virtual_offset_t end_addr; + libIRDB::virtual_offset_t last_advance_addr; + // the pgm for the fde + EhProgramListingManip_t pgm; + + public: + FDErepresentation_t(libIRDB::Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw); + void extend(libIRDB::Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw); + void emitAssembly(std::ostream& out); + bool canExtend(libIRDB::Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw); + bool hasLsda() const { return lsda.exists(); } + + friend EhWriterImpl_t<ptrsize>; + }; + + friend class FDErepresentation_t; + friend class CIErepresentation_t; + + ZiprImpl_t& zipr_obj; + std::vector<FDErepresentation_t*> all_fdes; + std::vector<CIErepresentation_t*> all_cies; + + void BuildFDEs(); + void GenerateEhOutput(); + void CompileEhOutput(); + void ScoopifyEhOutput(); + + public: + EhWriterImpl_t(ZiprImpl_t& p_zipr_obj) + : zipr_obj(p_zipr_obj) + + { + } + + virtual ~EhWriterImpl_t(); + + void GenerateNewEhInfo(); + +}; + +#endif diff --git a/include/elfwrite.h b/include/elfwrite.h index d984fab..0c412bb 100644 --- a/include/elfwrite.h +++ b/include/elfwrite.h @@ -1,6 +1,6 @@ -#ifndef ElfWriter_h -#define ElfWriter_h +#ifndef EhWriter_h +#define EhWriter_h #include <vector> #include <map> diff --git a/include/zipr_all.h b/include/zipr_all.h index 3d53ca6..8fdbe56 100644 --- a/include/zipr_all.h +++ b/include/zipr_all.h @@ -59,6 +59,7 @@ using namespace Zipr_SDK; #include <zipr_optimizations.h> #include <zipr_stats.h> #include <elfwrite.h> +#include <ehwrite.h> }; #endif diff --git a/include/zipr_impl.h b/include/zipr_impl.h index c4194c3..8406fbd 100644 --- a/include/zipr_impl.h +++ b/include/zipr_impl.h @@ -398,6 +398,8 @@ class ZiprImpl_t : public Zipr_t void dump_map(); + public: + virtual Zipr_SDK::MemorySpace_t *GetMemorySpace() { return &memory_space; } virtual Zipr_SDK::DollopManager_t *GetDollopManager() { return &m_dollop_mgr; } virtual ELFIO::elfio *GetELFIO() { return elfiop; } @@ -405,6 +407,8 @@ class ZiprImpl_t : public Zipr_t virtual Zipr_SDK::InstructionLocationMap_t *GetLocationMap() { return &final_insn_locations; } virtual Zipr_SDK::PlacementQueue_t* GetPlacementQueue() { return &placement_queue; } virtual Zipr_SDK::RangeAddress_t PlaceUnplacedScoops(Zipr_SDK::RangeAddress_t max); + virtual void RelayoutEhInfo(); + private: diff --git a/src/SConscript b/src/SConscript index 50a81a7..a13f761 100644 --- a/src/SConscript +++ b/src/SConscript @@ -4,7 +4,7 @@ import os Import('env') -myenv=env +myenv=env.Clone() myenv.Replace(SECURITY_TRANSFORMS_HOME=os.environ['SECURITY_TRANSFORMS_HOME']) myenv.Replace(ZIPR_HOME=os.environ['ZIPR_HOME']) myenv.Replace(ZIPR_SDK=os.environ['ZIPR_SDK']) @@ -22,6 +22,7 @@ files= ''' dollop.cpp zipr_dollop_man.cpp elfwrite.cpp + ehwrite.cpp ''' # ELFIO needs to be first so we get the zipr version instead of the sectrans version. the zipr version is modified to include get_offset. diff --git a/src/ehwrite.cpp b/src/ehwrite.cpp new file mode 100644 index 0000000..542c23a --- /dev/null +++ b/src/ehwrite.cpp @@ -0,0 +1,797 @@ + +#include <zipr_all.h> +#include <libIRDB-core.hpp> +#include <Rewrite_Utility.hpp> +#include <iostream> +#include <stdlib.h> +#include <string.h> +#include <algorithm> +#include <map> +#include <assert.h> +#include <sys/mman.h> +#include <ctype.h> +#include <iostream> // std::cout +#include <string> // std::string, std::to_string +#include <fstream> +#include <elf.h> + +#include "elfio/elfio.hpp" +#include "elfio/elfio_dump.hpp" +#include "targ-config.h" +#include "beaengine/BeaEngine.h" + +using namespace libIRDB; +using namespace std; +using namespace zipr; +using namespace ELFIO; + +template < typename T > std::string to_hex_string( const T& n ) +{ + std::ostringstream stm ; + stm << std::hex<< "0x"<< n ; + return stm.str() ; +} + +template<int ptrsize> +void EhWriterImpl_t<ptrsize>::GenerateNewEhInfo() +{ + + BuildFDEs(); + GenerateEhOutput(); + CompileEhOutput(); + ScoopifyEhOutput(); + +} + +template <int ptrsize> +bool EhWriterImpl_t<ptrsize>::CIErepresentation_t::canSupport(Instruction_t* insn) const +{ + // if the insn is missing info, we can support it. + if(insn==NULL) + return true; + if(insn->GetEhProgram()==NULL) + return true; + + // all info here. + + + // check that the program,CAF, DAF and RR match. if not, can't support + if(insn->GetEhProgram()->GetCIEProgram() != pgm || + insn->GetEhProgram()->GetCodeAlignmentFactor() != code_alignment_factor || + insn->GetEhProgram()->GetDataAlignmentFactor() != data_alignment_factor || + insn->GetEhProgram()->GetReturnRegNumber() != return_reg + ) + return false; + + auto personality_it=find_if( + insn->GetEhProgram()->GetRelocations().begin(), + insn->GetEhProgram()->GetRelocations().end(), + [](const Relocation_t* r) { return r->GetType()=="personality"; }); + + // lastly, check for a compatible personality reloc. + // if incoming has no personality, we better have no personality to match. + if(personality_it==insn->GetEhProgram()->GetRelocations().end()) + { + return personality_reloc==NULL; + } + + // incomming has personality, but do we? + if(personality_reloc==NULL) return false; + + // compare personalities. + if(personality_reloc->GetWRT() != (*personality_it)->GetWRT()) return false; + if(personality_reloc->GetAddend() != (*personality_it)->GetAddend()) return false; + + return true; +} + +template <int ptrsize> +EhWriterImpl_t<ptrsize>::CIErepresentation_t::CIErepresentation_t(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw) + : has_been_output(false) +{ + assert(insn && ehw && insn->GetEhProgram()); + + pgm = insn->GetEhProgram()->GetCIEProgram(); + code_alignment_factor = insn->GetEhProgram()->GetCodeAlignmentFactor(); + data_alignment_factor = insn->GetEhProgram()->GetDataAlignmentFactor(); + return_reg = insn->GetEhProgram()->GetReturnRegNumber(); + + auto personality_it=find_if( + insn->GetEhProgram()->GetRelocations().begin(), + insn->GetEhProgram()->GetRelocations().end(), + [](const Relocation_t* r) { return r->GetType()=="personality";}); + + personality_reloc = (personality_it==insn->GetEhProgram()->GetRelocations().end()) + ? (Relocation_t*)NULL + : *personality_it; +} + + +template <int ptrsize> +EhWriterImpl_t<ptrsize>::FDErepresentation_t::FDErepresentation_t(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw) + : + lsda(insn), + cie(NULL) +{ + auto cie_it=find_if( ehw->all_cies.begin(), ehw->all_cies.end(), [&](const CIErepresentation_t* candidate) + { + return candidate->canSupport(insn); + }); + + if(cie_it==ehw->all_cies.end()) + { + cie=new CIErepresentation_t(insn,ehw); + ehw->all_cies.push_back(cie); + } + else + cie=*cie_it; + + start_addr=ehw->zipr_obj.GetLocationMap()->at(insn); + last_advance_addr=start_addr; + end_addr=start_addr+insn->GetDataBits().size(); + pgm=EhProgramListingManip_t(insn->GetEhProgram()->GetFDEProgram()); +} + + +template <int ptrsize> +int EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::getMergeIndex(const EhProgramListingManip_t &other) +{ + auto other_index=(size_t)0; + for(const auto &this_ele : *this) + { + if(isAdvanceDirective(this_ele)) + continue; + + if(other_index >= other.size()) + return -1; + + if( this_ele!=other.at(other_index)) + return -1; + other_index++; + } + + return other_index; +} +template <int ptrsize> +bool EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::canExtend(const EhProgramListingManip_t &other) +{ + return getMergeIndex(other) != -1; +} + +template <int ptrsize> +void EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::extend(const uint64_t inc_amt, const EhProgramListingManip_t &other) +{ + + // make an advance directive + string ehinsn; + ehinsn.resize(5); + ehinsn[0]=DW_CFA_advance_loc4; + for(auto i=0;i<4;i++) + ehinsn[i+1]=((const char*)(&inc_amt))[i]; + + // add it with this->push_back() + this->push_back(ehinsn); + + // add elements from other[merge_index]-other[other.size()] + auto merge_index=getMergeIndex(other); + assert(merge_index>=0); + for_each(other.begin()+merge_index,other.end(), [&](const string& s) + { + this->push_back(s); + }); + + +} + +template <int ptrsize> +bool EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::isAdvanceDirective(const string &s) +{ + // make sure uint8_t is an unsigned char. + static_assert(std::is_same<unsigned char, uint8_t>::value, "uint8_t is not unsigned char"); + + auto data=s.data(); + auto opcode=data[0]; + auto opcode_upper2=(uint8_t)(opcode >> 6); + auto opcode_lower6=(uint8_t)(opcode & (0x3f)); + + switch(opcode_upper2) + { + case 1: + { + return true; + } + case 0: + { + switch(opcode_lower6) + { + case DW_CFA_advance_loc1: + case DW_CFA_advance_loc2: + case DW_CFA_advance_loc4: + return true; + + } + } + } + return false; + +} + +template <int ptrsize> +EhWriterImpl_t<ptrsize>::FDErepresentation_t::LSDArepresentation_t::LSDArepresentation_t(Instruction_t* insn) +{ + extend(insn); +} + +template <int ptrsize> +void EhWriterImpl_t<ptrsize>::FDErepresentation_t::LSDArepresentation_t::extend(Instruction_t* insn) +{ + // if there's no call site info, the LSDA doesn't need an extension. + if(insn->GetEhCallSite() == NULL) + return; + + // FIXME: optimization possibilty: see if the last call site in the table + // has the same set of catch-types + landing_pad and is "close enough" to this insn. + // if so, combine. + + cout<<"Creating call sites in LSDA for "<<hex<<insn->GetBaseID()<<":"<<insn->getDisassembly()<<endl; + + // just create a new entry in the CS table.. + auto cs=(call_site_t){0}; + + cs.cs_insn_start=insn; + cs.cs_insn_end=insn; + cs.landing_pad=insn->GetEhCallSite()->GetLandingPad(); + + + // go through the relocations on the eh call site and + // resolve each one by putting it into a set. + // the set will be (non-duplicating) inserted as a "entry" (really multiple entries) + // into the action table, + // Each reloc will also get a non-duplicating insert into the type table. + for(const auto &reloc : insn->GetEhCallSite()->GetRelocations()) + { + const auto wrt_scoop=dynamic_cast<DataScoop_t*>(reloc->GetWRT()); + if(reloc->GetWRT()==NULL) + cout<<"\tFound reloc: NULL (catch all)"<<endl; + else if(wrt_scoop) + cout<<"\tFound reloc: scoop "<<wrt_scoop->GetName()<<"+0x"<<hex<<reloc->GetAddend()<<endl; + else + cout<<"\tFound reloc: unexpected type? "<<endl; + + // for now, this is the only supported reloc type on a EhCallSite + assert(reloc->GetType()=="type_table_entry"); + cs.actions.insert(reloc); + auto tt_it=find(type_table.begin(),type_table.end(), reloc); + if(tt_it==type_table.end()) + type_table.push_back(reloc); + } + + // non-duplciating insert into the action table + auto at_it=find(action_table.begin(),action_table.end(), cs.actions); + if(at_it==action_table.end()) + { + // actions will be at the end of the action table. + cs.action_table_index=action_table.size(); + + // add to the action table + action_table.push_back(cs.actions); + } + else + { + // calc which entry in the action table for the call site. + cs.action_table_index=at_it-action_table.begin(); + } + + // the call site will index the action table at the end of the action table. + callsite_table.push_back(cs); +} + +template <int ptrsize> +bool EhWriterImpl_t<ptrsize>::FDErepresentation_t::canExtend(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw) +{ + const auto insn_addr=ehw->zipr_obj.GetLocationMap()->at(insn); + const auto new_fde_thresh=100; + + if(insn_addr<start_addr) + return false; + + if(end_addr + new_fde_thresh < insn_addr) + return false; + + return pgm.canExtend(insn->GetEhProgram()->GetFDEProgram()) && + lsda.canExtend(insn); + + +} + +template <int ptrsize> +void EhWriterImpl_t<ptrsize>::FDErepresentation_t::extend(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw) +{ + const auto insn_addr=ehw->zipr_obj.GetLocationMap()->at(insn); + const auto new_end_addr=insn_addr+insn->GetDataBits().size(); + const auto incr_amnt=insn_addr-last_advance_addr; + last_advance_addr=insn_addr; + + // add appropriate instructions to the pgm. + pgm.extend((incr_amnt)/cie->code_alignment_factor, insn->GetEhProgram()->GetFDEProgram()); + + lsda.extend(insn); + + // extend the end + end_addr=new_end_addr; + +} + +template <int ptrsize> +void EhWriterImpl_t<ptrsize>::FDErepresentation_t::emitAssembly(ostream& out) +{ + out<<"Hello"<<endl; +} + +template<int ptrsize> +void EhWriterImpl_t<ptrsize>::BuildFDEs() +{ + // build a map of the instructions in program order + map<virtual_offset_t,Instruction_t*> insn_in_order; + for(const auto& this_pair : *zipr_obj.GetLocationMap()) + insn_in_order[this_pair.second]=this_pair.first; + + + // build the fdes (and cies/lsdas for this insn, starting with a null fde in case none exist + auto current_fde=(FDErepresentation_t*)NULL; + auto insns_with_frame=0; + +// for_each instruction in program order + for(const auto& this_pair : insn_in_order) + { + const auto &this_insn=this_pair.second; + const auto &this_addr=this_pair.first; + + // no eh pgm or call site? no worries, just ignore this insn + if(this_insn->GetEhProgram()==NULL && this_insn->GetEhCallSite()==NULL) + continue; + + insns_with_frame++; + + // if it has an unwinder and/or a call site, we will need an fde. + + // end this fde + if(current_fde && !current_fde->canExtend(this_insn, this)) + { + if(getenv("EH_VERBOSE")!=NULL) + cout<<"Ending FDE because insn "<<hex<<this_insn->GetBaseID()<<":"<<this_insn->getDisassembly()<<" doesn't fit at " << this_addr<< endl; + current_fde=NULL; + } + + + // if we need to start a new fde, create one. + if(current_fde==NULL) + { + if(getenv("EH_VERBOSE")!=NULL) + cout<<"Creating new FDE for "<<hex<<this_insn->GetBaseID()<<":"<<this_insn->getDisassembly()<< " at " << this_addr<<endl; + current_fde=new FDErepresentation_t(this_insn,this); + all_fdes.push_back(current_fde); + } + else + { + if(getenv("EH_VERBOSE")!=NULL) + cout<<"Extending new FDE for "<<hex<<this_insn->GetBaseID()<<":"<<this_insn->getDisassembly()<<" at " << this_addr <<endl; + current_fde->extend(this_insn,this); + } + } + cout<<"#ATTRIBUTE fdes_calculated="<<dec<<all_fdes.size()<<endl; + cout<<"#ATTRIBUTE cies_calculated="<<dec<<all_cies.size()<<endl; + cout<<"#ATTRIBUTE insns_with_eh_info="<<dec<<insns_with_frame<<endl; + cout<<"#ATTRIBUTE avg_insns_per_fde="<<dec<<insns_with_frame/(float)all_fdes.size()<<endl; +} + +template<int ptrsize> +void EhWriterImpl_t<ptrsize>::GenerateEhOutput() +{ + + auto output_program=[&](const EhProgramListingManip_t& p, ostream & out) + { + auto flags=out.flags();//save flags + for(const auto &s : p) + { + out<<" .byte "; + auto first=true; + for(const auto &c : s) + { + if(!first) + { + out<<", "; + } + else + first=false; + out<<"0x"<<hex<<setfill('0')<<setw(2)<<((int)c&0xff); + } + out << endl; + } + out.flags(flags); // restore flags + }; + const auto output_lsda=[&](const FDErepresentation_t* fde, ostream& out, const uint32_t lsda_num) -> void + { + const auto lsda=&fde->lsda; + + const auto output_action=[&](const set<Relocation_t*> acts, const uint32_t act_num) -> void + { + const auto zero_it=find_if(acts.begin(), acts.end(), [](const Relocation_t* act) { return act->GetWRT()==NULL; }); + const auto has_zero=(zero_it!=acts.end()); + + // counter for the element in this action table entry. + auto act_entry_num=acts.size()-1; + + if(has_zero) + { + const auto zero_reloc=*zero_it; + const auto tt_it=find(lsda->type_table.begin(), lsda->type_table.end(), zero_reloc); + assert(tt_it != lsda->type_table.end()); + const auto tt_index=tt_it-lsda->type_table.begin(); + out<<"LSDA"<<dec<<lsda_num<<"_act"<<act_num<<"_start_entry"<<act_entry_num<<":"<<endl; + out<<" .uleb128 "<<dec<<1+tt_index<<endl; + out<<" .uleb128 0 "<<endl; + act_entry_num--; + + } + + for(const auto& act : acts) + { + // do nothing for a + if(act->GetWRT()==NULL) continue; + + const auto tt_it=find(lsda->type_table.begin(), lsda->type_table.end(), act); + assert(tt_it != lsda->type_table.end()); + const auto tt_index=tt_it-lsda->type_table.begin(); + out<<"LSDA"<<dec<<lsda_num<<"_act"<<act_num<<"_start_entry"<<act_entry_num<<""<<":"<<endl; + out<<" .uleb128 "<<dec<<1+tt_index<<endl; + if(act_entry_num==acts.size()-1) + out<<" .uleb128 0 "<<endl; + else + out<<" .uleb128 LSDA"<<lsda_num<<"_act"<<act_num<<"_start_entry"<<act_entry_num+1<<" - . "<<endl; + act_entry_num--; + } + //out<<" .equ LSDA"<<lsda_num<<"_act"<<act_num<<"_start, LSDA"<<lsda_num<<"_act"<<act_num<<"_start_entry0"<<endl; + }; + + + const auto output_callsite=[&](const typename FDErepresentation_t::LSDArepresentation_t::call_site_t &cs, const uint32_t cs_num) -> void + { + const auto cs_start_addr=zipr_obj.GetLocationMap()->at(cs.cs_insn_start); + const auto cs_end_addr=zipr_obj.GetLocationMap()->at(cs.cs_insn_start)+cs.cs_insn_start->GetDataBits().size(); + const auto cs_len=cs_end_addr-cs_start_addr; + out<<"LSDA"<<dec<<lsda_num<<"_cs_tab_entry"<<cs_num<<"_start:"<<endl; + out<<" # 1) start of call site relative to FDE start addr"<<endl; + out<<" .uleb128 0x"<<hex<<cs_start_addr<<" - 0x"<<hex<<fde->start_addr<<endl; + out<<" # 2) length of call site"<<endl; + out<<" .uleb128 "<<dec<<cs_len<<endl; + if(cs.landing_pad) + { + const auto lp_addr=zipr_obj.GetLocationMap()->at(cs.landing_pad); + out<<" # 3) the landing pad, or 0 if none exists."<<endl; + out<<" .uleb128 0x"<<hex<<lp_addr<<" - 0x"<<hex<<fde->start_addr<<endl; + } + else + { + out<<" # 3) the landing pad, or 0 if none exists."<<endl; + out<<" .uleb128 0"<<endl; + } + if(cs.actions.size() > 0 ) + { + out<<" # 4) index into action table + 1 -- 0 indicates unwind only"<<endl; + out<<" .uleb128 1 + LSDA"<<dec<<lsda_num<<"_act"<<cs.action_table_index<<"_start_entry0 - LSDA"<<dec<<lsda_num<<"_action_tab_start"<<endl; + } + else + { + out<<" # 4) index into action table + 1 -- 0 indicates unwind only"<<endl; + out<<" .uleb128 0 # no actions!" << endl; + } + out<<"LSDA"<<dec<<lsda_num<<"_cs_tab_entry"<<cs_num<<"_end:"<<endl; + + }; + + out<<"LSDA"<<dec<<lsda_num<<":"<<endl; + if(!lsda->exists()) + { + return; + } + out<<""<<endl; + out<<" # 1) encoding of next field "<<endl; + out<<" .byte 0xff # DW_EH_PE_omit (0xff)"<<endl; + out<<""<<endl; + out<<" # 2) landing pad base, if omitted, use FDE start addr"<<endl; + out<<" # .<fdebasetype> <fdebase> -- omitted. "<<endl; + out<<""<<endl; + out<<" # 3) encoding of type table entries"<<endl; + out<<" .byte 0x3 # DW_EH_PE_udata4"<<endl; + out<<""<<endl; + out<<" # 4) type table pointer -- always a uleb128"<<endl; + out<<" .uleb128 LSDA"<<lsda_num<<"_type_table_end - LSDA"<<lsda_num<<"_tt_ptr_end"<<endl; + out<<"LSDA"<<lsda_num<<"_tt_ptr_end:"<<endl; + out<<""<<endl; + out<<" # 5) call site table encoding"<<endl; + out<<" .byte 0x1 # DW_EH_PE_uleb128 "<<endl; + out<<""<<endl; + out<<" # 6) the length of the call site table"<<endl; + out<<" .uleb128 LSDA"<<lsda_num<<"_cs_tab_end-LSDA"<<lsda_num<<"_cs_tab_start"<<endl; + out<<"LSDA"<<lsda_num<<"_cs_tab_start:"<<endl; + + + // output call site table + auto cs_num=0; + for(const auto & cs : lsda->callsite_table) + { + output_callsite(cs,cs_num++); + } + out<<"LSDA"<<dec<<lsda_num<<"_cs_tab_end:"<<endl; + + // output action table + out<<"LSDA"<<dec<<lsda_num<<"_action_tab_start:"<<endl; + auto act_num=0; + for(const auto & act : lsda->action_table) + { + output_action(act,act_num++); + } + out<<"LSDA"<<dec<<lsda_num<<"_action_tab_end:"<<endl; + + + out<<"LSDA"<<dec<<lsda_num<<"_type_table_start:"<<endl; + for_each( lsda->type_table.rbegin(), lsda->type_table.rend(), [&](const Relocation_t* reloc) + { + if(reloc->GetWRT()==NULL) + { + out<<" .int 0x0"<<endl; + } + else + { + const auto scoop=dynamic_cast<DataScoop_t*>(reloc->GetWRT()); + assert(scoop); + const auto final_addr=scoop->GetStart()->GetVirtualOffset() + reloc->GetAddend(); + out<<" .int 0x"<<hex<<final_addr<<endl; + + } + }); + out<<"LSDA"<<dec<<lsda_num<<"_type_table_end:"<<endl; + }; + const auto output_cie=[&](const CIErepresentation_t* cie, ostream& out) -> void + { + assert(cie); + if(cie->has_been_output) + return; + + const auto cie_pos_it=std::find(all_cies.begin(), all_cies.end(), cie); + assert(cie_pos_it!=all_cies.end()); + + const auto personality_scoop=cie->personality_reloc ? dynamic_cast<DataScoop_t*> (cie->personality_reloc->GetWRT()) : (DataScoop_t*)NULL; + const auto personality_insn =cie->personality_reloc ? dynamic_cast<Instruction_t*>(cie->personality_reloc->GetWRT()) : (Instruction_t*)NULL; + const auto personality_addend=cie->personality_reloc ? cie->personality_reloc->GetAddend() : 0; + + const auto cie_pos=cie_pos_it-all_cies.begin(); + + cie->has_been_output=true; + out<<"# cie "<<dec<<cie_pos<<""<<endl; + out<<"Lcie"<<cie_pos<<":"<<endl; + out<<" .int Lcie"<<cie_pos<<"_end - Lcie"<<cie_pos<<" - 4 # length of this record. -4 because length doesn't include this field"<<endl; + out<<" .int 0 # cie (not fde)"<<endl; + out<<" .byte 3 # version"<<endl; + out<<" .asciz \"zPLR\" # aug string."<<endl; + out<<" .uleb128 "<<dec<<cie->code_alignment_factor<<" # code alignment factor"<<endl; + out<<" .sleb128 "<<dec<<cie->data_alignment_factor<<" # data alignment factor"<<endl; + out<<" .uleb128 "<<dec<<cie->return_reg<<" # return address reg."<<endl; + out<<" # encode the Z (length)"<<endl; + out<<" .sleb128 Lcie"<<cie_pos<<"_aug_data_end-Lcie"<<cie_pos<<"_aug_data_start # Z -- handle length field"<<endl; + out<<"Lcie"<<cie_pos<<"_aug_data_start:"<<endl; + out<<""<<endl; + if(personality_scoop) + { + auto personality_value=personality_scoop->GetStart()->GetVirtualOffset()+personality_addend; + out<<" #encode the P (personality encoding + personality routine)"<<endl; + out<<" .byte 0x80 | 0x10 | 0x0B # personality pointer encoding DH_EH_PE_indirect (0x80) | pcrel | sdata4"<<endl; + out<<" .int "<<personality_value<<" - . # actual personality routine, encoded as noted in prev line."<<endl; + } + else if(personality_insn) + { + const auto personality_insn_addr=zipr_obj.GetLocationMap()->at(personality_insn); + const auto personality_value=personality_insn_addr+personality_addend; + out<<" #encode the P (personality encoding + personality routine)"<<endl; + out<<" .byte 0x10 | 0x0B # personality pointer encoding pcrel | sdata4"<<endl; + out<<" .int "<<personality_value<<" - . # actual personality routine, encoded as noted in prev line."<<endl; + } + else + { + assert(cie->personality_reloc==NULL || cie->personality_reloc->GetWRT()==NULL); + out<<" #encode the P (personality encoding + personality routine)"<<endl; + out<<" .byte 0x0B # personality pointer encoding sdata4"<<endl; + out<<" .int 0 # actual personality routine, encoded as noted in prev line."<<endl; + } + out<<""<<endl; + out<<" # encode L (lsda encoding) "<<endl; + out<<" .byte 0x03 # LSDA encoding (udata4 -- or maybe later pcrel|sdata4 ? )"<<endl; + out<<""<<endl; + out<<" # encode R (FDE encoding) "<<endl; + out<<" .byte 0x10 | 0x0B # FDE encoding (pcrel | sdata4)"<<endl; + out<<"Lcie"<<cie_pos<<"_aug_data_end:"<<endl; + out<<" # CIE program"<<endl; + output_program(cie->pgm,out); + out<<""<<endl; + out<<" # pad with nops"<<endl; + out<<" .align 4, 0"<<endl; + out<<"Lcie"<<cie_pos<<"_end:"<<endl; + + }; + auto output_fde=[&](const FDErepresentation_t* fde, ostream& out, const uint32_t fde_num) -> void + { + assert(fde && fde->cie); + output_cie(fde->cie,out); + + + auto cie_pos_it=std::find(all_cies.begin(), all_cies.end(), fde->cie); + assert(cie_pos_it!=all_cies.end()); + auto cie_pos=cie_pos_it-all_cies.begin(); + + out<<"#fde "<<dec<<fde_num<<""<<endl; + out<<"Lfde"<<fde_num<<":"<<endl; + out<<" .int Lfde"<<fde_num<<"_end - Lfde"<<fde_num<<" - 4 # length of this record. -4 because " + "length doesn't include this field."<<endl; + out<<" .int . - Lcie"<<cie_pos<<" # this is an FDE (not a " + "cie), and it's cie is CIE"<<cie_pos<<". byte offset from start of field."<<endl; + out<<" .int 0x"<<hex<<fde->start_addr<<dec<<" - . # FDE start addr"<<endl; + out<<" .int "<<dec<<fde->end_addr-fde->start_addr<<" # fde range length (i.e., can calc the " + "fde_end_addr from this -- note that pcrel is ignored here!)"<<endl; + out<<" #encode Z (length)"<<endl; + out<<" .uleb128 Lfde"<<fde_num<<"_aug_data_end-Lfde"<<fde_num<<"_aug_data_start"<<endl; + out<<"Lfde"<<fde_num<<"_aug_data_start:"<<endl; + out<<" #encode L (LSDA) "<<endl; + if(fde->hasLsda()) + out<<" .int LSDA"<<fde_num<<" # LSDA hard coded here"<<endl; + else + out<<" .int 0 # no LSDA "<<endl; + out<<"Lfde"<<fde_num<<"_aug_data_end:"<<endl; + out<<""<<endl; + out<<" # FDE"<<fde_num<<" program"<<endl; + output_program(fde->pgm,out); + out<<" .align 4, 0"<<endl; + out<<" Lfde"<<fde_num<<"_end:"<<endl; + + }; + auto generate_eh_frame_hdr=[&](ostream& out) -> void + { + out<<".section eh_frame_hdr, \"a\", @progbits"<<endl; + out<<"eh_frame_hdr_start:"<<endl; + out<<" .byte 1 # version"<<endl; + out<<" .byte 0x10 | 0x0B # encoding for pointer to eh-frame -- DH_EH_PE_pcrel (0x10) | DH_EH_PE_sdata4 (0x0B)"<<endl; + out<<" .byte 0x03 # encoding for ; of entries in eh-frame-hdr -- BDH_EH_PE_udata4 (0x03)"<<endl; + out<<" .byte 0x30 | 0x0B # encoding for pointers (to fdes) held in the eh-frame-hdr header " + "-- DH_EH_PE_datarel (0x30) | DH_EH_PE_sdata4 (0x0b) " <<endl; + + out<<" .int Lfde_table - . # pointer to fde_table, encoded as an sdata4, pcrel"<<endl; + out<<" .int (eh_frame_table_end-eh_frame_table)/8 # number of FDEs in the header."<<endl; + out<<" .align 4"<<endl; + out<<"eh_frame_table:"<<endl; + out<<" # fde pointers"<<endl; + + for(auto fde_num=0; fde_num < all_fdes.size(); fde_num++) + { + const auto& fde=all_fdes[fde_num]; + out<<" .int 0x"<<hex<<fde->start_addr<<" - eh_frame_hdr_start"<<endl; + out<<" .int Lfde"<<dec<<fde_num<<" - eh_frame_hdr_start"<<endl; + } + + out<<"eh_frame_table_end:"<<endl; + + }; + auto generate_eh_frame=[&](ostream& out) -> void + { + out<<".section eh_frame, \"a\", @progbits"<<endl; + out<<"Lfde_table: # needed for xref to eh_frame_hdr" <<endl; + + auto fde_num=0; + for(const auto& fde: all_fdes) + { + output_fde(fde,out, fde_num++); + } + }; + auto generate_gcc_except_table=[&](ostream& out) -> void + { + out<<".section gcc_except_table, \"a\", @progbits"<<endl; + auto lsda_num=0; + for(const auto& fde: all_fdes) + { + output_lsda(fde,out,lsda_num++); + } + }; + + ofstream fout(ehframe_s_filename, std::ofstream::out); + if(!fout) + { + cerr<<"Fatal: cannot open "<<ehframe_s_filename<<"."<<endl; + exit(2); + } + + generate_eh_frame_hdr(fout); + generate_eh_frame(fout); + generate_gcc_except_table(fout); +} + +template<int ptrsize> +void EhWriterImpl_t<ptrsize>::CompileEhOutput() +{ + auto page_round_up=[](const uintptr_t x) -> uintptr_t + { + auto page_size=(uintptr_t)PAGE_SIZE; + return ( (((uintptr_t)(x)) + page_size-1) & (~(page_size-1)) ); + }; + + // find maximum used scoop address. + const auto max_used_addr=std::max_element( + zipr_obj.GetFileIR()->GetDataScoops().begin(), + zipr_obj.GetFileIR()->GetDataScoops().end(), + [&](const DataScoop_t* a, const DataScoop_t* b) + { + assert(a && b && a->GetEnd() && b->GetEnd()) ; + return a->GetEnd()->GetVirtualOffset() < b->GetEnd()->GetVirtualOffset(); + } + ); + + // round it up and stringify it. + const auto eh_frame_hdr_addr=page_round_up((*max_used_addr)->GetEnd()->GetVirtualOffset()); + const auto eh_frame_hdr_addr_str=to_hex_string(eh_frame_hdr_addr); + + // create and execute the command to build the ehframe. + auto cmd=(string)"$PEASOUP_HOME/tools/eh_frame_tools/eh_to_bin.sh "+ehframe_s_filename+" "+eh_frame_hdr_addr_str+" "+ehframe_exe_filename; + auto res=system(cmd.c_str()); + + // err check. + if( res==-1 || WEXITSTATUS(res)!=0 ) + { + cerr<<"Cannot compile eh_frame."<<endl; + exit(2); + } +} + +template<int ptrsize> +void EhWriterImpl_t<ptrsize>::ScoopifyEhOutput() +{ + ELFIO::elfio ehframe_exe_elfio; + ehframe_exe_elfio.load(ehframe_exe_filename); + + auto to_scoop=[&](const string &secname)->void + { + auto sec=ehframe_exe_elfio.sections[secname]; + + // if sec is missing, don't scoopify. + + if(sec==NULL) return; + auto data=string(sec->get_data(), sec->get_size()); + auto start_vo=sec->get_address(); + auto start_addr=new AddressID_t(BaseObj_t::NOT_IN_DATABASE, BaseObj_t::NOT_IN_DATABASE, start_vo); + auto end_vo=sec->get_address()+sec->get_size()-1; + auto end_addr=new AddressID_t(BaseObj_t::NOT_IN_DATABASE, BaseObj_t::NOT_IN_DATABASE, end_vo); + auto new_scoop=new DataScoop_t(BaseObj_t::NOT_IN_DATABASE, secname, start_addr,end_addr,NULL,4,false,data); + + zipr_obj.GetFileIR()->GetAddresses().insert(start_addr); + zipr_obj.GetFileIR()->GetAddresses().insert(end_addr); + zipr_obj.GetFileIR()->GetDataScoops().insert(new_scoop); + }; + + to_scoop(".eh_frame_hdr"); + to_scoop(".eh_frame"); + to_scoop(".gcc_except_table"); + + +} + +template<int ptrsize> +EhWriterImpl_t<ptrsize>::~EhWriterImpl_t() +{ + for(const auto &i : all_fdes) delete i; + for(const auto &i : all_cies) delete i; +} + + +/* make sure these get compiled */ +namespace zipr +{ +template class EhWriterImpl_t<8>; +template class EhWriterImpl_t<4>; +}; diff --git a/src/elfwrite.cpp b/src/elfwrite.cpp index 2b2efad..b75babd 100644 --- a/src/elfwrite.cpp +++ b/src/elfwrite.cpp @@ -663,47 +663,6 @@ bool ElfWriterImpl<T_Elf_Ehdr,T_Elf_Phdr,T_Elf_Addr,T_Elf_Shdr,T_Elf_Sym, T_Elf_ std::vector<T_Elf_Phdr> relro_phdrs; -#if 0 - for_each(new_phdrs.begin(), new_phdrs.end(), [&](const T_Elf_Phdr& phdr) - { - if(phdr.p_type==PT_LOAD) - { - //auto do_relro=[&this,phdr,&relro_phdrs](const virtual_offset_t start, const virtual_offset_t end) - auto do_relro=[&](virtual_offset_t start, virtual_offset_t end) - { - if(! (pagemap.at(start)).is_relro) - return; - - cout<<"Creating relro for "<<hex<<start<<"-"<<end<<endl; - - T_Elf_Phdr relro_phdr=phdr; - relro_phdr.p_type=PT_GNU_RELRO; - relro_phdr.p_memsz=end-start+1; - relro_phdr.p_filesz=end-start+1; - relro_phdr.p_vaddr=start; - relro_phdr.p_paddr=start; - relro_phdr.p_offset= phdr.p_offset+start-phdr.p_vaddr; - relro_phdr.p_flags=4; - - relro_phdrs.push_back(relro_phdr); - }; - - bool prev_relro=pagemap[phdr.p_vaddr].is_relro; - virtual_offset_t prev_i=phdr.p_vaddr, i=0; - for(i=phdr.p_vaddr; i<phdr.p_vaddr+phdr.p_memsz;i+=PAGE_SIZE) - { - if(prev_relro != pagemap.at(i).is_relro) - { - do_relro(prev_i, i-1); - prev_i=i; - prev_relro=pagemap.at(i).is_relro; - - } - } - do_relro(prev_i, i-1); - } - }); -#endif new_phdrs.insert(new_phdrs.end(), relro_phdrs.begin(), relro_phdrs.end()); #ifdef CGC diff --git a/src/zipr.cpp b/src/zipr.cpp index c55873d..041e99d 100644 --- a/src/zipr.cpp +++ b/src/zipr.cpp @@ -927,7 +927,7 @@ void ZiprImpl_t::PreReserve2ByteJumpTargets() * b. If i has prereserved space associated with it, we * we clear that space. */ - printf("Warning: No location for near jump reserved at 0x%x.\n", addr); + cout<<"Warning: No location for near jump reserved at 0x"<<hex<<addr<<"."<<endl; /* * The first thing that we have to do is to tell @@ -948,7 +948,8 @@ void ZiprImpl_t::PreReserve2ByteJumpTargets() for (RangeAddress_t i = addr; i<end_of_sled; i++) { Instruction_t *found_pinned_insn = NULL; - if (found_pinned_insn = FindPinnedInsnAtAddr(i)) + found_pinned_insn = FindPinnedInsnAtAddr(i); + if (found_pinned_insn) { /* * TODO: Continue from here. Continue implementing the above @@ -1286,7 +1287,7 @@ RangeAddress_t ZiprImpl_t::Do68Sled(RangeAddress_t addr) /* * Put down the sled. */ - for(size_t i=0;i<sled_size;i++) + for(auto i=0;i<sled_size;i++) { if (m_verbose) cout << "Adding 68 at " @@ -1428,7 +1429,7 @@ int ZiprImpl_t::Calc68SledSize(RangeAddress_t addr, size_t sled_overhead) int sled_size=0; while(true) { - int i=0; + auto i=(size_t)0; for(i=0;i<sled_overhead;i++) { if (FindPinnedInsnAtAddr(addr+sled_size+i)) @@ -3765,6 +3766,11 @@ void ZiprImpl_t::OutputBinaryFile(const string &name) #endif + // now that the textra scoop has been crated and setup, we have the info we need to + // re-generate the eh information. + RelayoutEhInfo(); + + // create the output file in a totally different way using elfwriter. later we may // use this instead of the old way. @@ -4255,3 +4261,30 @@ void ZiprImpl_t::FixMultipleFallthroughs() cout<<"#ATTRIBUTE zipr::jumps_inserted_for_multiple_fallthroughs="<<dec<<count<<endl; } + + +void ZiprImpl_t::RelayoutEhInfo() +{ + const auto found_eh_ir_it = find_if( + m_firp->GetInstructions().begin(), + m_firp->GetInstructions().end(), + [](const Instruction_t* i) + { + return (i->GetEhProgram()!=NULL || i->GetEhCallSite()!=NULL); + } + ); + + // do nothing if we didn't find any IR. + if(found_eh_ir_it==m_firp->GetInstructions().end()) + return; + + auto eh = (EhWriter_t *)NULL; + if(m_firp->GetArchitectureBitWidth()==64) + eh=new EhWriterImpl_t<8>(*this); + else if(m_firp->GetArchitectureBitWidth()==32) + eh=new EhWriterImpl_t<4>(*this); + else + assert(0); + + eh->GenerateNewEhInfo(); +} -- GitLab