From 72be39879b01e6c54865c935a1894c8eb2b1b8b8 Mon Sep 17 00:00:00 2001 From: whh8b <whh8b@git.zephyr-software.com> Date: Fri, 24 Oct 2014 17:35:06 +0000 Subject: [PATCH] First pass at refactoring memory range operations --- .gitattributes | 2 + include/memory_space.h | 57 +++++++++++ include/zipr.h | 18 +--- include/zipr_all.h | 1 + src/Makefile | 2 +- src/memory_space.cpp | 196 ++++++++++++++++++++++++++++++++++++ src/zipr.cpp | 219 ++++------------------------------------- 7 files changed, 280 insertions(+), 215 deletions(-) create mode 100644 include/memory_space.h create mode 100644 src/memory_space.cpp diff --git a/.gitattributes b/.gitattributes index 7e714e6..d521160 100644 --- a/.gitattributes +++ b/.gitattributes @@ -18,6 +18,7 @@ callbacks/libc/src/Makefile.in -text callbacks/libc/src/cgc.s -text callbacks/libc/src/malloc.c -text callbacks/libc/src/unistd.c -text +include/memory_space.h -text include/range.h -text include/unresolved.h -text include/zipr.h -text @@ -27,6 +28,7 @@ include/zipr_options.h -text include/zipr_stats.h -text src/Makefile -text src/main.cpp -text +src/memory_space.cpp -text src/zipr.cpp -text src/zipr_options.cpp -text src/zipr_stats.cpp -text diff --git a/include/memory_space.h b/include/memory_space.h new file mode 100644 index 0000000..2270c63 --- /dev/null +++ b/include/memory_space.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (c) 2014 Zephyr Software LLC. All rights reserved. + * + * This software is furnished under a license and/or other restrictive + * terms and may be used and copied only in accordance with such terms + * and the inclusion of the above copyright notice. This software or + * any other copies thereof may not be provided or otherwise made + * available to any other person without the express written consent + * of an authorized representative of Zephyr Software LCC. Title to, + * ownership of, and all rights in the software is retained by + * Zephyr Software LCC. + * + * Zephyr Software LLC. Proprietary Information + * + * Unless otherwise specified, the information contained in this + * directory, following this legend, and/or referenced herein is + * Zephyr Software LLC. (Zephyr) Proprietary Information. + * + * CONTACT + * + * For technical assistance, contact Zephyr Software LCC. at: + * + * + * Zephyr Software, LLC + * 2040 Tremont Rd + * Charlottesville, VA 22911 + * + * E-mail: jwd@zephyr-software.com + **************************************************************************/ + +#ifndef memory_space_h +#define memory_space_h + +class MemorySpace_t +{ + public: + MemorySpace_t() { } + + // range operatations + void SplitFreeRange(RangeAddress_t addr); + void MergeFreeRange(RangeAddress_t addr); + std::list<Range_t>::iterator FindFreeRange(RangeAddress_t addr); + Range_t GetFreeRange(int size); + void AddFreeRange(Range_t newRange); + + // queries about free areas. + bool AreBytesFree(RangeAddress_t addr, int num_bytes); + bool IsByteFree(RangeAddress_t addr); + bool IsValidRange(std::list<Range_t>::iterator it); + + int GetRangeCount(); + + protected: + std::list<Range_t> free_ranges; // keep ordered +}; + +#endif diff --git a/include/zipr.h b/include/zipr.h index 56323c7..970d104 100644 --- a/include/zipr.h +++ b/include/zipr.h @@ -40,7 +40,7 @@ class Zipr_t { public: Zipr_t(libIRDB::FileIR_t* p_firp, Options_t &p_opts) - : m_firp(p_firp), m_opts(p_opts) + : m_firp(p_firp), m_opts(p_opts), memory_space() { }; @@ -67,17 +67,6 @@ class Zipr_t void UpdateCallbacks(); void PrintStats(); - - // range operatations - void SplitFreeRange(RangeAddress_t addr); - void MergeFreeRange(RangeAddress_t addr); - std::list<Range_t>::iterator FindFreeRange(RangeAddress_t addr); - Range_t GetFreeRange(int size); - - // queries about free areas. - bool AreBytesFree(RangeAddress_t addr, int num_bytes); - bool IsByteFree(RangeAddress_t addr); - // emitting bytes. void PlopByte(RangeAddress_t addr, char the_byte); void PlopBytes(RangeAddress_t addr, const char the_byte[], int num); @@ -118,9 +107,7 @@ class Zipr_t private: // structures necessary for ZIPR algorithm. std::set<UnresolvedUnpinned_t> unresolved_unpinned_addrs; - std::list<Range_t> free_ranges; // keep ordered std::set<UnresolvedPinned_t> unresolved_pinned_addrs; - std::list<Range_t> pinned_ranges; // keep ordered std::multimap<UnresolvedUnpinned_t,Patch_t> patch_list; // map of where bytes will actually go. @@ -144,8 +131,7 @@ class Zipr_t // records where we will insert extra bytes into the program. RangeAddress_t start_of_new_space; - - + MemorySpace_t memory_space; }; #endif diff --git a/include/zipr_all.h b/include/zipr_all.h index 3ec3341..9a0f477 100644 --- a/include/zipr_all.h +++ b/include/zipr_all.h @@ -47,6 +47,7 @@ namespace zipr #include <range.h> #include <unresolved.h> +#include <memory_space.h> #include <zipr.h> #include <zipr_optimizations.h> #include <zipr_options.h> diff --git a/src/Makefile b/src/Makefile index e6283f1..69ca44f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,7 +3,7 @@ INC=-I../include -I../third_party/ELFIO/elfio-2.2 -I$(SECURITY_TRANSFORMS_HOME)/ -SRCS=zipr.cpp zipr_options.cpp zipr_stats.cpp main.cpp +SRCS=zipr.cpp zipr_options.cpp zipr_stats.cpp memory_space.cpp main.cpp OBJS=$(subst .cpp,.o, $(SRCS)) HDRS=../include/*.h EXE=zipr.exe diff --git a/src/memory_space.cpp b/src/memory_space.cpp new file mode 100644 index 0000000..562160f --- /dev/null +++ b/src/memory_space.cpp @@ -0,0 +1,196 @@ +#include <zipr_all.h> +#include <unistd.h> +#include <stdlib.h> +#include <getopt.h> + +using namespace zipr; +using namespace std; + +void MemorySpace_t::SplitFreeRange(RangeAddress_t addr) +{ + list<Range_t>::iterator it=FindFreeRange(addr); + assert(IsValidRange(it)); + + Range_t r=*it; + + if(r.GetStart()==r.GetEnd()) + { + assert(addr==r.GetEnd()); + free_ranges.erase(it); + } + else if(addr==r.GetStart()) + { + free_ranges.insert(it, Range_t(r.GetStart()+1, r.GetEnd())); + free_ranges.erase(it); + } + else if(addr==r.GetEnd()) + { + free_ranges.insert(it, Range_t(r.GetStart(), r.GetEnd()-1)); + free_ranges.erase(it); + } + else // split range + { + free_ranges.insert(it, Range_t(r.GetStart(), addr-1)); + free_ranges.insert(it, Range_t(addr+1, r.GetEnd())); + free_ranges.erase(it); + } +} + +void MemorySpace_t::MergeFreeRange(RangeAddress_t addr) +{ + /* + * Make a new range of one byte. + * + * Then, look to see whether or not it + * can be merged with another range. + * + * If not, add it as a one byte range. + */ + + Range_t nr(addr, addr); + bool merged = false; + list<Range_t>::iterator it=free_ranges.begin(); + for(;it!=free_ranges.end();++it) + { + Range_t r=*it; + if ((addr+1) == r.GetStart()) { + /* + * Make the beginning of this range + * one byte smaller! + */ + Range_t nnr(addr, r.GetEnd()); + if (true) //if(m_opts.GetVerbose()) + { + printf("Expanded range:\n"); + printf("from: %p to %p\n", (void*)r.GetStart(), (void*)r.GetEnd()); + printf("to: %p to %p\n", (void*)nnr.GetStart(), (void*)nnr.GetEnd()); + } + free_ranges.insert(it, nnr); + free_ranges.erase(it); + nr = nnr; + merged = true; + break; + } else if ((addr-1) == r.GetEnd()) { + /* + * Make the end of this range one byte + * bigger + */ + Range_t nnr(r.GetStart(), addr); + if (true) //if(m_opts.GetVerbose()) + { + printf("Expanded range:\n"); + printf("from: %p to %p\n", (void*)r.GetStart(), (void*)r.GetEnd()); + printf("to: %p to %p\n", (void*)nnr.GetStart(), (void*)nnr.GetEnd()); + } + free_ranges.insert(it, nnr); + free_ranges.erase(it); + nr = nnr; + merged = true; + break; + } + } + + if (!merged) + free_ranges.insert(it, nr); + + /* + * Correctness: + * Take a pass through and see if there are + * free ranges that can now be merged. This + * is important because it's possible that + * we added the byte to the end of a range + * where it could also have gone at the + * beginning of another. + */ + for(it=free_ranges.begin();it!=free_ranges.end();++it) + { + Range_t r = *it; + if (( + /* + * <--r--> + * <--nr--> + */ + (r.GetEnd() >= nr.GetStart() && + r.GetEnd() <= nr.GetEnd()) || + /* + * <--r--> + * <--nr--> + */ + (r.GetStart() <= nr.GetEnd() && + r.GetEnd() >= nr.GetEnd()) + ) && + (r.GetStart() != nr.GetStart() || + r.GetEnd() != nr.GetEnd())) + { + /* + * merge. + */ + Range_t merged_range(std::min(r.GetStart(), nr.GetStart()), std::max(r.GetEnd(), nr.GetEnd())); + if (true) //if(m_opts.GetVerbose()) + { + printf("Merged two ranges:\n"); + printf("1: %p to %p\n", (void*)r.GetStart(), (void*)r.GetEnd()); + printf("2: %p to %p\n", (void*)nr.GetStart(), (void*)nr.GetEnd()); + } + free_ranges.insert(it, merged_range); + free_ranges.erase(it); + return; + } + } +} + +std::list<Range_t>::iterator MemorySpace_t::FindFreeRange(RangeAddress_t addr) +{ + for( list<Range_t>::iterator it=free_ranges.begin(); + it!=free_ranges.end(); + ++it) + { + Range_t r=*it; + if(r.GetStart() <= addr && addr <=r.GetEnd()) + return it; + } + return free_ranges.end(); +} + +bool MemorySpace_t::IsValidRange(std::list<Range_t>::iterator it) +{ + return it!=free_ranges.end(); +} + +Range_t MemorySpace_t::GetFreeRange(int size) +{ + for( list<Range_t>::iterator it=free_ranges.begin(); + it!=free_ranges.end(); + ++it) + { + Range_t r=*it; + if(r.GetEnd() - r.GetStart() > size) + return r; + } + assert(0);// assume we find a big enough range. +} + +// queries about free areas. +bool MemorySpace_t::AreBytesFree(RangeAddress_t addr, int num_bytes) +{ + for(int i=0;i<num_bytes;i++) + if(!IsByteFree(addr+i)) + return false; + return true; +} + +bool MemorySpace_t::IsByteFree(RangeAddress_t addr) +{ + if (IsValidRange(FindFreeRange(addr))) + return true; + return false; +} + +void MemorySpace_t::AddFreeRange(Range_t newRange) +{ + free_ranges.push_back(Range_t(newRange.GetStart(), newRange.GetEnd())); +} +int MemorySpace_t::GetRangeCount() +{ + return free_ranges.size(); +} diff --git a/src/zipr.cpp b/src/zipr.cpp index 903867e..6acd690 100644 --- a/src/zipr.cpp +++ b/src/zipr.cpp @@ -107,7 +107,7 @@ void Zipr_t::CreateBinaryFile(const std::string &name) // go ahead and update any callback sites with the new locations UpdateCallbacks(); - m_stats->total_free_ranges = free_ranges.length(); + m_stats->total_free_ranges = memory_space.GetRangeCount(); // write binary file to disk OutputBinaryFile(name); @@ -198,7 +198,7 @@ void Zipr_t::FindFreeRanges(const std::string &name) last_end=end; if(m_opts.GetVerbose()) printf("Adding free range 0x%p to 0x%p\n", (void*)start,(void*)end); - free_ranges.push_back(Range_t(start,end)); + memory_space.AddFreeRange(Range_t(start,end)); } } @@ -208,7 +208,7 @@ void Zipr_t::FindFreeRanges(const std::string &name) // now that we've looked at the sections, add a (mysterious) extra section in case we need to overflow // the sections existing in the ELF. RangeAddress_t new_free_page=PAGE_ROUND_UP(max_addr); - free_ranges.push_back( Range_t(new_free_page,(RangeAddress_t)-1)); + memory_space.AddFreeRange(Range_t(new_free_page,(RangeAddress_t)-1)); if(m_opts.GetVerbose()) printf("Adding (mysterious) free range 0x%p to EOF\n", (void*)new_free_page); start_of_new_space=new_free_page; @@ -234,166 +234,6 @@ void Zipr_t::AddPinnedInstructions() } - -Range_t Zipr_t::GetFreeRange(int size) -{ - for( list<Range_t>::iterator it=free_ranges.begin(); - it!=free_ranges.end(); - ++it) - { - Range_t r=*it; - if(r.GetEnd() - r.GetStart() > size) - return r; - } - assert(0);// assume we find a big enough range. -} - -list<Range_t>::iterator Zipr_t::FindFreeRange(RangeAddress_t addr) -{ - for( list<Range_t>::iterator it=free_ranges.begin(); - it!=free_ranges.end(); - ++it) - { - Range_t r=*it; - if(r.GetStart() <= addr && addr <=r.GetEnd()) - return it; - } - return free_ranges.end(); -} - -void Zipr_t::MergeFreeRange(RangeAddress_t addr) -{ - /* - * Make a new range of one byte. - * - * Then, look to see whether or not it - * can be merged with another range. - * - * If not, add it as a one byte range. - */ - - Range_t nr(addr, addr); - bool merged = false; - list<Range_t>::iterator it=free_ranges.begin(); - for(;it!=free_ranges.end();++it) - { - Range_t r=*it; - if ((addr+1) == r.GetStart()) { - /* - * Make the beginning of this range - * one byte smaller! - */ - Range_t nnr(addr, r.GetEnd()); - if(m_opts.GetVerbose()) - { - printf("Expanded range:\n"); - printf("from: %p to %p\n", (void*)r.GetStart(), (void*)r.GetEnd()); - printf("to: %p to %p\n", (void*)nnr.GetStart(), (void*)nnr.GetEnd()); - } - free_ranges.insert(it, nnr); - free_ranges.erase(it); - nr = nnr; - merged = true; - break; - } else if ((addr-1) == r.GetEnd()) { - /* - * Make the end of this range one byte - * bigger - */ - Range_t nnr(r.GetStart(), addr); - if(m_opts.GetVerbose()) - { - printf("Expanded range:\n"); - printf("from: %p to %p\n", (void*)r.GetStart(), (void*)r.GetEnd()); - printf("to: %p to %p\n", (void*)nnr.GetStart(), (void*)nnr.GetEnd()); - } - free_ranges.insert(it, nnr); - free_ranges.erase(it); - nr = nnr; - merged = true; - break; - } - } - - if (!merged) - free_ranges.insert(it, nr); - - /* - * Correctness: - * Take a pass through and see if there are - * free ranges that can now be merged. This - * is important because it's possible that - * we added the byte to the end of a range - * where it could also have gone at the - * beginning of another. - */ - for(it=free_ranges.begin();it!=free_ranges.end();++it) - { - Range_t r = *it; - if (( - /* - * <--r--> - * <--nr--> - */ - (r.GetEnd() >= nr.GetStart() && - r.GetEnd() <= nr.GetEnd()) || - /* - * <--r--> - * <--nr--> - */ - (r.GetStart() <= nr.GetEnd() && - r.GetEnd() >= nr.GetEnd()) - ) && - (r.GetStart() != nr.GetStart() || - r.GetEnd() != nr.GetEnd())) - { - /* - * merge. - */ - Range_t merged_range(std::min(r.GetStart(), nr.GetStart()), std::max(r.GetEnd(), nr.GetEnd())); - if(m_opts.GetVerbose()) - { - printf("Merged two ranges:\n"); - printf("1: %p to %p\n", (void*)r.GetStart(), (void*)r.GetEnd()); - printf("2: %p to %p\n", (void*)nr.GetStart(), (void*)nr.GetEnd()); - } - free_ranges.insert(it, merged_range); - free_ranges.erase(it); - return; - } - } -} - -void Zipr_t::SplitFreeRange(RangeAddress_t addr) -{ - list<Range_t>::iterator it=FindFreeRange(addr); - assert(it!=free_ranges.end()); - - Range_t r=*it; - - if(r.GetStart()==r.GetEnd()) - { - assert(addr==r.GetEnd()); - free_ranges.erase(it); - } - else if(addr==r.GetStart()) - { - free_ranges.insert(it, Range_t(r.GetStart()+1, r.GetEnd())); - free_ranges.erase(it); - } - else if(addr==r.GetEnd()) - { - free_ranges.insert(it, Range_t(r.GetStart(), r.GetEnd()-1)); - free_ranges.erase(it); - } - else // split range - { - free_ranges.insert(it, Range_t(r.GetStart(), addr-1)); - free_ranges.insert(it, Range_t(addr+1, r.GetEnd())); - free_ranges.erase(it); - } -} - Instruction_t *Zipr_t::FindPinnedInsnAtAddr(RangeAddress_t addr) { for( @@ -520,7 +360,7 @@ void Zipr_t::OptimizePinnedFallthroughs() */ for (int j = up.GetRange().GetStart(); j<up.GetRange().GetEnd(); j++) { - MergeFreeRange(j); + memory_space.MergeFreeRange(j); } up.SetRange(Range_t(0,0)); @@ -570,7 +410,7 @@ void Zipr_t::PreReserve2ByteJumpTargets() printf("Looking for %d-byte jump targets to pre-reserve.\n", size); for(int i=120;i>=-120;i--) { - if(AreBytesFree(addr+i,size)) + if(memory_space.AreBytesFree(addr+i,size)) { if(m_opts.GetVerbose()) printf("Found location for 2-byte->%d-byte conversion " @@ -585,7 +425,7 @@ void Zipr_t::PreReserve2ByteJumpTargets() up.SetRange(Range_t(addr+i, addr+i+size)); for (int j = up.GetRange().GetStart(); j<up.GetRange().GetEnd(); j++) { - SplitFreeRange(j); + memory_space.SplitFreeRange(j); } found_close_target = true; break; @@ -650,7 +490,7 @@ void Zipr_t::ReservePinnedInstructions() for(int i=0;i<upinsn->GetDataBits().size();i++) { byte_map[addr+i]=upinsn->GetDataBits()[i]; - SplitFreeRange(addr+i); + memory_space.SplitFreeRange(addr+i); m_stats->total_other_space++; } continue; @@ -672,7 +512,7 @@ void Zipr_t::ReservePinnedInstructions() { assert(byte_map.find(addr+i) == byte_map.end() ); byte_map[addr+i]=bytes[i]; - SplitFreeRange(addr+i); + memory_space.SplitFreeRange(addr+i); } } } @@ -691,7 +531,7 @@ void Zipr_t::ExpandPinnedInstructions() RangeAddress_t addr=upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset(); char bytes[]={0xe9,0,0,0,0}; // jmp rel8 - bool can_update=AreBytesFree(addr+2,sizeof(bytes)-2); + bool can_update=memory_space.AreBytesFree(addr+2,sizeof(bytes)-2); if(can_update) { if(m_opts.GetVerbose()) @@ -703,7 +543,7 @@ void Zipr_t::ExpandPinnedInstructions() */ for (int j = up.GetRange().GetStart(); j<up.GetRange().GetEnd(); j++) { - MergeFreeRange(j); + memory_space.MergeFreeRange(j); } up.SetRange(Range_t(0,0)); @@ -754,7 +594,7 @@ void Zipr_t::Fix2BytePinnedInstructions() */ for (int j = up.GetRange().GetStart(); j<up.GetRange().GetEnd(); j++) { - MergeFreeRange(j); + memory_space.MergeFreeRange(j); } if (up.GetRange().Is5ByteRange()) @@ -795,8 +635,8 @@ void Zipr_t::Fix2BytePinnedInstructions() { assert(byte_map.find(up.GetRange().GetStart()+i) == byte_map.end() ); byte_map[up.GetRange().GetStart()+i]=bytes[i]; - SplitFreeRange(up.GetRange().GetStart()+i); - assert(!IsByteFree(up.GetRange().GetStart()+i)); + memory_space.SplitFreeRange(up.GetRange().GetStart()+i); + assert(!memory_space.IsByteFree(up.GetRange().GetStart()+i)); } if(m_opts.GetVerbose()) @@ -819,23 +659,6 @@ void Zipr_t::Fix2BytePinnedInstructions() } } - -bool Zipr_t::AreBytesFree(RangeAddress_t addr, int num_bytes) -{ - for(int i=0;i<num_bytes;i++) - if(!IsByteFree(addr+i)) - return false; - return true; -} - -bool Zipr_t::IsByteFree(RangeAddress_t addr) -{ - if(FindFreeRange(addr)!=free_ranges.end()) - return true; - return false; -} - - void Zipr_t::OptimizePinnedInstructions() { @@ -895,7 +718,7 @@ void Zipr_t::PlopBytes(RangeAddress_t addr, const char the_byte[], int num) void Zipr_t::PlopByte(RangeAddress_t addr, char the_byte) { if(byte_map.find(addr) == byte_map.end() ) - SplitFreeRange(addr); + memory_space.SplitFreeRange(addr); byte_map[addr]=the_byte; } @@ -944,7 +767,7 @@ void Zipr_t::PatchJump(RangeAddress_t at_addr, RangeAddress_t to_addr) { uintptr_t off=to_addr-at_addr-2; - assert(!IsByteFree(at_addr)); + assert(!memory_space.IsByteFree(at_addr)); switch(byte_map[at_addr]) { @@ -956,7 +779,7 @@ void Zipr_t::PatchJump(RangeAddress_t at_addr, RangeAddress_t to_addr) { assert(off==(uintptr_t)(char)off); - assert(!IsByteFree(at_addr+1)); + assert(!memory_space.IsByteFree(at_addr+1)); byte_map[at_addr+1]=(char)off; } } @@ -1028,7 +851,7 @@ static int DetermineWorseCaseInsnSize(Instruction_t* insn) void Zipr_t::ProcessUnpinnedInstruction(const UnresolvedUnpinned_t &uu, const Patch_t &p) { int req_size=DetermineWorseCaseInsnSize(uu.GetInstruction()); - Range_t r=GetFreeRange(req_size); + Range_t r=memory_space.GetFreeRange(req_size); int insn_count=0; const char* truncated="not truncated."; @@ -1390,7 +1213,7 @@ void Zipr_t::FillSection(section* sec, FILE* fexe) printf("Dumping addrs %p-%p\n", (void*)start, (void*)end); for(RangeAddress_t i=start;i<end;i++) { - if(!IsByteFree(i)) + if(!memory_space.IsByteFree(i)) { // get byte and write it into exe. char b=byte_map[i]; @@ -1441,8 +1264,8 @@ void Zipr_t::OutputBinaryFile(const string &name) perror( "void Zipr_t::OutputBinaryFile(const string &name)"); // first byte of this range is the last used byte. - list<Range_t>::iterator it=FindFreeRange((RangeAddress_t) -1); - assert(it!=free_ranges.end()); + list<Range_t>::iterator it=memory_space.FindFreeRange((RangeAddress_t) -1); + assert(memory_space.IsValidRange(it)); RangeAddress_t end_of_new_space=it->GetStart(); @@ -1450,7 +1273,7 @@ void Zipr_t::OutputBinaryFile(const string &name) for(RangeAddress_t i=start_of_new_space;i<end_of_new_space;i++) { char b=0; - if(!IsByteFree(i)) + if(!memory_space.IsByteFree(i)) { b=byte_map[i]; } -- GitLab