/* 
   Ralph Engel Piazza - 0610286  Professor Markus Endler
   Guilherme Polakovics Paiva - 0411477  Professor Renato Cerqueira 
*/

#include <stdlib.h>
#include "dyncall.h"
#include <stdio.h>
DynCall create_func (void* f, const char* signature)
{
   int i =0;                              /*contador*/
   int offset = 0;                        /*vetor de offset*/
   unsigned char* a;                      /* vetor com instrucoes */
   int z=0;                               /* contador do vetor de execução */
   int n=0;                               /* numero de entradas */
   int j=0;                               /* contador do offset */
   DynCall gerada;                        /* funcao a ser retornada */
   int flag = 0;                          /* nao ha saida */
   int ponteiro = 0;                      /* variavel temporaria para auxilio de passagem para a funcao original */   
   ponteiro = (int) f;  
   
   for (i = 0; signature[i] != '\0'; i++)
   {
      if (signature[i] == '>')
	  {
         flag = 1;
         break;
      }
      n++;  
   }
   
   a = (unsigned char*) malloc(5000 * sizeof(unsigned char));
   
   a[z]=0x55; z++;                                  /* push %ebp */
   a[z]=0x89; z++; a[z]=0xE5; z++;                  /* movl %esp, %ebp  */
   
   a[z]=0x8B; z++; a[z]=0x4D; z++; a[z]=0x08; z++;  /* movl 8(%ebp), %ecx */
   
   if(n > 0)
   {
	    for(i=n; i>0; i--)
		{
			if(signature[i-1] == 'd')
			{
				offset = 8*i + 4; 
				a[z]=0x8B; z++; a[z]=0x41; z++; a[z]=offset; z++;     /* movl offset(%ecx), %eax */
				a[z]=0x50; z++;                                       /* push %eax  */
				offset=8*i;
				a[z]=0x8B; z++; a[z]=0x41; z++; a[z]=offset; z++;     /* movl offset(%ecx), %eax */
				a[z]=0x50; z++;                                       /* push %eax  */
				j = j + 2;
			}
			else
			{
				offset=8*i;
				a[z]=0x8B; z++; a[z]=0x41; z++; a[z]=offset; z++;     /* movl offset(%ecx), %eax */
				a[z]=0x50; z++;                                       /* push %eax  */
				j++;
			} 
		}
   }
   
   a[z] = 0xB8; z++;		               /* movl $f %eax */    
   
   a[z] = ponteiro; z++;               /* passa endereco da funcao original */
   
   ponteiro = ponteiro >> 8;   
   a[z] = ponteiro; z++;
   
   ponteiro = ponteiro >> 8;   
   a[z] = ponteiro; z++;
   
   ponteiro = ponteiro >> 8;   
   a[z] = ponteiro; z++;

   a[z]=0xFF ; z++; a[z]=0xD0; z++;    /* call %eax */  
   
   for(i=0; i<j; i++)
   {
      a[z]=0x59; z++;                  /* pop %ecx - libera os parametros passados*/
   }

   a[z]=0x8B; z++; a[z]=0x4D; z++; a[z]=0x08; z++;  /* movl 8(%ebp), %ecx */
   
   if(flag == 1)
   {
      if( ((signature[n+1]) == 'c') || ((signature[n+1]) == 'i')  || ((signature[n+1]) == 'p'))
      {
         a[z]=0x89; z++; a[z]=0x01; z++;           /* mov eax, (%ecx) */
      }
   
      else
      {
         if( ((signature[n+1]) == 'f') )  
         {
            a[z]=0xD9; z++; a[z]=0x19; z++;        /* fstps (%ecx) */
         }
         
         if( ((signature[n+1]) == 'd') )
         {
            a[z]=0xDD; z++; a[z]=0x19; z++;         /* fstpl (%ecx) */
         }
      }
   }
      
   a[z]=0x89; z++; a[z]=0xEC; z++;                  /* movl %ebp, %esp */
   a[z]=0x5D; z++;                                  /* pop %ebp */
   a[z]=0xC3;                                       /* ret */
    
   gerada = (DynCall)a;
   return gerada;
}

void free_func (DynCall func)
{
   free(func);
}

/* Nosso trabalho funcionou em todos os testes aplicados,
   incluindo casos aonde a estrada e/ou saida eram void.
   Tratamos um string signature somente com saida como 
   tendo o formato `>x` onde x pode ser i,d,c,f ou p.*/ 






