Traduza a função abaixo para assembler, criando um arquivo foo.s
:
int foo (int x) { return x+1; }
Use gcc -m32 -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 o comando objdump -d foo.o
(a opção -d do objdump
faz um "disassembly" do arquivo objeto).
Você pode também usar a opção -Wa,-al
do gcc
para listar o código de máquina gerado.
Escreva agora um programa em C como descrito a seguir.
Esse programa deve criar um
array de bytes (unsigned char codigo[]
)
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)codigo;Agora, você pode chamar
f
como se fosse uma função C, fazendo, por exemplo:
i = (*f)(10);Faça isso no seu programa. Deve ser necessário compilar seu programa com
gcc -m32 -Wall -Wa,--execstack -o seuprograma seuprograma.c
para permitir a execução do seu código de máquina. Execute o programa resultante.
Traduza agora a função abaixo para assembler,
int foo (int x) { return add(x); }
foo
com
gcc -c -Wa,-al
ou objdump -d
.
Note que o código gerado contém a instrução
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, dependendo do endereço da
função chamada ser "menor" ou "maior" que o da instrução seguinte ao call.
Note que o deslocamento NÃO está correto no arquivo .o, pois o endereço da função chamada somente será conhecido no passo de linkedição.
Declare agora no seu arquivo C a função:
int add (int x) { return x+1; }e modifique o programa para ele criar no array o equivalente à função abaixo (para fazer isso, novamente escreva o assembly equivalente em
foo.s
e execute objdump -d
).
int foo (int x) { return add(x); }Como você pode obter o endereço de
add
, você pode modificar seu
programa C para calcular qual deve
ser o deslocamento para a chamada de foo
a add
e completar o código gerado para o call corretamente.