diff --git a/.gitattributes b/.gitattributes
index 9fd8d073f9761a47b68d2fb3a6de9dda562d409c..b35d339297f35a74e320439c744697b61cdb6393 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,10 +4,13 @@ include/range.h -text
 include/unresolved.h -text
 include/zipr.h -text
 include/zipr_all.h -text
+include/zipr_optimizations.h -text
 include/zipr_options.h -text
+include/zipr_stats.h -text
 src/Makefile -text
 src/main.cpp -text
 src/zipr.cpp -text
+src/zipr_options.cpp -text
 third_party/ELFIO/elfio-2.2/AUTHORS -text
 third_party/ELFIO/elfio-2.2/COPYING -text
 third_party/ELFIO/elfio-2.2/ChangeLog -text
diff --git a/include/range.h b/include/range.h
index 4bb6fb3ad2abd13965c6a72dfc739bd6ff5740e5..e0ec3b7ad5368b1dcbcd45a9a53cf8d63a84412f 100644
--- a/include/range.h
+++ b/include/range.h
@@ -38,10 +38,20 @@ class Range_t
 {
 	public:
 		Range_t(RangeAddress_t p_s, RangeAddress_t p_e) : m_start(p_s), m_end(p_e) { }
+		Range_t() : m_start(0), m_end(0) { }
 
 		RangeAddress_t GetStart() { return m_start; }
 		RangeAddress_t GetEnd() { return m_end; }
 
+		bool Is2ByteRange()
+		{
+			return (m_end - m_start) == 2;
+		};
+		bool Is5ByteRange()
+		{
+			return (m_end - m_start) == 5;
+		};
+
 	protected:
 
 		RangeAddress_t m_start, m_end;
diff --git a/include/unresolved.h b/include/unresolved.h
index fa58014d350d1503a266c289c56eb226c84da912..49c5d620cf4508ca093cee7f015d38a8e66a09b3 100644
--- a/include/unresolved.h
+++ b/include/unresolved.h
@@ -71,10 +71,45 @@ inline bool operator< (const UnresolvedUnpinned_t& lhs, const UnresolvedUnpinned
 class UnresolvedPinned_t : public UnresolvedInfo_t
 {
 	public:
-		UnresolvedPinned_t(libIRDB::Instruction_t* p_from) : from_instruction(p_from) {}
+		UnresolvedPinned_t(libIRDB::Instruction_t* p_from) : from_instruction(p_from), m_range(0,0), m_updated_address(0) {}
+		UnresolvedPinned_t(libIRDB::Instruction_t* p_from, Range_t range) : from_instruction(p_from), m_range(range) {}
 		libIRDB::Instruction_t* GetInstruction() const { return from_instruction; }
+
+		/*
+		 * Use the range to store the place where 
+		 * reserved space is held for this
+		 * instruction.
+		 */
+		Range_t GetRange() const { return m_range; };
+		void SetRange(Range_t range) { m_range = range; };
+		bool HasRange()
+		{
+			return m_range.GetStart() != 0 || m_range.GetEnd() != 0;
+		};
+
+		/*
+		 * Store an address with the UnresolvedPinned
+		 * in case this instruction needs to float
+		 * through the program based on a chain
+		 * of two-byte calls.
+		 */
+		bool HasUpdatedAddress()
+		{
+			return m_updated_address != 0;
+		};
+		void SetUpdatedAddress(RangeAddress_t address)
+		{
+			m_updated_address = address;
+		};
+		RangeAddress_t GetUpdatedAddress()
+		{
+			return m_updated_address;
+		};
+
 	private:
 		libIRDB::Instruction_t* from_instruction;
+		Range_t m_range;
+		RangeAddress_t m_updated_address;
 
 	friend bool operator< (const UnresolvedPinned_t& lhs, const UnresolvedPinned_t& rhs);
 		
diff --git a/include/zipr.h b/include/zipr.h
index 8db9c3a73ccb15fe34d3a381cd126ce9bc8b0d27..fed065746962257bb3bf6b6e4696eb977fbe1811 100644
--- a/include/zipr.h
+++ b/include/zipr.h
@@ -31,12 +31,14 @@
 #ifndef zipr_h
 #define zipr_h
 
+class Options_t;
+class Stats_t;
 
 class Zipr_t
 {
 	public:
-		Zipr_t(libIRDB::FileIR_t* p_firp, const Options_t &p_opts)
-			: m_firp(p_firp), m_opts(p_opts) 
+		Zipr_t(libIRDB::FileIR_t* p_firp, Options_t &p_opts)
+			: m_firp(p_firp), m_opts(p_opts)
 		{ 
                 	total_dollops=0;
                 	total_dollop_space=0;
@@ -55,13 +57,15 @@ class Zipr_t
 
 		// data for the stuff we're rewriting.
 		libIRDB::FileIR_t* m_firp;
-		const Options_t& m_opts;
+		Options_t& m_opts;
+		Stats_t *m_stats;
 
 		// phases of rewriting.
 		void FindFreeRanges(const std::string &name);
 		void AddPinnedInstructions();
 		void ResolvePinnedInstructions();
 		void ReservePinnedInstructions();
+		void PreReserve2ByteJumpTargets();
 		void ExpandPinnedInstructions();
 		void Fix2BytePinnedInstructions();
 		void OptimizePinnedInstructions();
@@ -71,6 +75,7 @@ class Zipr_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);
 
@@ -104,6 +109,8 @@ class Zipr_t
 		// helpers.
 		void ProcessUnpinnedInstruction(const UnresolvedUnpinned_t &uu, const Patch_t &p);
 		void InsertNewSegmentIntoExe(std::string old_file, std::string new_file, RangeAddress_t sec_start);
+		libIRDB::Instruction_t *FindPinnedInsnAtAddr(RangeAddress_t addr);
+		bool ShouldPinImmediately(libIRDB::Instruction_t *upinsn);
 
 
 	private:
diff --git a/include/zipr_all.h b/include/zipr_all.h
index 753d8ae8f79d608683d67f21c9f2912e2fafb181..3ec33419f3fadb33b158de441bc944cb076f701d 100644
--- a/include/zipr_all.h
+++ b/include/zipr_all.h
@@ -45,10 +45,12 @@
 namespace zipr
 {
 
-#include <zipr_options.h>
 #include <range.h>
 #include <unresolved.h>
 #include <zipr.h>
+#include <zipr_optimizations.h>
+#include <zipr_options.h>
+#include <zipr_stats.h>
 
 };
 
diff --git a/include/zipr_optimizations.h b/include/zipr_optimizations.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d4601c3552edd1e154022451b0376fe33314004
--- /dev/null
+++ b/include/zipr_optimizations.h
@@ -0,0 +1,8 @@
+#ifndef zipr_optimizations_t
+#define zipr_optimizations_t
+
+class Optimizations_t {
+	public:
+		enum OptimizationName_t { OptimizationPlopNotJump = 0 , NumberOfOptimizations};
+};
+#endif
diff --git a/include/zipr_options.h b/include/zipr_options.h
index 6cb2fe019fc2635e33ace6fce80cc49c1273a9eb..f84b6180a725b7ade29e1a657b40e10b0d4b0727 100644
--- a/include/zipr_options.h
+++ b/include/zipr_options.h
@@ -31,28 +31,36 @@
 #ifndef zipr_options_h
 #define zipr_options_h
 
+#include <zipr_all.h>
 #include <string>
-// #include <libIRDB-core.hpp>
+#include <unistd.h>
+#include <libIRDB-core.hpp>
 
 class Options_t 
 {
 	public:
-		Options_t() : m_outname("b.out") { };
+		Options_t() : m_outname("b.out") { }
+
+		static Options_t* parse_args(int p_argc, char* p_argv[]);
+		static void print_usage(int p_argc, char *p_argv[]);
 
-		static Options_t* parse_args(int p_argc, char* p_argv[]) 
-		{ 
-			Options_t *opt=new Options_t;
-			assert(opt);
-			opt->m_var_id=::atoi(p_argv[1]); 
-			return opt;
-		};
-		
 		std::string GetOutputFileName(libIRDB::File_t* p_file) { return m_outname; }
 		int GetVariantID() { return m_var_id; }
+		
+		void EnableOptimization(Optimizations_t::OptimizationName_t opt) 
+		{ 
+			EnabledOptimizations[opt] = 1; 
+		};
+
+		bool IsEnabledOptimization(Optimizations_t::OptimizationName_t opt) 
+		{ 
+			return EnabledOptimizations[opt] == 1; 
+		};
 
 	private:
 		std::string m_outname;
 		int m_var_id;
+		int EnabledOptimizations[Optimizations_t::NumberOfOptimizations];
 };
 
 #endif
diff --git a/include/zipr_stats.h b/include/zipr_stats.h
new file mode 100644
index 0000000000000000000000000000000000000000..938863de77042b26edea909c4c05e1efdf7e44b6
--- /dev/null
+++ b/include/zipr_stats.h
@@ -0,0 +1,18 @@
+#ifndef zipr_stats_t
+#define zipr_stats_t
+
+class Stats_t
+{
+	public:
+		Stats_t() {
+			for (int i=0; i<Optimizations_t::NumberOfOptimizations; i++)
+			{
+				Hits[i] = Misses[i] = 0;
+			}
+		};
+		int Hits[Optimizations_t::NumberOfOptimizations];
+		int Misses[Optimizations_t::NumberOfOptimizations];
+		void Hit(Optimizations_t::OptimizationName_t opt) { Hits[opt]++; };
+		void Missed(Optimizations_t::OptimizationName_t opt) { Misses[opt]++; };
+};
+#endif
diff --git a/src/Makefile b/src/Makefile
index 484a9f909eb3b5ed42047055467c618ef80a2707..8d82759084433c605858397ad9f8fdcaef742005 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=main.cpp zipr.cpp
+SRCS=zipr.cpp zipr_options.cpp main.cpp
 OBJS=$(subst .cpp,.o, $(SRCS))
 HDRS=../include/*.h 
 EXE=zipr.exe
diff --git a/src/main.cpp b/src/main.cpp
index 54779a54c894717445ced7900adc38a63314bc6e..d114e813c7a7c2c00d3c2e8e57b705afc1008337 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -53,6 +53,12 @@ int main(int argc, char* argv[])
         VariantID_t *pidp=NULL;
         FileIR_t * firp=NULL;
 
+	if ((!options->GetVariantID()))
+	{
+		Options_t::print_usage(argc, argv);
+		return 1;
+	}
+
         try
         {
                 /* setup the interface to the sql server */
diff --git a/src/zipr.cpp b/src/zipr.cpp
index 8bee382358fcc3194f20a31cdf0bfe5271142340..363a29b89efd4067884b16017e7549061573aaee 100644
--- a/src/zipr.cpp
+++ b/src/zipr.cpp
@@ -54,6 +54,7 @@ using namespace ELFIO;
 
 void Zipr_t::CreateBinaryFile(const std::string &name)
 {
+	m_stats = new Stats_t();
 
 	// create ranges, including extra range that's def. big enough.
 	FindFreeRanges(name);
@@ -64,11 +65,30 @@ void Zipr_t::CreateBinaryFile(const std::string &name)
 	// reserve space for pins
 	ReservePinnedInstructions();
 
+	PreReserve2ByteJumpTargets();
+
 	// expand 2-byte pins into 4-byte pins
 	ExpandPinnedInstructions();
 
-	// Allocate space near 2-byte pins for a 5-byte pin
-	Fix2BytePinnedInstructions();
+	while (!two_byte_pins.empty()) 
+	{
+		/*
+		 * Put down the five byte targets
+		 * for two byte jumps, if any exist.
+		 */
+		printf("Going to Fix2BytePinnedInstructions.\n");
+		Fix2BytePinnedInstructions();
+
+		/*
+		 * If there are still two byte pins, 
+		 * try the dance again.
+		 */
+		if (!two_byte_pins.empty())
+		{
+			printf("Going to Re PreReserve2ByteJumpTargets.\n");
+			PreReserve2ByteJumpTargets();
+		}
+	}
 
 	// Convert all 5-byte pins into full fragments
 	OptimizePinnedInstructions();
@@ -96,16 +116,55 @@ void Zipr_t::FindFreeRanges(const std::string &name)
 	RangeAddress_t last_end=0;
 	RangeAddress_t max_addr=0;
 
-	// For all sections
+	std::map<RangeAddress_t, int> ordered_sections;
+
+	/*
+	 * Make an ordered list of the sections
+	 * by their starting address.
+	 */
 	Elf_Half n = elfiop->sections.size();
 	for ( Elf_Half i = 0; i < n; ++i ) 
 	{ 
 		section* sec = elfiop->sections[i];
 		assert(sec);
+		ordered_sections.insert(std::pair<RangeAddress_t,int>(sec->get_address(), i));
+	}
+
+	std::map<RangeAddress_t, int>::iterator it = ordered_sections.begin();
+	for (;it!=ordered_sections.end();) 
+	{ 
+		section* sec = elfiop->sections[it->second];
+		assert(sec);
 
 		RangeAddress_t start=sec->get_address();
 		RangeAddress_t end=sec->get_size()+start-1;
 
+		printf("Section %s:\n", sec->get_name().c_str());
+
+		++it;
+		if (false)
+		//if ((++it) != ordered_sections.end())
+		{
+			/*
+			 * TODO: This works. However, the updated
+			 * section size is not properly handled
+			 * in OutputBinaryFile. So, it is disabled
+			 * until that is handled.
+			 */
+			section *next_section = elfiop->sections[it->second];
+
+			printf("Using %s as the next section (%p).\n", 
+				next_section->get_name().c_str(), 
+				(void*)next_section->get_address());
+			printf("Modifying the section end. Was %p.", (void*)end);
+
+			end = next_section->get_address() - 1;
+			sec->set_size(end - start);
+			
+			printf(". Is %p.\n", (void*)end);
+
+		}
+
 		printf("max_addr is %p, end is %p\n", (void*)max_addr, (void*)end);
 		if(start && end>max_addr)
 		{
@@ -185,6 +244,100 @@ list<Range_t>::iterator Zipr_t::FindFreeRange(RangeAddress_t addr)
 	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());
+			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);
+			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()));
+			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);
@@ -215,11 +368,36 @@ void Zipr_t::SplitFreeRange(RangeAddress_t addr)
 	}
 }
 
+Instruction_t *Zipr_t::FindPinnedInsnAtAddr(RangeAddress_t addr)
+{
+	for(
+		set<Instruction_t*>::const_iterator it=m_firp->GetInstructions().begin();
+		it!=m_firp->GetInstructions().end();
+		++it
+	)
+	{
+		RangeAddress_t ibta_addr;
+		Instruction_t* insn=*it;
+		assert(insn);
 
-static bool should_pin_immediately(Instruction_t *upinsn)
+		if(!insn->GetIndirectBranchTargetAddress()) {
+			continue;
+		}
+		ibta_addr=(unsigned)insn->
+			GetIndirectBranchTargetAddress()->
+			GetVirtualOffset();
+
+		if (addr == ibta_addr)
+			return insn;
+	}
+	return NULL;
+}
+
+bool Zipr_t::ShouldPinImmediately(Instruction_t *upinsn)
 {
 	DISASM d;
 	upinsn->Disassemble(d);
+	Instruction_t *pin_at_next_byte = NULL;
 
 	if(d.Instruction.BranchType==RetType)
 		return true;
@@ -237,9 +415,124 @@ static bool should_pin_immediately(Instruction_t *upinsn)
 			return true;
 	}
 
+	/*
+	 * lock cmpxchange op1 op2 [pinned at x]
+	 * x    x+1        x+2 x+3
+	 * 
+	 * pin at x and pin at x+1
+	 *
+	 * x should become nop, put down immediately
+	 * x+1 should become the entire lock command.
+	 */
+	if ((pin_at_next_byte = 
+		FindPinnedInsnAtAddr(upinsn_ibta->GetVirtualOffset() + 1)) != NULL)
+	{
+		printf("Using pin_at_next_byte special case.\n");
+		/*
+		 * Because upinsn is longer than 
+		 * 1 byte, we must be somehow
+		 * pinned into ourselves. Fix!
+		 */
+
+		/*
+		 * Make pin_at_next_byte look like upinsn.
+		 */
+		pin_at_next_byte->SetDataBits(upinsn->GetDataBits());
+		pin_at_next_byte->SetComment(upinsn->GetComment());
+		pin_at_next_byte->SetCallback(upinsn->GetCallback());
+		pin_at_next_byte->SetFallthrough(upinsn->GetFallthrough());
+		pin_at_next_byte->SetTarget(upinsn->GetTarget());
+		/*
+		 * Convert upins to nop.
+		 */
+		string dataBits = upinsn->GetDataBits();
+		dataBits.resize(1);
+		dataBits[0] = 0x90;
+		upinsn->SetDataBits(dataBits);
+
+		return true;
+	}
 	return false;
 }
 
+void Zipr_t::PreReserve2ByteJumpTargets()
+{
+	for(set<UnresolvedPinned_t>::const_iterator it=two_byte_pins.begin();
+		it!=two_byte_pins.end();
+		)
+	{
+		UnresolvedPinned_t up=*it;
+		bool found_close_target = false;
+		Instruction_t* upinsn=up.GetInstruction();
+
+		RangeAddress_t addr;
+		
+		if (up.HasUpdatedAddress())
+		{
+			addr = up.GetUpdatedAddress();
+		}
+		else
+		{
+			addr=upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset();
+		}
+
+		/*
+		 * Check for near branch instructions
+		 * by starting far away!
+		 * Note: two byte jump range is 127 bytes, 
+		 * but that's from the pc after it's been 
+		 * inc, etc. complicated goo. 120 is a 
+		 * safe estimate of range.
+		 */
+		for(int size=5;size>0;size-=3) 
+		{
+			printf("Looking for %d-byte jump targets to pre-reserve.\n", size);
+			for(int i=120;i>=-120;i--)
+			{
+				if(AreBytesFree(addr+i,size))
+				{
+					printf("Found location for 2-byte->%d-byte conversion "
+						"(%p-%p)->(%p-%p) (orig: %p)\n", 
+						size,
+						(void*)addr,
+						(void*)(addr+1),
+						(void*)(addr+i),
+						(void*)(addr+i+size),
+						(void*)upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset());
+
+					up.SetRange(Range_t(addr+i, addr+i+size));
+					for (int j = up.GetRange().GetStart(); j<up.GetRange().GetEnd(); j++)
+					{
+						SplitFreeRange(j);
+					}
+					found_close_target = true;
+					break;
+				}
+			}
+			if (found_close_target)
+				break;
+		}
+
+		if (!found_close_target)
+		{
+			printf("FATAL: No location for near jump reserved.\n");
+			assert(false);
+			++it;
+		}
+		else
+		{
+			UnresolvedPinned_t new_up = UnresolvedPinned_t(up.GetInstruction(), up.GetRange());
+			if (up.HasUpdatedAddress())
+			{
+				new_up.SetUpdatedAddress(up.GetUpdatedAddress());
+			}
+			two_byte_pins.erase(it++);
+			two_byte_pins.insert(new_up);
+				
+		}
+	}
+}
+
 void Zipr_t::ReservePinnedInstructions()
 {
 	set<UnresolvedPinned_t> reserved_pins;
@@ -267,7 +560,7 @@ void Zipr_t::ReservePinnedInstructions()
 		 * so, we attempt to pin any 1-byte instructions with no fallthrough (returns are most common) immediately.
 		 * we also attempt to pin any 1-byte insn that falls through to the next pinned address (nops are common).
 		 */
-		if(should_pin_immediately(upinsn))
+		if(ShouldPinImmediately(upinsn))
 		{
 			printf("Final pinning %p-%p.  fid=%d\n", (void*)addr, (void*)(addr+upinsn->GetDataBits().size()-1),
 				upinsn->GetAddress()->GetFileID());
@@ -281,9 +574,13 @@ void Zipr_t::ReservePinnedInstructions()
 		}
 
 		char bytes[]={0xeb,0}; // jmp rel8
-		printf("Two-byte Pinning %p-%p.  fid=%d\n", (void*)addr, (void*)(addr+sizeof(bytes)-1),
-				upinsn->GetAddress()->GetFileID());
-	
+
+		printf("Two-byte Pinning %p-%p.  fid=%d\n", 
+			(void*)addr, 
+			(void*)(addr+sizeof(bytes)-1),
+			upinsn->GetAddress()->GetFileID());
+		printf("%s\n", upinsn->GetComment().c_str());
+
 		two_byte_pins.insert(up);
 		for(int i=0;i<sizeof(bytes);i++)
 		{
@@ -292,30 +589,37 @@ void Zipr_t::ReservePinnedInstructions()
 			SplitFreeRange(addr+i);
 		}
 	}
-
 }
 
-
 void Zipr_t::ExpandPinnedInstructions()
 {
 	/* now, all insns have 2-byte pins.  See which ones we can make 5-byte pins */
 	
-        for(   
-		set<UnresolvedPinned_t>::const_iterator it=two_byte_pins.begin();
-                it!=two_byte_pins.end();
-           )
+	for(
+		set<UnresolvedPinned_t>::iterator it=two_byte_pins.begin();
+		it!=two_byte_pins.end();
+		)
 	{
 		UnresolvedPinned_t up=*it;
 		Instruction_t* upinsn=up.GetInstruction();
 		RangeAddress_t addr=upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset();
 
-
 		char bytes[]={0xe9,0,0,0,0}; // jmp rel8
 		bool can_update=AreBytesFree(addr+2,sizeof(bytes)-2);
 		if(can_update)
 		{
 			printf("Found %p can be updated to 5-byte jmp\n", (void*)addr);
 			PlopJump(addr);
+
+			/*
+			 * Unreserve those bytes that we reserved before!
+			 */
+			for (int j = up.GetRange().GetStart(); j<up.GetRange().GetEnd(); j++)
+			{
+				MergeFreeRange(j);
+			}
+			up.SetRange(Range_t(0,0));
+
 			five_byte_pins[up]=addr;
 			two_byte_pins.erase(it++);
 			total_5byte_pins++;
@@ -323,7 +627,7 @@ void Zipr_t::ExpandPinnedInstructions()
 		}
 		else
 		{
-                	++it;
+			++it;
 			printf("Found %p can NOT be updated to 5-byte jmp\n", (void*)addr);
 			total_2byte_pins++;
 			total_trampolines++;
@@ -337,46 +641,92 @@ void Zipr_t::ExpandPinnedInstructions()
 
 void Zipr_t::Fix2BytePinnedInstructions()
 {
-        for(   
+	for(
 		set<UnresolvedPinned_t>::const_iterator it=two_byte_pins.begin();
-                it!=two_byte_pins.end();
-           )
+		it!=two_byte_pins.end();
+		)
 	{
 		UnresolvedPinned_t up=*it;
 		Instruction_t* upinsn=up.GetInstruction();
-		RangeAddress_t addr=upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset();
+		RangeAddress_t addr;
+		
+		if (up.HasUpdatedAddress())
+		{
+			addr = up.GetUpdatedAddress();
+		}
+		else
+		{
+			addr=upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset();
+		}
 
-		// check for near branch instructions
-		for(int i=0;i<120;i++)	// two byte jump range is 127 bytes, but that's from the pc after it's been inc, etc. complicated goo.  120 is a safe estimate of range.
+		if (up.HasRange())
 		{
-			if(AreBytesFree(addr-i,5))
+			/*
+			 * Always clear out the previously reserved space.
+			 */
+			for (int j = up.GetRange().GetStart(); j<up.GetRange().GetEnd(); j++)
 			{
-				printf("Found location for 2-byte->5-byte conversion (%p-%p)->(%p-%p)\n", 
-					(void*)addr,(void*)(addr+1), (void*)(addr-i),(void*)(addr-i+4)); 
-
-				five_byte_pins[up]=addr-i;
-				PlopJump(addr-i);
-				PatchJump(addr, addr-i);
-				break;
+				MergeFreeRange(j);
 			}
-			else if(AreBytesFree(addr+i,5))
-			{
-				printf("Found location for 2-byte->5-byte conversion (%p-%p)->(%p-%p)\n", 
-					(void*)addr,(void*)(addr+1), (void*)(addr+i),(void*)(addr+i+5)); 
 
-				five_byte_pins[up]=addr+i;
-				PlopJump(addr+i);
-				PatchJump(addr, addr+i);
-				break;
+			if (up.GetRange().Is5ByteRange()) 
+			{
+				printf("Using previously reserved spot of 2-byte->5-byte conversion "
+					"(%p-%p)->(%p-%p) (orig: %p)\n", 
+					(void*)addr,
+					(void*)(addr+1),
+					(void*)(up.GetRange().GetStart()),
+					(void*)(up.GetRange().GetEnd()),
+					(void*)upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset());
+
+				five_byte_pins[up] = up.GetRange().GetStart();
+				PlopJump(up.GetRange().GetStart());
+				PatchJump(addr, up.GetRange().GetStart());
+
+				two_byte_pins.erase(it++);
 			}
-			else
+			else if (up.HasRange() && up.GetRange().Is2ByteRange()) 
 			{
-//				printf("Not free at %p or %p\n", (void*)(addr-i),(void*)(addr+i));
+				/*
+				 * Add jump to the reserved space.
+				 * Make an updated up that has a new
+				 * "addr" so that addr is handled 
+				 * correctly the next time through.
+				 *
+				 * Ie tell two_byte_pins list that
+				 * the instruction is now at the jump
+				 * target location.
+				 */
+				UnresolvedPinned_t new_up = 
+					UnresolvedPinned_t(up.GetInstruction());
+				new_up.SetUpdatedAddress(up.GetRange().GetStart());
+
+				char bytes[]={0xeb,0}; // jmp rel8
+				for(int i=0;i<sizeof(bytes);i++)
+				{
+					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));
+				}
+
+				printf("Patching 2 byte to 2 byte: %p to %p (orig: %p)\n", 
+					(void*)addr,
+					(void*)up.GetRange().GetStart(),
+					(void*)upinsn->GetIndirectBranchTargetAddress()->GetVirtualOffset());
+
+				PatchJump(addr, up.GetRange().GetStart());
+				two_byte_pins.erase(it++);
+				two_byte_pins.insert(new_up);
 			}
 		}
-		two_byte_pins.erase(it++);
+		else
+		{
+			printf("FATAL: Two byte pin without reserved range: %p\n", (void*)addr);
+			assert(false);
+			it++;
+		}
 	}
-
 }
 
 
@@ -578,19 +928,41 @@ void Zipr_t::ProcessUnpinnedInstruction(const UnresolvedUnpinned_t &uu, const Pa
 		DISASM d;
 		cur_insn->Disassemble(d);
 		int id=cur_insn->GetBaseID();
-		printf("Emitting %d:%s at %p until ", id, d.CompleteInstr, (void*)cur_addr);
-		cur_addr=PlopInstruction(cur_insn,cur_addr);
-		printf("%p\n", (void*)cur_addr);
-		cur_insn=cur_insn->GetFallthrough();
-		insn_count++;
+		RangeAddress_t to_addr;
+		/*
+		 * Check to see if id is already plopped somewhere.
+		 * If so, emit a jump to it and break.
+		 * TODO: Test and enable.
+		 */
+		if (false)
+		//if ((to_addr=final_insn_locations[to_insn]) != 0)
+		{
+			printf("Fallthrough loop detected. "
+				"Emitting jump from %p to %p.\n",
+				(void*)cur_addr,
+				(void*)to_addr);
+			PlopJump(cur_addr);
+			PatchJump(cur_addr, to_addr);
+			cur_insn = NULL;
+			cur_addr+=5;
+			break;
+		}
+		else
+		{
+			printf("Emitting %d:%s at %p until ", id, d.CompleteInstr, (void*)cur_addr);
+			cur_addr=PlopInstruction(cur_insn,cur_addr);
+			printf("%p\n", (void*)cur_addr);
+			cur_insn=cur_insn->GetFallthrough();
+			insn_count++;
+		}
 	}
 	if(cur_insn)
 	{
 		// Mark this insn as needing a patch since we couldn't completely empty 
 		// the 'fragment' we are translating into the elf section.
-                UnresolvedUnpinned_t uu(cur_insn);
-                Patch_t thepatch(cur_addr,UncondJump_rel32);
-                patch_list.insert(pair<UnresolvedUnpinned_t,Patch_t>(uu,thepatch));
+		UnresolvedUnpinned_t uu(cur_insn);
+		Patch_t thepatch(cur_addr,UncondJump_rel32);
+		patch_list.insert(pair<UnresolvedUnpinned_t,Patch_t>(uu,thepatch));
 		PlopJump(cur_addr);
 		truncated="truncated due to lack of space.";
 		total_tramp_space+=5;
@@ -946,8 +1318,6 @@ void Zipr_t::OutputBinaryFile(const string &name)
 		{
 			b=byte_map[i];
 		}
-
-	
 		if(i-start_of_new_space<200)// keep verbose output short enough.
 			printf("Writing byte %#2x at %p, fileoffset=%lld\n", ((unsigned)b)&0xff, 
 				(void*)i, (long long)(i-start_of_new_space));
diff --git a/src/zipr_options.cpp b/src/zipr_options.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ca05858a701723f4669bb07d84516fc63be6c1f
--- /dev/null
+++ b/src/zipr_options.cpp
@@ -0,0 +1,82 @@
+#include <zipr_all.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+using namespace zipr;
+
+void Options_t::print_usage(int p_argc, char *p_argv[])
+{
+	printf("%s [options]\n", p_argv[0]);
+	printf("\t-v variant-id\t--variant variant-id: "
+		"Variant ID. Mandatory. Default: none.\n");
+	printf("\t-o file\t\t--output file: "
+		"Output file name. Optional. Default: b.out.\n");
+	printf("\t-z optimization\t--optimize optimization: "
+		"Enable an optimization. Repeatable. Optional. \n");
+}
+
+Options_t* Options_t::parse_args(int p_argc, char* p_argv[])
+{
+	extern char *optarg;
+	extern int optind, opterr, optopt;
+	int option = 0;
+	char options[] = "o:v:z:";
+	struct option long_options[] = {
+		{"output", 1, 0, 'o'},
+		{"variant", 1, 0, 'v'},
+		{"optimize", 0, 0, 'z'},
+		{0, 0, 0, 0},
+	};
+
+	Options_t *opt=new Options_t;
+	assert(opt);
+
+	while ((option = getopt_long(
+		p_argc, 
+		p_argv, 
+		options, 
+		long_options, 
+		NULL)) != -1)
+	{
+		switch (option) {
+			case 'z':
+			{
+				if (!strcmp("plopnotjump", ::optarg))
+				{
+					opt->EnableOptimization(
+						Optimizations_t::OptimizationPlopNotJump);
+				}
+				else
+				{
+					printf("Warning: Unrecognized optimization: %s\n", ::optarg);
+				}
+				break;
+			}
+			case 'o':
+			{
+				opt->m_outname = std::string(::optarg);
+				break;
+			}
+			case 'v':
+			{
+				char *valid = NULL;
+				long int variant_id = ::strtol(::optarg, 
+								&valid, 
+								10); 
+				if (*valid == '\0') {
+					opt->m_var_id = variant_id;
+					break;
+				}
+				printf("Error: Invalid variant id (%s).\n", ::optarg);
+				break;
+			}
+			default:
+			{
+				printf("Warning: Unrecognized option!\n");
+				break;
+			}
+		}
+	}
+	return opt;
+}