Traduza a função abaixo para assembler:
int foo (int x) { return x+1; }
Use gcc -c foo.s
para traduzir
seu programa para linguagem de máquina (o gcc
vai gerar um arquivo foo.o
).
Veja qual o código de máquina que seu programa gera,
usando ou objdump -d foo.o
ou a opção -Wa,-al
do gcc
.
Escreva agora um programa em C como descrito a seguir.
Esse programa deve criar um
array de bytes (unsigned char
)
preenchido com o código de máquina visto no item anterior.
A seguir, ele deve converter o endereço do array para um
endereço de função.
Para isso, declare o tipo
ponteiro para função recebendo
int
e retornando int
,
conforme abaixo:
typedef int (*funcp) (int x);A seguir, atribua o endereço do array a uma variável do tipo acima:
funcp f = (funcp)a;Agora, você pode chamar
f
como se fosse uma função C normal, por exemplo:
i = (*f)(10);Faça isso no seu programa. Pode ser necessário compilar seu programa com
gcc -Wall -Wa,--execstack seuprograma.c
para permitir a
execução do seu código de máquina.
Execute o programa resultante.
Dica: a função dump
pode ser útil para você "inspecionar" o
código gerado...
Declare no seu programa a função:
int add (int x) { return x+1; }Agora modifique o programa para ele criar no array o equivalente à função abaixo:
int foo (int x) { return add(x); }
Observe o código de máquina da nova função foo
com gcc -c -Wa,-al foo.s
Observe que o código gerado contém a instrução de chamada:
e8 fc ff ff ffNessa instrução, o byte
e8
representa o código
de call, e os quatro bytes seguintes, o deslocamento (em número de bytes)
da função chamada em relação à instrução seguinte ao call (em little endian!).
Esse deslocamento pode ser negativo ou positivo!
O deslocamento NÃO está correto no arquivo .o.
Calcule qual deve ser o deslocamento para a chamada de foo
a add
e complete o código corretamente.