Enunciado T2 Entrega: 14/06 (até 23:59) create_func: gera, em tempo de execução, uma nova função a partir de outra função qualquer f (a original) DynCall create_func(void* f, const char* signature) Onde: f = ponteiro para uma função já existente signature = descrição da assinatura de f (tipo de parâmetros e valor de retorno), Create_func retorna um ponteiro para a função gerada dinamicamente, de tipo DynCall Typedef void (*DynCall) (Any* params) A função gerada por create_func • Recebe como parâmetro um vetor p (tipo Any) com os argumentos a serem passados à f. typedef union { int i; char c; double d; float f; void* p; } Any; • Elemento p[0] fica reservado para o valor de retorno de f (mesmo que f não retorne valor) • Os argumentos da chamada a f: de p[1] em diante Exemplo de assinaturas Função original float f (int a, int b) String signature “ii>f” void g (int a, double b) “id” double h (int n, double* v) “ip>d” Cada tipo de parâmetro é indicado por um caracter: (int, char, double, float, pointer) Tipo do valor de retorno precedido do caracter ‘>’ Exemplo: double pow(double x,double y) ≡ xy • create_func (pow,”dd>d”) deve gerar código de máquina que equivale ao procedimento: void df (Any* v) { v[0].d = pow(v[1].d, v[2].d); } • Implemente também uma free_func (DynCall f) com código para liberar o espaço ocupado pela função criada dinamicamente • O protótipo de create_func e free_func (& definição de Any) estão em dyncall.h (seu trabalho deverá ser o dyncall.c) 1 Exemplo: double pow(double x,double y) • Uso de create_func (pow,”dd>d”): #include <math.h> #include "dyncall.h" int main (void) { int i; Any params[3]; DynCall f = create_func(pow,"dd>d"); params[2].d = 2.0; /* todos os numeros elevados ao quadrado */ for (i = 0; i <= 10; i++) { params[1].d = i; f(params); printf("%.0f^%.0f =.0f\n",params[1].d,params[2].d,params[0].d); } free_func(f); return 0; } Create_func Deve gerar, em um uma área da memória, um trecho de código em linguagem de máquina que implementa a função criada dinamicamente Para isso, create func deve percorrer o vetor signature da função original e gerar código de máquina que: • Leia cada parâmetro do vetor params (respeitando os tipos) • Use push para empilhar estes parâmetros para chamada da função original (neste exemplo, pow) • Chame a função através de “call” • Use pop para desempilhar os argumentos da pilha • Armazene em p[0] o valor de retorno da função original (neste exemplo, pow) Para descobrir qual é o código de máquina equivalente ao assembly, leia o manual do Intel Pentium (vol 2), ou faça engenharia reversa usando: objdump –d objectfile Creat_func • Código de máquina deve ser escrito em vetor de bytes (alocado previamente) unsigned char[500] a; • Para converter end. do vetor para endereço de função, declare o tipo ponteiro para função (recebendo params e retornando void), conforme abaixo: typedef void (*funcp) (Any* params); • A seguir, atribua o endereço do array a uma variável do tipo acima: funcp f = (funcp) a; • Obs: Use gcc com a opção -Wa,--execstack 2