Traduza a função abaixo para assembler:
int foo (int x) { return x+1; }
Use gcc -c prog.s
para traduzir
seu programa para linguagem de máquina (o gcc
vai gerar um arquivo prog.o
).
Veja qual o código de máquina que seu programa gera,
usando ou objdump -d prog.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.
Faça isso no seu programa.
Será necessário compilar seu programa com
gcc -Wall -Wa,--execstack seuprograma.c
.
Execute o programa resultante.
Modifique o programa anterior para ele criar no array o equivalente às duas funções abaixo:
int bar (int x) { return x+2; } int foo (int x) { return bar(x)+1; }
(Se quiser, gere o código de máquina diretamente a partir de C,
com gcc -c -O0 prog.c
.)
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
da função chamada em relação à instrução seguinte (em little endian!).
Esse deslocamento NÃO está correto no arquivo .o.
Calcule qual deve ser o deslocamento para a chamada de foo
a bar
e complete o código corretamente.
Seu programa C deve chamar a função foo
.
No entanto, ela não está no início do array de código a
.
Vamos fazer isso de duas maneiras:
foo
. Execute o programa.
jmp
para a posição onde começa foo
.
O código do jmp é e9
seguido de 4 bytes com
o deslocamento do endereço desejado em relação ao endereço da
próxima isntrução.
Volte a atribuir a seu ponteiro de função o ponteiro para o início
do código, como antes. Execute o programa.