Logo Passei Direto
Buscar

Trabalho 2 - Gerador de Funcoes Generico

User badge image

Enviado por Marcello Lins em

Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original

cria_func.c
/* Luis Marcelo Fonseca - 0911762 - 3WB */
/* Marcello Lins - 0910675 - 3WB */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "definitions.h"
//Definicoes de Constantes
#define PUSH_EBP 0x55
#define MOVL 0x89
#define RET 0xc3
#define CALL 0xe8
// Vetores Estaticos
static unsigned char inicioDeFuncao[] = {PUSH_EBP,0x89,0xe5};
static unsigned char fimDeFuncao[] = {0x89,0xec,0x5d,RET};
static unsigned char callNaoConfigurado[] = {CALL,0xfc,0xff,0xff,0xff};
/*********************************************************
* Funcao Libera Malloc
*********************************************************/
void libera_func(void * func) {
	free(func);
}
/*********************************************************
* Funcao Principal
*********************************************************/
void* cria_func (void* f, int n, Parametro params[]) {
	// Variáveis
	int indexaInstrucoes = 0; 
	int contador = 0; 
	int endFuncao;
	int endProximaInstrucao;
	int indiceProximaInstrucao;
	int indiceDepoisDoCall;
	int endCall;
	unsigned char offset = 8;
	unsigned char* pointer;
	unsigned char * codigo = (unsigned char*) malloc(sizeof(unsigned char) * 255); // Tamanho maximo do vetor = 255
/************************
* Inicio do Código *
*************************/
	// Adiciona instrucoes Iniciais no vetor de Instrucoes
	for(contador = 0 ; contador < 3 ; contador ++ , indexaInstrucoes++)
	{
		codigo[contador] = inicioDeFuncao[contador];
	} 
	// Para ler os parametros de tras para frente
	for (contador = 0; contador < n ; contador++)
	{
		if (params[contador].e_constante == 0) {
			if (params[contador].tipo == DOUBLE_PAR)
				offset += 8;
			else
				offset += 4;
		}
			
	}
		
	// Loop Principal, empilha os parametros de tras pra frente
	for (contador = n - 1; contador >= 0; contador--) 
	{	
		// Se o parametro for Fixo
		if (params[contador].e_constante) 
		{
			codigo[indexaInstrucoes] = 0xb9; // mov $const, %ecx
			if (params[contador].tipo == INT_PAR)
			{
			
				pointer = (unsigned char*) &params[contador].valor.v_int;
				codigo[indexaInstrucoes + 1] = *(pointer);
				codigo[indexaInstrucoes + 2] = *(pointer + 1); /* Armazenando o int */
				codigo[indexaInstrucoes + 3] = *(pointer + 2);
				codigo[indexaInstrucoes + 4] = *(pointer + 3);
				indexaInstrucoes += 5;
			} /* Primeiro If Interno */ 
			else 
				if (params[contador].tipo == CHAR_PAR) 
				{
				
					pointer = (unsigned char*)&params[contador].valor.v_char;
					codigo[indexaInstrucoes + 1] = *(pointer); // Armazenando o char 
					codigo[indexaInstrucoes + 2] = 0;
					codigo[indexaInstrucoes + 3] = 0; // Zeramos os paddings
					codigo[indexaInstrucoes + 4] = 0;
					indexaInstrucoes += 5;
				} /* Segundo If Interno*/
			else
				if (params[contador].tipo == PTR_PAR) 
				{
				
					pointer = (unsigned char*)&params[contador].valor.v_ptr;
					codigo[indexaInstrucoes + 1] = *(pointer);
					codigo[indexaInstrucoes + 2] = *(pointer + 1); /* Armazenando o ponteiro */
					codigo[indexaInstrucoes + 3] = *(pointer + 2);
					codigo[indexaInstrucoes + 4] = *(pointer + 3);
					indexaInstrucoes += 5;
				} /* Terceiro If Interno*/
			else
				if (params[contador].tipo == DOUBLE_PAR) 
				{
					pointer = (unsigned char*)&params[contador].valor.v_double;
					
					codigo[indexaInstrucoes + 1] = *(pointer + 4);
					codigo[indexaInstrucoes + 2] = *(pointer + 5); /* Armazenando o double */
					codigo[indexaInstrucoes + 3] = *(pointer + 6);
					codigo[indexaInstrucoes + 4] = *(pointer + 7); /* Salva em ordem de dois ints inversos */
					codigo[indexaInstrucoes + 5] = 0x51; // Push %ecx
					codigo[indexaInstrucoes + 6] = 0xb9; // Mov $const, %ecx
					codigo[indexaInstrucoes + 7] = *(pointer + 0); /* mov $constant, %ecx */
					codigo[indexaInstrucoes + 8] = *(pointer + 1);
					codigo[indexaInstrucoes + 9] = *(pointer + 2); /* Precisa dar dois push */
					codigo[indexaInstrucoes + 10] = *(pointer + 3);
					indexaInstrucoes += 11;
				} /* Quarto If Interno*/
			else 
				printf("Erro - Tipo indefinido\n");
				
			codigo [indexaInstrucoes] = 0x51; // Push %ecx
			indexaInstrucoes++;
		} /* If Externo */
		else // Se Parametro Não For Fixo
		{
			if(params[contador].tipo == INT_PAR)
			{
			
				offset -= 4;
				codigo[indexaInstrucoes + 0] = 0x8b; // mov offset(%ebp), %ecx 
				codigo[indexaInstrucoes + 1] = 0x4d;
				codigo[indexaInstrucoes + 2] = offset;
				
				
				indexaInstrucoes += 3;
			} /* Primeiro If Interno*/
			else
				if(params[contador].tipo == CHAR_PAR)
				{
				
					offset -= 4;
					codigo[indexaInstrucoes + 0] = 0x31; // xor %ecx, %ecx
					codigo[indexaInstrucoes + 1] = 0xc9; // Precisa zerar o parametro, mas está errado
					codigo[indexaInstrucoes + 2] = 0x8b; // mov offset(%ebp), %ecx 
					codigo[indexaInstrucoes + 3] = 0x4d;
					codigo[indexaInstrucoes + 4] = offset;
					
					
					
					indexaInstrucoes += 5;
				} /* Segundo If Interno*/
			else
				if(params[contador].tipo == PTR_PAR)
				{
				
					offset -= 4;
					codigo[indexaInstrucoes + 0] = 0x8b; // mov offset(%ebp), %ecx 
					codigo[indexaInstrucoes + 1] = 0x4d;
					codigo[indexaInstrucoes + 2] = offset;
					
					
					
					indexaInstrucoes += 3;
				} /* Terceiro If Interno*/
			else
				if(params[contador].tipo == DOUBLE_PAR)
				{
					
					// Primeira parte do double
					offset -= 4;
					codigo[indexaInstrucoes + 0] = 0x8b; // mov offset(%ebp), %ecx 
					codigo[indexaInstrucoes + 1] = 0x4d;
					codigo[indexaInstrucoes + 2] = offset; // Precisa ser ao contrario!
					codigo[indexaInstrucoes + 3] = 0x51; // Push %ecx
					
					offset -= 4; // 
					// Segunda parte do double
					codigo[indexaInstrucoes + 4] = 0x8b; // mov offset(%ebp), %ecx 
					codigo[indexaInstrucoes + 5] = 0x4d;
					codigo[indexaInstrucoes + 6] = offset; // Precisa ser ao contrario!				
					indexaInstrucoes += 7;
				} /* Quarto If Inferno*/
			codigo[indexaInstrucoes] = 0x51;
			indexaInstrucoes++;
		} /* Else Externo*/
	} /* Loop Principal */
	 // Configurando o Endereço do Call
		for(contador = 0 ; contador < 5 ; contador++,indexaInstrucoes++)
		{
			codigo[indexaInstrucoes] = callNaoConfigurado[contador];
		}
		// Desempilhando, Tirando o EBP da Pilha e RETORNO
		for(contador = 0 ; contador < 4 ; contador++,indexaInstrucoes++)
		{
			codigo[indexaInstrucoes] = fimDeFuncao[contador];
		}
		//Procurando indice da próxima instrucao depois do CALL
		contador=0;
		while(codigo[contador]!= CALL)
		{
			contador++;
		}
		indiceProximaInstrucao = contador+5;
		indiceDepoisDoCall = contador + 1;
		//printf("\n****************************************");
		//printf("\nIndice da Instrucao depois do Call : %d",indiceProximaInstrucao);
		// Arrumando o Call
		endFuncao = (int)f;
		endProximaInstrucao = (int)&codigo[indiceProximaInstrucao];
		endCall = endFuncao - endProximaInstrucao;
		//printf("\nEndereco da Funcao : %x",endFuncao);
		//printf("\nEndereco da Proxima Instrucao : %x",endProximaInstrucao);
		//printf("\nEndereco do Call (offset) : %x",endCall);
		//printf("\n****************************************\n");
		*((int*) &codigo[indiceDepoisDoCall]) = endCall; // Casting do Endereco da proxima instrucao,para int* recebendo o endereco certo
	
	// Testando o Vetor de Instrucoes
	//traduzAssembly(codigo,indexaInstrucoes);
	imprimeInstrucoes(codigo,indexaInstrucoes);
	// Comentei as funções acima para que ficasse menos sobrecarregado
	// e para facilitar a leitura da saida do programa
	return codigo;
}
/*************************************************
* Faz o parsing do Conteúdo do Vetor de Codigo
* Traduzindo Código de máquina para a Assembly 
* em Nossa Lingua Natal Tupiniquim :)
*************************************************/
void traduzAssembly(unsigned
char* codigo,int tamanho)
{
	int contador = 0 ;
	for( ; contador < tamanho ; contador ++)
	{
		switch(codigo[contador])
		{
			case PUSH_EBP:
				printf("\nPUSH EBP");
			break;
			case MOVL:
				if(codigo[contador+1] == 0xe5)	
				{
					printf("\nMOVL ESP,EBP");
					contador++;
				}
				else
					if(codigo[contador+1] == 0xec)
					{
					printf("\nMOVL EBP,ESP");
					contador++;
					}
					else
						printf("\nMOVL ");
			break;
			case CALL:
				contador++;
				printf("\nCALL %x %x %x %x",codigo[contador],codigo[contador+1],codigo[contador+2],codigo[contador+3]);
				contador = contador + 3;
			break;
			case RET:
				printf("\nRET");
			break;
			case 0xb9:
				printf("\nMOVL UMA CONSTANTE");
			break;
			case 0x51:
				printf("\nPUSH ECX");
			break;
			default:
				printf("\n Instrucao Sem Tratamento : %x",codigo[contador]);
		 break;
		} /* switch*/
	} /* for */
	printf("\n\n==== Fim da Funcao de Traducao ====\n\n");
}
/*************************************************
* Imprime o código de máquina de cada instrucao
* com um índice antes(que é o indice no vetor de 
* codigo). Ajuda a conferir a implementacao
*************************************************/
void imprimeInstrucoes(unsigned char* codigo,int tam)
{
	int contador = 0 ;
	printf("\n**********************************************\n");
	while(contador<tam)
	{
		printf("\n%d - %x",contador,codigo[contador]);
		contador++;
	}
	return ;
}
relatorio.txt
/* Luis Marcelo Fonseca - 0911762 - 3WB */
/* Marcello Lins - 0910675 - 3WB */
Para a realização dos testes foram utilizadas funções como as que seguem :
double myAdd(double b, int c, char d)
{
	return b + (c * 2) + d;
}
// b = variavel, c = variavel, d = constante
// ---------------------------------------------------------- //
double myAdd(double b, double d)
{
	return b + d;
}
// b = variavel, d = constante
// ---------------------------------------------------------- //
int myAdd(int a, int b)
{
	return a * b;
}
// a = variavel, b = variavel
// ---------------------------------------------------------- //
int myAdd(char a, int b, char d)
{
	return a * b * d;
}
// a = constante, b = variavel, d = constante
// ---------------------------------------------------------- //
int * myAdd(int * a, int b)
{
	a = &b;
	return a;
}
// a = variavel, b = constante
// ---------------------------------------------------------- //
double myAdd(double b, int c, char d, double o, double p, int u, char t, int x)
{
	return b + c + d + o + p + u + t + x;
}
// b = variavel, c = variavel, d = variavel, t = variavel, resto constante.
// ---------------------------------------------------------- //
Observamos que os resultados foram satisfatorios, tendo em vista que todas elas funcionaram
e não observamos nenhum erro presente em outras funções testadas não listadas aqui.
Aprendemos as regras de empilhamento da pilha de execução, tendo sempre em mente que os parâmetros
devem ser empilhados de trás para frente para que a leitura seja possível.
Aprendemos também como funciona um call dinâmico, tendo que subtrair o endereço da função do endereço
da próxima instrução para obter o endereço do call.
Obs. Existem algumas funçoes que usamos para printar instruções na tela para ajudar com a criação
do programa. elas foram comentadas para que não fique muito complicado de ler.

Teste o Premium para desbloquear

Aproveite todos os benefícios por 3 dias sem pagar! 😉
Já tem cadastro?