diff --git a/libtransform/include/integertransform64.hpp b/libtransform/include/integertransform64.hpp
index 9e6a0af3324606cedd3e883fbfbdbb2d59e73a79..7f2b2c20ec9e96297bf567324de644150614fe29 100644
--- a/libtransform/include/integertransform64.hpp
+++ b/libtransform/include/integertransform64.hpp
@@ -25,4 +25,7 @@ class IntegerTransform64 : public IntegerTransform
 
 } // end namespace
 
+#define OVERFLOW_DETECTOR_64             "overflow_detector_64"
+#define UNDERFLOW_DETECTOR_64            "underflow_detector_64"
+
 #endif
diff --git a/libtransform/include/transform.hpp b/libtransform/include/transform.hpp
index 03be88e4dae7b82b6cc72373ef9b65ac88534426..079b6e6caff1a8830859d1002c96d5b5abbfb8ea 100644
--- a/libtransform/include/transform.hpp
+++ b/libtransform/include/transform.hpp
@@ -24,8 +24,10 @@ class Transform {
 
 	protected:
 		void setAssembly(Instruction_t *p_instr, string p_asm);
+		Instruction_t* addNewAssembly(string p_asm);
 		Instruction_t* addNewAssembly(Instruction_t *p_instr, string p_asm);
-		Instruction_t* addCallbackHandler64(Instruction_t *p_orig, string p_callbackHandler, int p_numArgs);
+		Instruction_t* registerCallbackHandler64(string p_callbackHandler, int p_numArgs);
+		void addCallbackHandler64(Instruction_t *p_instr, string p_callbackHandler, int p_numArgs);
 		void addInstruction(Instruction_t *p_instr, string p_dataBits, Instruction_t *p_fallThrough, Instruction_t *p_target);
 		Instruction_t* carefullyInsertBefore(Instruction_t* &p_target, Instruction_t* &p_new);
 
@@ -59,7 +61,7 @@ class Transform {
 		void addMulRegisterConstant(Instruction_t *p_instr, Register::RegisterName p_regTgt, int p_constantValue, Instruction_t *p_fallThrough);
 		void addMovRegisters(Instruction_t *p_instr, Register::RegisterName p_regTgt, Register::RegisterName p_regSrc, Instruction_t *p_fallThrough);
 
-		Instruction_t* allocateNewInstruction(db_id_t p_fileID, Function_t* p_func);
+		Instruction_t* allocateNewInstruction(db_id_t p_fileID=BaseObj_t::NOT_IN_DATABASE, Function_t* p_func=NULL);
 
 		virtual_offset_t getAvailableAddress();
 
@@ -88,6 +90,7 @@ class Transform {
 		VariantID_t 		*m_variantID;
 		FileIR_t           	*m_fileIR;
 		set<std::string>	*m_filteredFunctions;
+		std::map<std::string, Instruction_t*> m_handlerMap;
 };
 
 // make sure these match values in detector_handlers.h in the strata library
diff --git a/libtransform/src/integertransform64.cpp b/libtransform/src/integertransform64.cpp
index 5fd5ae163941aa95d4d6253c6ea893468dc40e72..8bc5c8ce52df3563ab36e107fbe1105a19f1fc90 100644
--- a/libtransform/src/integertransform64.cpp
+++ b/libtransform/src/integertransform64.cpp
@@ -5,12 +5,25 @@ using namespace libTransform;
 
 /**
 *     64 bit implementation status of the integer transform
+*     20140228 64-bit overflows on multiply, signed/unsigned add/sub
+*     20140422 callback handlers added
 *
-*     20140228 64-bit overflows on multiply, signed/unsigned add/sub, halt policy
-*
+*      64-bit        signed     unsigned   unknown
+*      --------      ------     --------   -------
+*      add, sub       of          c         of,c
+*        mul          of          of        of
+*        lea         @todo      @todo       @todo
+*             
+*      32-bit        signed     unsigned   unknown
+*      --------      ------     --------   -------
+*      add, sub      @todo      @todo       @todo
+*        mul         @todo      @todo       @todo
+*        lea         @todo      @todo       @todo
+
 *     @todo:
+*           - test unknown
+*           - test warnings only mode
 *           - handle LEA instructions
-*           - callback handler for diagnostics
 *
 **/
 
@@ -154,15 +167,14 @@ void IntegerTransform64::handleUnderflowCheck(Instruction_t *p_instruction, cons
 //	        mul a, b                 ; <instruction to instrument>
 //              jno <OrigNext>           ; if no overflows, jump to original fallthrough instruction
 //              mov a, MIN/MAX           ; policy = min-saturate (underflow) / max-saturate (overflow)
+//              of64/uf64 handler        ; call the callback handler (handle diagnostics)
 // OrigNext:    <nextInstruction>        ; original fallthrugh
 //
 void IntegerTransform64::addOverflowUnderflowCheck(Instruction_t *p_instruction, const MEDS_InstructionCheckAnnotation& p_annotation, int p_policy)
 {
-	Instruction_t* jncond_i = NULL;
-	Instruction_t* policy_i = NULL;
+	char tmpbuf[1024];
 
 	assert(getFileIR() && p_instruction && p_instruction->GetFallthrough());
-
 	Register::RegisterName targetReg = getTargetRegister(p_instruction);
         if (targetReg == Register::UNKNOWN)
         {
@@ -172,42 +184,66 @@ void IntegerTransform64::addOverflowUnderflowCheck(Instruction_t *p_instruction,
 
         logMessage(__func__, p_annotation, "debug");
 
-	jncond_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction());
-	policy_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction());
+	Instruction_t* jncond_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction());
+	Instruction_t* lea_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction());
+	Instruction_t* policy_i;
 
 	Instruction_t* next_i = p_instruction->GetFallthrough();
 	p_instruction->SetFallthrough(jncond_i); 
 
-	if (p_annotation.isUnsigned())
+	if (p_policy == POLICY_CONTINUE_SATURATING_ARITHMETIC)
+		policy_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction());
+	else
+		policy_i = lea_i;
+
+	if (p_annotation.isSigned() || isMultiplyInstruction(p_instruction))
 	{
-		addJnc(jncond_i, policy_i, next_i);
+		addJno(jncond_i, policy_i, next_i); 
 	}
-	else if (p_annotation.isSigned())
+	if (p_annotation.isUnsigned())
 	{
-		addJno(jncond_i, policy_i, next_i);
+		addJnc(jncond_i, policy_i, next_i);
 	}
 	else
 	{ 	// unknown sign
-		addJno(jncond_i, policy_i, next_i);
+		Instruction_t* jnc_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction());
+		addJno(jncond_i, policy_i, jnc_i); 
+		addJnc(jnc_i, policy_i, next_i); 
 	}
 
         if (p_policy == POLICY_CONTINUE_SATURATING_ARITHMETIC)
 	{
 		if (p_annotation.isUnderflow())
-		{
-                	addMinSaturation(policy_i, targetReg, p_annotation, next_i);
-		}
+                	addMinSaturation(policy_i, targetReg, p_annotation, lea_i); 
 		else
-		{
-                	addMaxSaturation(policy_i, targetReg, p_annotation, next_i);
-		}
-
-		// add callback handler here for diagnostics
+                	addMaxSaturation(policy_i, targetReg, p_annotation, lea_i);
 	}
+
+	setAssembly(lea_i, "lea rsp, [rsp-128]");  // red zone 
+
+	// add callback handler here for diagnostics
+	// pass in PC of instrumented instruction
+	// pass in p_policy 
+	sprintf(tmpbuf,"push 0x%08x", p_policy);  
+	Instruction_t* instr = addNewAssembly(lea_i, tmpbuf);
+	sprintf(tmpbuf,"push 0x%08x", p_instruction->GetAddress()->GetVirtualOffset()); 
+	instr = addNewAssembly(instr, tmpbuf);
+
+	Instruction_t* call = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction());
+	instr->SetFallthrough(call);
+//	setAssembly(call, "db 0xe8, 00, 00, 00, 00"); 
+	setAssembly(call, "call 0"); 
+		
+	if (p_annotation.isOverflow())
+		addCallbackHandler64(call, OVERFLOW_DETECTOR_64, 2); // 2 args for now
 	else
-	{
-		addHlt(policy_i, next_i);
-	}
+		addCallbackHandler64(call, UNDERFLOW_DETECTOR_64, 2); // 2 args for now
+
+	assert(call->GetTarget());
+
+	instr = addNewAssembly(call, "lea rsp, [rsp+128+16]");  
+	call->SetFallthrough(instr);
+	instr->SetFallthrough(next_i);
 
 	if (p_annotation.isUnderflow())
 		m_numUnderflows++;
diff --git a/libtransform/src/transform.cpp b/libtransform/src/transform.cpp
index c8ee073b08bbab177a50b4a239e0f5ebe161a788..898453d6547befd288f2f8e4b3858f2831a6b39a 100644
--- a/libtransform/src/transform.cpp
+++ b/libtransform/src/transform.cpp
@@ -78,6 +78,14 @@ Instruction_t* Transform::carefullyInsertBefore(Instruction_t* &p_instrumented,
 	return dupInstr;
 }
 
+void Transform::addPushf(Instruction_t *p_pushf_i, Instruction_t *p_fallThrough)
+{
+	string dataBits;
+	dataBits.resize(1);
+	dataBits[0] = 0x9c;
+	addInstruction(p_pushf_i, dataBits, p_fallThrough, NULL);
+}
+
 void Transform::addPushRegister(Instruction_t *p_instr, Register::RegisterName p_reg, Instruction_t *p_fallThrough)
 {
 	string dataBits;
@@ -282,7 +290,7 @@ void Transform::addNop(Instruction_t *p_nop_i, Instruction_t *p_fallThrough)
 Instruction_t* Transform::allocateNewInstruction(db_id_t p_fileID, Function_t* p_func)
 {
 	Instruction_t *instr = new Instruction_t();
-	AddressID_t *a =new AddressID_t();
+	AddressID_t *a = new AddressID_t();
 
 	a->SetFileID(p_fileID);
 
@@ -1242,14 +1250,6 @@ void Transform::addMinSaturation(Instruction_t *p_instruction, Register::Registe
 	}
 }
 
-void Transform::addPushf(Instruction_t *p_pushf_i, Instruction_t *p_fallThrough)
-{
-	string dataBits;
-	dataBits.resize(1);
-	dataBits[0] = 0x9c;
-	addInstruction(p_pushf_i, dataBits, p_fallThrough, NULL);
-}
-
 void Transform::setAssembly(Instruction_t *p_instr, string p_asm)
 {
 	m_fileIR->RegisterAssembly(p_instr, p_asm);
@@ -1257,125 +1257,149 @@ void Transform::setAssembly(Instruction_t *p_instr, string p_asm)
 
 //
 // Allocate and add new instruction given its assembly form
+// If <p_instr> not NULL, then set fallthrough appropriately
+//
 // Returns the newly added instruction
 //
+// <p_instr> defined:
 // <p_instr>            <p_instr>
-// <fallthrough>  ==>   <p_asm>
+// <fallthrough>  ==>   <newinstr>(<p_asm>)
 //                      <fallthrough>
 //
+// <p_instr> is NULL:
+//                ==>   <newinstr>(<p_asm>)
+//
 Instruction_t* Transform::addNewAssembly(Instruction_t *p_instr, string p_asm)
 {
-	Instruction_t* newinstr = allocateNewInstruction(p_instr->GetAddress()->GetFileID(), p_instr->GetFunction());
+	Instruction_t* newinstr;
+	if (p_instr)
+		newinstr = allocateNewInstruction(p_instr->GetAddress()->GetFileID(), p_instr->GetFunction());
+	else
+		newinstr = allocateNewInstruction(BaseObj_t::NOT_IN_DATABASE, NULL);
+
 	m_fileIR->RegisterAssembly(newinstr, p_asm);
-	newinstr->SetFallthrough(p_instr->GetFallthrough());
-	p_instr->SetFallthrough(newinstr);
+
+	if (p_instr)
+	{
+		newinstr->SetFallthrough(p_instr->GetFallthrough());
+		p_instr->SetFallthrough(newinstr);
+	}
+
 	return newinstr;
 }
 
+// register instruction in IRDB
+// 20140421
+Instruction_t* Transform::addNewAssembly(string p_asm)
+{
+	return addNewAssembly(NULL, p_asm);
+}
+
+// x86-64
+// 20140421
+void Transform::addCallbackHandler64(Instruction_t *p_orig, string p_callbackHandler, int p_numArgs)
+{
+	// nb: if first time, register and cache callback handler sequence
+	if (m_handlerMap.count(p_callbackHandler) == 0)
+	{
+		m_handlerMap[p_callbackHandler] = registerCallbackHandler64(p_callbackHandler, p_numArgs);
+	}
+
+	if (p_orig)
+		p_orig->SetTarget(m_handlerMap[p_callbackHandler]);
+}
 
 // x86-64
-// add callback handler sequence to <p_orig>
+// register callback handler sequence 
 // 20140416
-Instruction_t* Transform::addCallbackHandler64(Instruction_t *p_orig, string p_callbackHandler, int p_numArgs)
+Instruction_t* Transform::registerCallbackHandler64(string p_callbackHandler, int p_numArgs)
 {
 	Instruction_t *instr;
+	Instruction_t *first;
 	char tmpbuf[1024];
 
-	// save flags and registers
-	instr = addNewAssembly(p_orig, "pushf");
-	instr = addNewAssembly(instr,  "push rax");
-	instr = addNewAssembly(instr,  "push rbx");
-	instr = addNewAssembly(instr,  "push rcx");
-	instr = addNewAssembly(instr,  "push rdx");
-	instr = addNewAssembly(instr,  "push rsi");
-	instr = addNewAssembly(instr,  "push rdi");
-	instr = addNewAssembly(instr,  "push rbp");
-	instr = addNewAssembly(instr,  "push rsp");
-	instr = addNewAssembly(instr,  "push r8");
-	instr = addNewAssembly(instr,  "push r9");
-	instr = addNewAssembly(instr,  "push r10");
-	instr = addNewAssembly(instr,  "push r11");
-	instr = addNewAssembly(instr,  "push r12");
-	instr = addNewAssembly(instr,  "push r13");
-	instr = addNewAssembly(instr,  "push r14");
-	instr = addNewAssembly(instr,  "push r15");
-
-	// handle the arguments (if any)
-	//    rdi, rsi, rdx, rcx, r8, r9
-	for (int i = p_numArgs, paramCount = 1; i >= 1; --i, paramCount++)
-	{
-		//            pushf    16 regs       param 	
-		//            -----    --------      -----
-		int offset =    8    + (16 * 8)   +  (i*8);
-		string paramReg;
-		switch(paramCount) 
-		{
-			case 1:
-				paramReg = "rdi";
-				break;
-			case 2:
-				paramReg = "rsi";
-				break;
-			case 3:
-				paramReg = "rdx";
-				break;
-			case 4:
-				paramReg = "rcx";
-				break;
-			case 5:
-				paramReg = "r8";
-				break;
-			case 6:
-				paramReg = "r9";
-				break;
-			default:
-				assert(0); // only handle up to 6 args
-				break;
-		}
-
-		// e.g.: mov rdi, [rsp+offset]
-		sprintf(tmpbuf, "[rsp+%d]", offset);
-
-		instr = addNewAssembly(instr, "mov " + paramReg + ", " + tmpbuf);
-	}
+	// save flags and 16 registers (136 bytes)
+	// call pushes 8 bytes
+	// Total: 8 * 18 = 144
+	first = instr = addNewAssembly("push rsp");
+	instr = addNewAssembly(instr, "push rbp");
+	instr = addNewAssembly(instr, "push rdi");
+	instr = addNewAssembly(instr, "push rsi");
+	instr = addNewAssembly(instr, "push rdx");
+	instr = addNewAssembly(instr, "push rcx");
+	instr = addNewAssembly(instr, "push rbx");
+	instr = addNewAssembly(instr, "push rax");
+	instr = addNewAssembly(instr, "push r8");
+	instr = addNewAssembly(instr, "push r9");
+	instr = addNewAssembly(instr, "push r10");
+	instr = addNewAssembly(instr, "push r11");
+	instr = addNewAssembly(instr, "push r12");
+	instr = addNewAssembly(instr, "push r13");
+	instr = addNewAssembly(instr, "push r14");
+	instr = addNewAssembly(instr, "push r15");
+	instr = addNewAssembly(instr, "pushf");
+
+	instr = addNewAssembly(instr, "mov rdi, rsp");
+
+	// handle the arguments (if any): rdi, rsi, rdx, rcx, r8, r9
+	// first arg starts at byte +144
+	if (p_numArgs >= 1)
+		instr = addNewAssembly(instr,  "mov rsi, [rsp+144]");
+	if (p_numArgs >= 2)
+		instr = addNewAssembly(instr,  "mov rdx, [rsp+152]");
+	if (p_numArgs >= 3)
+		instr = addNewAssembly(instr,  "mov rcx, [rsp+160]");
+	if (p_numArgs >= 4)
+		instr = addNewAssembly(instr,  "mov r8, [rsp+168]");
+	if (p_numArgs > 4)
+		assert(0); // only handle up to 5 args
 
 	// pin the instruction that follows the callback handler
-	Instruction_t* postCallback = allocateNewInstruction(p_orig->GetAddress()->GetFileID(), p_orig->GetFunction());
+	Instruction_t* postCallback = allocateNewInstruction();
 	virtual_offset_t postCallbackReturn = getAvailableAddress();
 	postCallback->GetAddress()->SetVirtualOffset(postCallbackReturn);
 
 	// push the address to return to once the callback handler is invoked
-	sprintf(tmpbuf,"push 0x%x", postCallbackReturn);
+	sprintf(tmpbuf,"mov rax, 0x%x", postCallbackReturn);
 	instr = addNewAssembly(instr, tmpbuf);
 
+	instr = addNewAssembly(instr, "push rax");
+
 	// use a nop instruction for the actual callback
 	instr = addNewAssembly(instr, "nop");
-	instr->SetComment(" -- callback to " + p_callbackHandler + " orig: " + p_orig->GetComment()) ;
+	instr->SetComment(" -- callback: " + p_callbackHandler);
 	instr->SetCallback(p_callbackHandler); 
 	instr->SetFallthrough(postCallback); 
 
+	// need to make sure the post callback address is pinned
+	// (so that ILR and other transforms do not relocate it)
+	AddressID_t *indTarg =new AddressID_t();
+	m_fileIR->GetAddresses().insert(indTarg);
+	indTarg->SetVirtualOffset(postCallback->GetAddress()->GetVirtualOffset());
+	indTarg->SetFileID(BaseObj_t::NOT_IN_DATABASE); // SPRI global namespace
+	postCallback->SetIndirectBranchTargetAddress(indTarg);
+
 	// restore registers
-	setAssembly(postCallback, "pop r15");           
-	instr = addNewAssembly(postCallback, "pop r14");
+	setAssembly(postCallback, "popf");           
+	instr = addNewAssembly(postCallback, "pop r15");
+	instr = addNewAssembly(instr, "pop r14");
 	instr = addNewAssembly(instr, "pop r13");
 	instr = addNewAssembly(instr, "pop r12");
 	instr = addNewAssembly(instr, "pop r11");
 	instr = addNewAssembly(instr, "pop r10");
 	instr = addNewAssembly(instr, "pop r9");
 	instr = addNewAssembly(instr, "pop r8");
-	instr = addNewAssembly(instr, "pop rsp");
-	instr = addNewAssembly(instr, "pop rbp");
-	instr = addNewAssembly(instr, "pop rdi");
-	instr = addNewAssembly(instr, "pop rsi");
-	instr = addNewAssembly(instr, "pop rdx");
-	instr = addNewAssembly(instr, "pop rcx");
-	instr = addNewAssembly(instr, "pop rbx");
 	instr = addNewAssembly(instr, "pop rax");
+	instr = addNewAssembly(instr, "pop rbx");
+	instr = addNewAssembly(instr, "pop rcx");
+	instr = addNewAssembly(instr, "pop rdx");
+	instr = addNewAssembly(instr, "pop rsi");
+	instr = addNewAssembly(instr, "pop rdi");
+	instr = addNewAssembly(instr, "pop rbp");
+	instr = addNewAssembly(instr, "lea rsp, [rsp+8]");
 
-	// restore flags
-	instr = addNewAssembly(instr, "popf");
 	instr = addNewAssembly(instr, "ret");
 
-	return instr;
+	// return first instruction in the callback handler chain
+	return first;
 }
-
diff --git a/libtransform/tests/Makefile b/libtransform/tests/Makefile
index 1675a65dd11e69dda64487fdee05f8351d01f164..162467a40000acd7cd2f53195366b1f3df510009 100644
--- a/libtransform/tests/Makefile
+++ b/libtransform/tests/Makefile
@@ -12,7 +12,7 @@ LD=DO_NOT_USE
 #exes=signed_add.exe
 #exes=simpletest.exe
 #exes=dummy.exe
-exes=unsigned_mul.exe
+exes=unsigned_mul.exe signed_add.exe signed_mul.exe 
 
 
 all: env_check  ${exes}