www.pudn.com > ASM86_64.rar > generate.c


#include 

#include "generate.h"
#include "operand.h"
#include "label.h"


extern hole_pos_t *hole_link;

static unsigned long offset = 0;

static char err_msg[80];


/******************************************************************
 function unsigned char get_16modrm(mem_t *mem)

last change: 02-19-2006 21:45 by mik
*******************************************************************/
unsigned char get_16modrm(mem_t *mem, int *is_sib, int *set_disp)
{
	unsigned char modrm = 0;

	unsigned int size = mem->disp ? get_sizeof(mem->disp) : 0;
		
	/* 16-bit memory operand only set MOD field and R/M field */
	if (mem) {
		if (!mem->base && !mem->index && mem->disp) {
			modrm |= 0x06;
		} else switch (size) {
		case 1: modrm |= 0x40; break;
		case 2: modrm |= 0x80; break;
		}
	
		if (((mem->base == BX) && (mem->index == SI)) ||
			(mem->base == SI && mem->index == BX))
			modrm |= 0x0;
		else if (((mem->base == BX) && (mem->index == DI)) ||
			(mem->base == DI && mem->index == BX))
			modrm |= 0x01;
		else if (((mem->base == BP) && (mem->index == SI)) ||
			(mem->base == SI && mem->index == BP))
			modrm |= 0x02;
		else if (((mem->base == BP) && (mem->index == DI)) ||
			(mem->base == DI && mem->index == BP))
			modrm |= 0x03;
		else if ((mem->base == SI) && (!mem->index))
			modrm |= 0x04;
		else if ((mem->base == DI) && (!mem->index))
			modrm |= 0x05;
		else if (!mem->base && !mem->index && mem->disp) {
			modrm |= 0x06;
			if (size == 1)
				*set_disp = 1; 	/* 1-byte 0 need */
		} else if ((mem->base == BP) && !mem->index) {
			if (size == 0) {
				modrm |= 0x46;
				*set_disp = 1;	/* 1-byte 0 need */
			} else if (size == 1)
				modrm |= 0x46;
			else if (size == 2)
				modrm |= 0x86;

		} else if ((mem->base == BX) && (!mem->index))
			modrm |= 0x07;
	}


	return modrm;
}





/*******************************************************************
 function: unsigned char get_modrm(e_key_t *e_key)
 parameter:
           e_key: instruction key word.
 return: 	 
           modrm byte.

last change: 02-19-2006 20:45 by mik
last change: 02-19-2006 22:09 by mik
********************************************************************/

unsigned char get_modrm(e_key_t *e_key, int *is_sib, int *set_disp)
{

	unsigned char modrm = 0;
	mem_t *mem = 0;
	unsigned char reg = 0;

	ops_key_t *ops_key = e_key->ops_key;
	unsigned int i_attr = e_key->i_key->i_attr;
	ops_type_t ops_type = get_ops_type(ops_key);
	unsigned int addr_size = get_ops_addr(ops_key);


	switch (ops_type) {
	case D_R|S_I:
		/* 
		  example: mov eax, 0xc 
		  if the opcode is 0xC7, it's a group.
	 	     so need to set group id at reg field of modrm !!!
		     so skip break jmp next to do ...

		  if the opcode is 0xB8, it's not need modrm byte
		     so this not to do never !!!

		  ****** It has not a SIB byte !!! ******
		*/
		
	case S_R:		/* only one register operand */
		/* 
		  example: inc eax
		  if the opcode is 0xFF/0, it's a group.
		     so need to set group id at reg field of modrm !!!
		     so do this ....

		  if the opcode is 0x40, it's not need modrm byte
		     so this not to do never !!!

		  ****** It has not a SIB byte !!! ******
		*/

		/* set MOD field of modrm byte */
		reg = ops_key->so_key->reg ? ops_key->so_key->reg :
			ops_key->do_key->reg ? ops_key->do_key->reg : 0;

		modrm |= 0xc0;	

		/* set R/M field of modrm byte */
		modrm |= reg & 0x07;

		/* set REG field of modrm byte */
		if (is_GROUP(i_attr)) {
			/* example: call rax, inc rax, so that.... */
			/* there have a group id 
			  ******* the REG field is GROUP ID ****** 
			*/
			modrm |= (unsigned char)get_GROUPID(i_attr);

		} else { 
			/* example: setz al, setb al, so that ... 
			  there are two opcodes, have not group id */

			/* so not group set 
			  ****** the REG field is 0 *****
			*/
		}
		break;

	case S_I:  break;	
		/* source operand is imme
		   ****** so it has no modrm byte ******
		 */

	case T_R|D_M|S_I:	
		/*
			the case for  IMUL Gv, Ev, Ev
			example: imul edi, [si], 0x0c

			in this case, the modrm's byte is same as D_M|S_R
		*/

	case D_M|S_R:
		/* source operand is register, dest operand is memory 
		   the reg field of modrm is register ID ...
		   ****** it has not group id ... ******
		*/
	case D_R|S_M:
		/* source operand is memory, dest operand is register
		   the reg field of modrm is register ID ...
		   ****** it has not group id ******
		*/

		reg = ops_key->so_key->reg ? ops_key->so_key->reg : 
			ops_key->do_key->reg ? ops_key->do_key->reg : 
			ops_key->to_key && ops_key->to_key->reg ?
			ops_key->to_key->reg : 0;
		
		/* 
		   it's no group,so skip break jmp next step to do !!!
		*/
		
		/* set REG field of modrm */
		modrm |= (reg & 0x07) << 3;

	case D_M|S_I:	/* skip break jmp next step to do !!! */
		/* example: mov [eax], 0xc => is group !!! */
		/* skip reg field set for register ... it has a group */
	case S_M:

		/* modrm's REG field */
		if (is_GROUP(i_attr))
			/* example: call [eax] */
			/* example: mov [eax], 0xc */

			/* the REG field is GROUP ID */
			modrm |= (unsigned char)get_GROUPID(i_attr);

		else { /* example: setz (byte)[ecx] is no group */ }

/*
		mem = ops_key->so_key->mem ? ops_key->so_key->mem :
			ops_key->do_key && ops_key->do_key->mem ?
			ops_key->do_key->mem : 0;
*/		
		unsigned int o_attr = 0;
		if (ops_key->so_key->mem) {
			mem = ops_key->so_key->mem;
			o_attr = e_key->i_key->so_attr;
		} else if (ops_key->do_key && ops_key->do_key->mem) {
			mem = ops_key->do_key->mem;
			o_attr = e_key->i_key->do_attr;
		} else if (ops_key->to_key && ops_key->to_key->mem) {
			/* this case never do */
			mem = ops_key->to_key->mem;
			o_attr = e_key->i_key->to_attr;
		}


		unsigned int size = mem->disp ? get_sizeof(mem->disp) : 0;

		if (((mem->index == ESP) || (mem->index == RSP)) 
			&& mem->base) 
		{
			/********************* NOTE: **********************
			   if have a "esp" or "rsp" register of memory operand
			   must set "esp" or "rsp" to base register !!!

			   becase the X86-64 not support "esp" or "rsp" 
				index register !!!
			*****************************************************/

			/* exchange base and index register */	
			/* example: mov [eax+esp],eax ==> mov [esp+eax],eax */

			unsigned char c = mem->base;
			mem->base = mem->index;
			mem->index = c;

		} else if (((mem->base == EBP) || (mem->base == RBP)) 	
			&& mem->index)
		{
			/********************* NOTE: **********************
			 if base is "ebp" or "rbp" register of memory operand
		         It's good choice that set "ebp" or "rbp" 
				to index register !!!

			 becase it's good idea !!!
			***************************************************/

			/* exchange base and index reister */
			/* example: mov [ebp+eax],eax ==> mov [eax+ebp],eax */

			unsigned char r = mem->index;
			mem->index = mem->base;
			mem->base = r;

		} else if (((mem->base == EBP) || (mem->base == RBP)) 
			&& !mem->index)
		{
			/* only base register is "ebp" or "rbp" */
			/* must set disp for "ebp" base register */
			if (size == 0) {
				*set_disp = 1;	/* 1-byte 0 need */
				modrm |= 0x40;	/* MOD field */

			} else if (size == 2)
				*set_disp = 2;


		} else if (!mem->base && !mem->index && mem->disp) {
			/* only memory offset value of memory operand */
			/* [disp32] is 0x05 => r/m field of memory operand */

			/* if base is 0, index is 0, and has a disp value 
			      return 0x05 modrm byte ...
			 */
/*
			if (SIZE(o_attr) == SIZE_V || is_FS_IN_BITS(i_attr))
				*set_disp =  (current_bits >> 3) - 
					get_sizeof(mem->disp);

*/
			*set_disp = (current_bits >> 3) - get_sizeof(mem->disp);

			/******* It has not a SIB byte *******/
			if (addr_size != 16) {
				modrm |= 0x05;
				return modrm;
			}
		}


		if (addr_size == 16) {
			modrm |= get_16modrm(mem, is_sib, set_disp);
			*is_sib = 0;
			break;
		}


		/* example: mov [ecx*4+0xc], 0xc */
		if (mem->index && !mem->base) {
			modrm |= 0x04;
			if (size == 1)
				*set_disp = 3;
			else if (size == 2)
				*set_disp = 2;

		} else { 

			/* modrm's MOD field */
			if (size == 0) {
				/* no disp */
			} else if (size == 1) { 
				/* disp8 */
				modrm |= 0x40;
			} else if (size == 2) {
				/* disp32 */
				modrm |= 0x80;
				*set_disp = 2;	/* 2-byte 0 need */
			} else {
				/* disp32 */
				modrm |= 0x80;
			}

			/* modrm's R/M field */
			modrm |= mem->index ? 0x04 : mem->base & 0x07;

		}
		/* 
  			*** is SIB byte need ???  ***
	
		 if base is "esp" or "rsp" register, then must set SIB byte !!!
		    becase x86-64 not support esp register in MODRM byte !!!
			
		 And if has a index register, then must set SIB byte !!!
		*/

		if ((mem->base == ESP) || (mem->base == RSP) || (mem->index))
			*is_sib = 1;

		break;

	case D_R|S_R:
		/* no group */
		modrm |= 0xc0 | ops_key->do_key->reg & 0x07;
		modrm |= (ops_key->so_key->reg & 0x07) << 3;

		/*** has not a SIB byte ***/
		break;

	case T_R|D_R|S_I:		/* imul Gv,Ev,Iv */
	case T_R|D_R|S_R:		/* shld Ev, Gv, CL */
		modrm |= 0xc0 | ops_key->to_key->reg & 0x07;
		modrm |= (ops_key->do_key->reg & 0x07) << 3;
		
		break;
	default: break;

	} /**** end of switch ****/	
		

	return modrm;
}



/*****************************************************************
 function: unsigned char get_sib(e_key_t *e_key)
 parameter: 

last change: 02-19-2006 00:01 by mik
*****************************************************************/
unsigned char get_sib(e_key_t *e_key, int *set_disp)
{
	unsigned char sib = 0;
	ops_key_t *ops_key = e_key->ops_key;

	mem_t *mem = ops_key->so_key && ops_key->so_key->mem ?
		ops_key->so_key->mem : ops_key->do_key &&
		ops_key->do_key->mem ? ops_key->do_key->mem :
		ops_key->to_key && ops_key->do_key->mem ?
		ops_key->to_key->mem : 0; 
	

	if (mem && ((mem->base & 0xf0) != 0x20)) {
		if (((mem->base == ESP) || (mem->base == RSP)) && mem->index)
		{
			/* example: mov (byte)[esp+eax], 0xc */
			sib |= mem->base & 0x07;
			sib |= (mem->index & 0x07) << 3;

		} else if (((mem->index == ESP) || (mem->index == RSP))
			&& mem->base) {
			/* example: mov (byte)[eax+esp], 0xc */
			sib |= mem->index & 0x07;
			sib |= (mem->base & 0x07) << 3;

		} else if (((mem->base == ESP) || (mem->base == RSP)) 
			&& !mem->index) {
			/* example: mov (byte)[esp], 0xc */
			sib |= (mem->base & 0x07) | 0x20;

		} else {
			sib |= (mem->index & 0x07) << 3;
			if (mem->base)
				sib |= mem->base & 0x07;
			else {
				/* example: mov [ecx*4], ecx */
				sib |= 0x05;
				if (!mem->disp)
					*set_disp = 4;
			}
		}

		sib |= (mem->scale & 0x0f) << 6;
	}

	return sib;
}


/**************************************************************
 function: int get_disp(char *e_buf, e_key_t *e_key)

**************************************************************/

void get_disp(char *e_buf, e_key_t *e_key)
{
	union {
		long long ll;
		char byte;
		char word[2];
		char dword[4];
		char qdword[8];
	} u;
	mem_t *mem = 0;
	
	if (e_key && e_key->ops_key)
		if (e_key->ops_key->so_key && e_key->ops_key->so_key->mem)
			mem = e_key->ops_key->so_key->mem;
		else if (e_key->ops_key->do_key && e_key->ops_key->do_key->mem)
			mem = e_key->ops_key->do_key->mem;
		else if (e_key->ops_key->to_key && e_key->ops_key->to_key->mem)
			mem = e_key->ops_key->to_key->mem;
	
	if (mem) {
		u.ll = mem->disp;
		switch (get_sizeof(u.ll)) {
		case 1:
			e_buf[offset++] = u.byte; break;
		case 2:
			e_buf[offset++] = u.word[0];
			e_buf[offset++] = u.word[1];
			e_buf[offset++] = 0;
			e_buf[offset++] = 0;
			break;
		case 4:
			e_buf[offset++] = u.dword[0];
			e_buf[offset++] = u.dword[1];
			e_buf[offset++] = u.dword[2];
			e_buf[offset++] = u.dword[3];
			break;
		case 8:
			e_buf[offset++] = u.qdword[0];
			e_buf[offset++] = u.qdword[1];
			e_buf[offset++] = u.qdword[2];	
			e_buf[offset++] = u.qdword[3];
			e_buf[offset++] = u.qdword[4];
			e_buf[offset++] = u.qdword[5];
			e_buf[offset++] = u.qdword[6];
			e_buf[offset++] = u.qdword[7];
		}
	
	}
}



/*********************************************************
 function: errno_t do_generate(char *e_buf, e_key_t *e_key)

 parameter: 
           e_buf: this is encode memory buffer.
           e_key: this is instruction encode key word link.
***********************************************************/

errno_t do_generate(char *e_buf, e_key_t *e_key)
{
	errno_t errno = 0;

	if (!e_buf || !e_key)
		return ERR_ERROR;

	unsigned long long priv_pc = current_pc;
	
	offset = 0;
	unsigned char rex = 0x40;
	int is_sib = 0;
	int set_disp = 0;		/* must set disp */
	int set_imme = 0;

	unsigned int to_attr = 0;
	unsigned int do_attr = 0;
	unsigned int so_attr = 0;
	unsigned int i_attr = 0;
	o_key_t *to_key = 0;
	o_key_t *so_key = 0;
	o_key_t *do_key = 0;

	ops_key_t *ops_key = e_key->ops_key;


	union {
		unsigned short opcode;	/* two bytes opcode */
		unsigned char code[2];
	} u;
	

	if (e_key->i_key) {
		to_attr = e_key->i_key->to_attr;
		do_attr = e_key->i_key->do_attr;
		so_attr = e_key->i_key->so_attr;
		i_attr = e_key->i_key->i_attr;
		u.opcode = e_key->i_key->opcode;
	}

	if (ops_key) {
		to_key = ops_key->to_key;
		do_key = ops_key->do_key;
		so_key = ops_key->so_key;
	}



	mem_t *mem = so_key && so_key->mem ? so_key->mem :
		do_key && do_key->mem ? do_key->mem : 0;
		to_key && to_key->mem ? to_key->mem : 0;
	
	imme_t *imme = so_key && so_key->imme ? so_key->imme :
		do_key && do_key->imme ? do_key->imme :	
		to_key && to_key->imme ? to_key->imme : 0;

	int oattr_size = 0;
	if (so_key) {
		oattr_size = SIZE(so_attr);
	} else if (do_key) {
		oattr_size = SIZE(do_attr);	
	} else if (to_key) {
		oattr_size = SIZE(to_attr);
	}

	unsigned int ops_size = get_ops_size(ops_key);
	unsigned int addr_size = get_ops_addr(ops_key);



	if (is_FS(i_attr))
		ops_size = get_FS_SIZE(i_attr);

/************************************************************************/


	prefix_t *i_prefix = e_key->i_prefix; 

	if (i_prefix) {			/* lock or rep prefix */
		if (i_prefix->lock)
			e_buf[offset++] = i_prefix->lock;
		if (i_prefix->rep)
			e_buf[offset++] = i_prefix->rep;
	}


	/************************************* 
	 * size override prefix  
	 * address override prefix
	 * segment override prefix 
         *************************************/

	/* segment override */
	if (mem && mem->oseg)
		e_buf[offset++] = mem->oseg;



	/*******************************************************
         * TODO: reserved for check instruction's attribute
         *       -> to check instruction fixed-operand size
         *       -> to check instruction default operand size
	 *******************************************************/


	/* size override */
	if (is_NO_CAST(i_attr)) {
		/* example: push es, push cs .... */
		/* do nothing */
	} else if (!so_key && !do_key && !to_key && !is_FS(i_attr)) { 
		/*** no operands and no fix operand's size ***/
		/* example: "nop", "ret", so that....*/	
		/* do nothing */
	} else if (current_bits == 16) {  /* CPU's current mode is 16-bit */
		if ((addr_size == 32) && !is_NO_CAST_ADDR(i_attr))
			e_buf[offset++] = 0x67;
		if ((ops_size == 32) && !is_NO_CAST_SIZE(i_attr))
			e_buf[offset++] = 0x66;

	} else if (current_bits == 32) { /* CPU's current mode is 32-bit */
		if ((addr_size == 16) && !is_NO_CAST_ADDR(i_attr))
			e_buf[offset++] = 0x67;
		if ((ops_size == 16) && !is_NO_CAST_SIZE(i_attr))
			e_buf[offset++] = 0x66;


	} else if (current_bits == 64) { /* CPU's current mode is 64-bit */

		if ((addr_size == 32) && !is_NO_CAST_ADDR(i_attr))
			e_buf[offset++] = 0x67;
		
		/*     more instruct in 64-bit mode to default 
		   operand size is 32-bit		
		       so ops_size is 32-bit have not 0x66 byte */

		if ((ops_size == 16) && !is_NO_CAST_SIZE(i_attr))
			e_buf[offset++] = 0x66;

		/* 64-bit mode not support to 16-bit address size 
		   so addr_size is 16-bit have not 0x67 byte */

		/******* set rex byte to get extern GPRs ***********/
		if (ops_size == 64 || addr_size == 64 ||
			((so_key && (so_key->reg & 0x08)) ||
			(do_key && (do_key->reg & 0x08)) ||
			(to_key && (to_key->reg & 0x08)))) 
		{
			/* set REX.W to extern 64-bit */
			if (!is_DS_64(i_attr) && !is_FS_64(i_attr)
					&& !is_FS_8(i_attr))
				rex |= REX_W;	

			switch (get_ops_type(ops_key)) {
			case S_R: 	/* register */
		#if 0
				if (is_GROUP(i_attr)) {
					/* example "inc rcx" 
					   it's GROUP,so set REX.B 
					*/
					if (so_key->reg & 0x08) 
						rex |= REX_B;	
				} else { /* have not other insturction */ }
		#endif
				if (is_eGPR(so_key->reg))
					rex |= REX_B;
				break;
			case S_M:	/* it's a memory */
				/* it's not to extern 64-bit address */
				if (addr_size != 64)
					break;

				if (mem->base && !mem->index) {
			#if 0
					if (is_GROUP(i_attr)) {
						/* example: call [rcx] */
						/* it's a GROUP,so set REX.B */ 
						if (so_key->mem->base & 0x08)
							rex |= REX_B;
					} else { /* have not other */ }	
			#endif
					if (is_eGPR(so_key->mem->base))
						rex |= REX_B;

				} else if (mem->index && !mem->base) {
			#if 0
					if (is_GROUP(i_attr)) {
						if (mem->index & 0x08)
							rex |= REX_X;
					} else { /* have not oterh */}
			#endif
					if (is_eGPR(mem->index))	
						rex |= REX_X;

				} else if (mem->base && mem->index) {
			#if 0
					if (is_GROUP(i_attr)) {
						if (mem->base & 0x08)
							rex |= REX_B;
						if (mem->index & 0x08)
							rex |= REX_X;	
					} else { }
			#endif
					if (is_eGPR(mem->base))
						rex |= REX_B;

					if (is_eGPR(mem->index))
						rex |= REX_X;	

				} else if (mem->disp) {
					/* example:call [0x1122334455667788] */
					/* it's GROUP,so set REX.B */
					if (is_GROUP(i_attr)) {
						rex |= REX_B;
					} else { /* have not other */ }
				
				}
				break;
			case S_I: break; 	/* have not REX.B */
			case D_R|S_R:	/* source is reg and dest is reg */ 
				/* example: mov rax, rcx */
				/* modrm: 
					mod field = 11
					reg field = REX_R + XXX
					r/m field = REX_B + XXX
				*/
				if (is_eGPR(so_key->reg))
					rex |= REX_R;

				if (is_eGPR(do_key->reg))
				 	rex |= REX_B;
				break;

			case D_R|S_M:
			case D_M|S_R:
				if (is_eGPR(so_key->reg) 
						|| is_eGPR(do_key->reg))
					rex |= REX_R;

				if (addr_size != 64) {
					/* example: mov rax, [ecx] */
					/* the ops_size is 64-bit, but
					   the addr_size is 32-bit.
					   so not set to REX_B */
					break;
				}

				/* example: mov rax, [rcx*8+rbx+0xc] */
				/* REX_B: set for base reg */
				/* REX_X: set for index reg */
				if (is_eGPR(mem->base))
					rex |= REX_B;

				if (is_eGPR(mem->index))
					rex |= REX_X;

				break;	

			case D_R|S_I: 	/* dest is reg and source is imme */
				/* example: mov rax, 0x0c */
				/* register id in reg field of opcode byte 
				   so, REX_R & REX_X are not used */

				/* is GROUP set REX_B too !!! 
				   example: mov ecx,0x00000001 
				   if the opcode code is 0xC7/0...
				   it's a GROUP, so set REX_B 
				*/
				if (is_eGPR(do_key->reg))
					rex |= REX_B;
				break;
			case D_M|S_I:
				/* ops_size is 64-bit,but addr_size 
				   isn't 64-bit, so skip set REX */
				if (addr_size != 64) 
					break;
				
				/* example: mov [rax+rcx], 0x0c 
				   it's GROUP */
				/* set REX_B for base reg */
				/* set REX_X for index reg */	
				if (is_eGPR(mem->base))
					rex |= REX_B;

				if (is_eGPR(mem->index))
					rex |= REX_X;
				
				break;

			default: break;	
				/***********************************
   				 * TODO: reserved for three operands
 				 ***********************************/
			}
			

			e_buf[offset++] = rex;
		}


	}	/*** prefix bytes ****/



	/* opcode bytes */
	if (u.code[1])		/* it's two bytes opcode */
		e_buf[offset++] = u.code[1];
	e_buf[offset++] = u.code[0];

	/****************** modrm byte *******************/

	/* example: inc eax
         * it has not modrm byte 
         */
	if (!is_NO_NEED_MODRM(i_attr)) {
		e_buf[offset++] = get_modrm(e_key, &is_sib, &set_disp);
	} else if (mem && !mem->base && !mem->index && mem->disp) {
		/* example: mov eax, [0x1122] */
		set_disp = (current_bits >> 3) - get_sizeof(mem->disp);
	}


	/* sib byte */
	if (is_sib) {
		e_buf[offset++] = get_sib(e_key, &set_disp);
	}


	/******** disp bytes *************/
	union {
		long long ll;
		char byte[8];
	} d;

	d.ll = mem ? mem->disp : 0;


	if (d.ll == 0) {
		/* do nothing */
	} else switch (get_sizeof(d.ll)) {
	case 1:
		e_buf[offset++] = d.byte[0];
		break;
	case 2:
		e_buf[offset++] = d.byte[0];
		e_buf[offset++] = d.byte[1];
		break;
	case 4:
		e_buf[offset++] = d.byte[0];
		e_buf[offset++] = d.byte[1];
		e_buf[offset++] = d.byte[2];
		e_buf[offset++] = d.byte[3];
		break;
	case 8:
		e_buf[offset++] = d.byte[0];
		e_buf[offset++] = d.byte[1];
		e_buf[offset++] = d.byte[2];
		e_buf[offset++] = d.byte[3];

		if (!is_SUPPORT_VALUE64(i_attr)) {
			fputs("warning: "
				"the instruction not support 64-bit value,",
				 stderr);
			break;	
		}

		e_buf[offset++] = d.byte[4];
		e_buf[offset++] = d.byte[5];
		e_buf[offset++] = d.byte[6];
		e_buf[offset++] = d.byte[7];
	}

	for (; set_disp; set_disp--)
		e_buf[offset++] = 0;


	/************* imme bytes ********************/

	d.ll = imme ? imme->imme_value : 0;
	int imme_size = imme && imme->cast ? imme->cast >> 3 : 
			d.ll ? get_sizeof(d.ll) : 0;
	

	if (OPTYPE(so_attr) == IMME_1) { 	/* example: shl eax,1 */
		/* do nothing */
	} else if (imme) {
		switch (imme_size) {
		case 0:	/* imme operand is 0 */
			if (imme->cast == 8) {
				e_buf[offset++] = d.byte[0];
				imme_size = 1;
			} else if (imme->cast == 16) {
				e_buf[offset++] = d.byte[0];
				e_buf[offset++] = d.byte[1];
				imme_size = 2;
			} else if (imme->cast == 32) {
				e_buf[offset++] = d.byte[0];	
				e_buf[offset++] = d.byte[1];
				e_buf[offset++] = d.byte[2];
				e_buf[offset++] = d.byte[3];
				imme_size = 4;
			} else if (imme->cast == 64) {
				e_buf[offset++] = d.byte[0];
				e_buf[offset++] = d.byte[1];
				e_buf[offset++] = d.byte[2];
				e_buf[offset++] = d.byte[3];

				if (!is_SUPPORT_VALUE64(i_attr))
					break;

				e_buf[offset++] = d.byte[4];
				e_buf[offset++] = d.byte[5];
				e_buf[offset++] = d.byte[6];
				e_buf[offset++] = d.byte[7];
				imme_size = 8;
			}
			break;
		case 1:
			e_buf[offset++] = d.byte[0];
			break;
		case 2:
			e_buf[offset++] = d.byte[0];
			e_buf[offset++] = d.byte[1];
			break;
		case 4:
			e_buf[offset++] = d.byte[0];
			e_buf[offset++] = d.byte[1];
			e_buf[offset++] = d.byte[2];
			e_buf[offset++] = d.byte[3];
			break;
		case 8:
			e_buf[offset++] = d.byte[0];
			e_buf[offset++] = d.byte[1];
			e_buf[offset++] = d.byte[2];
			e_buf[offset++] = d.byte[3];

			if (!is_SUPPORT_VALUE64(i_attr)) {
				fputs("warning: the instruction not support "
				    "64-bit value, the 64-bit value cut to "
					"32-bit value\n", stderr);
				break;
			}		
			e_buf[offset++] = d.byte[4];
			e_buf[offset++] = d.byte[5];
			e_buf[offset++] = d.byte[6];
			e_buf[offset++] = d.byte[7];
			break;
	
		}
	
		/* example: sub esp, 8 */
		/*
		if (((OPTYPE(so_attr) == IMME) || (OPTYPE(so_attr) == IMME_1))
				&& (SIZE(so_attr) == SIZE8)) {
			set_imme = 0;
		}*/ 
		
		/* example: "sub esp,8", "out 0x0c, eax" */
		if ((SIZE(so_attr) == SIZE8) || (SIZE(do_attr) == SIZE8))
			set_imme = 0;
		else
			set_imme = (ops_size >> 3) - imme_size;
		
		for (; set_imme; set_imme--)
			e_buf[offset++] = 0;

		if (u.code[0] == 0xc8) {	/* It's Enter instruction */
			/* example: enter 0x0c, 0x01 */
			d.ll = do_key->imme->imme_value;
			if (get_sizeof(d.ll) == 1) {
				e_buf[offset++] = 0;
				e_buf[offset++] = d.byte[0];
			} else if (get_sizeof(d.ll) == 2) {
				e_buf[offset++] = d.byte[0];
				e_buf[offset++] = d.byte[1];
			}
		}



	} /* end if(imme) */


	return errno;
}




/*********************************************************
 *
 * function: do_transfer_gen(struct iob *e_buf, int adj)
 * 
**********************************************************/
errno_t do_transfer_gen(struct iob *e_buf, int adj)
{
	errno_t errno = 0;
	unsigned long long label_addr = 0;
	unsigned long long label_offset = 0;
	unsigned long long hole_addr = 0;
	
	o_key_t so_key = { 0, 0, 0 }; 


	ops_key_t ops_key = { 0, 0, 0 };
	ops_attr_t  ops_attr = { 0, 0, 0 };
 	e_key_t e_key = { 0, 0, 0, 0, 0, 0, 0 };
	
	imme_t imme;

	so_key.imme = &imme;
	ops_key.so_key = &so_key;
	

	char encode[15];
	struct transfer_hole_struct *hole_node = hole_link;

	while (hole_node) {
		imme.imme_value = 0;
		imme.cast = 0;

		/* get label address via hole_node's label 
		   example: jmp @label. the mean is get @label's 
			address with get_label_addr()
		*/
		current_bits = hole_node->bits;
	
		struct label_link *label_node = 
			get_label_node(hole_node->hole_label);

		if (!label_node) {
			sprintf(err_msg, "at %d: %s\n", hole_node->hole_line, 
				"transfer label error");

			mount_err_link(0, 0, err_msg);

			return ERR_OPERAND;
		}
	

		hole_addr = hole_node->hole_addr;
		label_addr = label_node->label->addr;

		/*    reserved:
		   the label_offset = label_offset - HOLE_SIZE 
		
		*/
		label_offset = hole_addr >= label_addr ?
				hole_addr - label_addr : label_addr - hole_addr;


		/* the mean is byte or dword or qword ? */
		unsigned long long offset_size = get_sizeof(label_offset);
			
		if (offset_size == 0) {
			/* it's two bytes, jmp self !!!!
			   so, it's operand's encode is 0xfe !!!

			   example:  @label: jmp @label
			*/
		
			imme.cast = 8;
			ops_attr.so_attr = IMME | SIZE8;

		} else if (offset_size == 1) {
			/* the offset size is byte 
				   example: jmp 0xc */

			unsigned char c_off = label_addr - hole_addr;
			imme.imme_value = (long long)c_off;
			imme.cast = 8;
			ops_attr.so_attr = IMME | SIZE8;
				
		} else if ((offset_size == 8) && (current_bits == 64)) {

			/* the offset size is qword in 64-bit mode 
			   example: jmp 0x1122334455667788 */
			unsigned long long ll_off = label_addr - hole_addr;
			imme.imme_value = (long long)ll_off;
			imme.cast = 64;
			ops_attr.so_attr = IMME | SIZE64;

		} else if (offset_size == 2) {
			/* else all the offset size is dword 
			   example: jmp 0x08040010 */
			if (current_bits == 16) {
				unsigned short s_off = label_addr - hole_addr;
				imme.imme_value = (long long)s_off;
				imme.cast = 16;
				ops_attr.so_attr = IMME | SIZE16;
			} else {
				unsigned int i_off = label_addr - hole_addr;
				imme.imme_value = (long long)i_off;	
				imme.cast = 32;
				ops_attr.so_attr = IMME | SIZE32;
			}
		} else if ((offset_size == 4) && (current_bits == 32)) {
			unsigned int i_off = label_addr - hole_addr;
			imme.imme_value = (long long)i_off;
			imme.cast =  32;
			ops_attr.so_attr = IMME | SIZE32;

		} else {
			sprintf(err_msg, "at %d: %s",
					"transfer instruct label size error!");
			mount_err_link(0, 0, err_msg);
			
			return  ERR_OPERAND;
		}
			
		e_key.ops_key = &ops_key;
			
		/* the hole_i_key is "jmp" , "call" or "jz", so that */
		e_key.i_key = get_i_key(hole_node->hole_i_key, &ops_attr);

		if (!e_key.i_key) { 	/* no found */
			sprintf(err_msg, "error: invalid instruction "
						"or operand\n");
			mount_err_link(0, 0, err_msg);
			return ERR_INS;
		}

		

		if (e_key.i_key->i_attr & FS_IN_BITS) {
			if (current_bits == 16) {
				short w_off = label_addr - hole_addr;
				imme.imme_value = (long long)w_off; 

			} else if (current_bits == 32) {
				int i_off = label_addr - hole_addr;

				imme.imme_value = (long long)i_off;
				
			} else if (current_bits == 64) {
				long long ll_off = label_addr - hole_addr;
				imme.imme_value = (long long)ll_off;
			}

			imme.cast = current_bits;
		}
			

		if (adj == 1) {
			/* frist adjust offset size of between label and hole */

			if (label_addr <= hole_addr)
				imme.imme_value -= hole_node->hole_size;

		} else {
			/* again adjust offset size of between label and hole */

			/* **** do not adjust offset size ******

			the this case: the adj value is 0 !!!! */


			imme.imme_value -= hole_node->hole_size;
		}


		do_generate(encode, &e_key);
		
		int adj_size = hole_node->hole_size - offset;
		
		if (adj && adj_size) {

			/**** adjust label link *****/
			struct label_link* head_ll = label_table;
			for (; head_ll; head_ll = head_ll->next)
				if (head_ll->label->addr > hole_addr)
					head_ll->label->addr -= adj_size;

		
			/*****  adjust hole link *****/
			struct transfer_hole_struct *hole_next =
						hole_node->next;

			for (; hole_next; hole_next = hole_next->next)
				hole_next->hole_addr -= adj_size;


			mem_copy(&e_buf->buf[hole_addr + offset],
				&e_buf->buf[hole_addr + hole_node->hole_size], 
				current_pc - hole_addr - hole_node->hole_size);

			current_pc -= adj_size;
			
			hole_node->hole_size = offset;
		}
		

		if (!adj)
			mem_copy(&e_buf->buf[hole_addr], encode, offset);


		hole_node = hole_node->next;
	}


	return errno;
}


/********************************************
* do_imul_gen(char *e_buf, e_key_t *e_key)
*********************************************/
errno_t do_imul_gen(char *e_buf, e_key_t *e_key)
{
	errno_t errno = 0;
	
	if (!e_buf || !e_key)	
		return ERR_INS;
	

	return errno;
}




/**********************************************************
 function generate(char *e_buf, e_key_t *e_key)
 parameter: 
  	    e_buf: this is encodes memory buffer.
            e_key: this is instruction encode key word link.
 return: 
            0 if successed.
            errno if failed.
**********************************************************/

errno_t generate(struct iob *e_buffer) 
{
	errno_t errno = 0;
	int i = 0;
	
	e_key_t *e_key = e_key_link;


	if (!e_buffer)
		return ERR_ERROR;

	unsigned char encode[15];
	
	e_key_t *head_e_key = e_key;
	struct transfer_hole_struct *head_hl = hole_link;	
	struct label_link *head_ll = label_table;

	int begin_line = 0;
	int end_line = 0;

	
	if (e_key) {
		if (head_hl) 
			begin_line = e_key->line <= head_hl->hole_line ?
				e_key->line : head_hl->hole_line;
		else 
			begin_line = e_key->line;
	
		if (head_ll)
			begin_line = begin_line <= head_ll->label->line ?
				begin_line : head_ll->label->line;		

		end_line = line;
	}


	if (!e_key) { /* only hole_link or have nothing */
		/* do nothing */
	} else for (i = begin_line; i <= end_line; i++) {

		unsigned long long prev_pc = current_pc;

		/* get label's address */
		if (head_ll && i == head_ll->label->line) {
			head_ll->label->addr = current_pc;
			head_ll = head_ll->next;
		}

		/* get hole_link's address */
		if (head_hl && (i == head_hl->hole_line)) {
			current_bits = head_hl->bits;

			head_hl->hole_addr = current_pc;
			if (current_bits == 16) {
				head_hl->hole_size = 4;
			} else if (current_bits == 32) {
				head_hl->hole_size = 6;
			} else if (current_bits == 64) {
				head_hl->hole_size = 10;
			}
			current_pc += head_hl->hole_size;

			head_hl = head_hl->next;
			
		} else if (e_key && (i == e_key->line)) {
			current_bits = e_key->bits;

			errno = do_generate(encode, e_key);
			
			current_pc += offset;
			e_key->current_pc = current_pc;
			e_key->length = offset - 1;

			e_key = e_key->next;
			
		}

		unsigned long e_len = current_pc - prev_pc;

		if (get_free_bytes(e_buffer) < e_len) 
			flush_all_iob(e_buffer);

		write_into_iob(e_buffer, encode, e_len);
				
	}

	if (hole_link) {
		/* follow step adjust for all hole_struct and label_link */
		errno = do_transfer_gen(e_buffer, 1);

		if (!errno) {
			/* finally adjust for all transfer instructions 
			   get right encode !!!! 
			*/
			errno = do_transfer_gen(e_buffer, 2);
		}
		if (!errno)
			errno = do_transfer_gen(e_buffer, 0);
	}

	e_buffer->cnt = current_pc;
	e_buffer->tail_ptr = e_buffer->buf + current_pc;
	
	
	return errno;
}