-
Notifications
You must be signed in to change notification settings - Fork 1
/
geracod.c
333 lines (259 loc) · 9.34 KB
/
geracod.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/*Esse arquivo deve conter as funções geracod e liberacod (e funções auxiliares, se for
o caso).
Esse arquivo não deve conter a função main. */
/*FUNCAO GERACOD:
le um arquivo de entrada contendo o código fonte uma função na linguagem
SB, gere o código de máquina correspondente, e retorne o endereço
da região de memória que contém o código gerado (um bloco de memória
alocado dinamicamente). O arquivo de entrada terá no máximo
20 linhas, com um comando SB por linha.
O parâmetro f é o descritor de um arquivo texto, já aberto para leitura,
de onde deve ser lido o código fonte da função escrita em SB.
Implementacao:
deve alocar um bloco de memória onde armazenará o código gerado (lembre-se que as
instruções de máquina ocupam um número variável de bytes na memória!). O endereço
retornado por geracod será o endereço do início da memória alocada.
Para cada instrução SB imagine qual uma tradução possível para assembly. Além disso,
lembre-se que a tradução de uma função SB deve começar com o prólogo usual (preparação
do registro de ativação, incluindo o espaço para variáveis locais) e terminar com a
finalização padrão (liberação do registro de ativação antes do retorno da função).
O código gerado deverá seguir as convenções de C/Linux quanto à passagem de parâmetros
e valor de retorno. As variáveis locais deverão ser alocadas na pilha de execução.
Para ler e interpretar cada linha da linguagem SB, teste se a linha contém cada um dos
formatos possíveis.
Não é necessário fazer tratamento de erros no arquivo de entrada, você pode supor que o
código fonte SB desse arquivo sempre estará correto.
O código gerado por geracod deverá ser um código de máquina x86-64, e não um código
fonte assembly. Ou seja, você deverá descobrir o código de máquina que corresponde às
instruções de assembly que implementam a tradução das instruções da linguagem SB. Para
isso, você pode usar o programa objdump e, se necessário, uma documentação das
instruções da Intel.
Por exemplo, para descobrir o código gerado por movl %eax, %ecx, você pode criar um
arquivo meuteste.s contendo apenas essa instrução, traduzi-lo com o gcc (usando a opção
-c) para gerar um arquivo objeto meuteste.o para ver o código de máquina gerado.
Estratégia de Implementação:
Implemente sua solução passo a passo, testando cada passo implementado!
Por exemplo:
Compile um arquivo assembly contendo uma função bem simples (por exemplo, uma função
que retorne o valor do seu parâmetro) usando:
$ minhamaquina> gcc -c code.s
e depois veja o código de máquina gerado usando:
$ minhamaquina> objdump -d code.o
Construa uma versão inicial da função geracod, que aloque uma área de memória,
coloque lá esse código, bem conhecido, e retorne o endereço da área alocada.
Crie uma função main e teste esse primeiro passo.
Implemente e teste a tradução da função SB equivalente:
ret p1
Pense em que informações você precisa extrair para poder traduzir as instruções
(quais são os operandos, qual é a operação, onde armazenar o resultado da operação).
Continue sua implementação, implementando e testando uma instrução por vez.
Experimente usar constantes, parâmetros, variáveis locais, e combinações desses
tipos como operandos.
Lembre-se que é necessário alocar espaço (na pilha) para as variáveis locais!
Deixe para implementar a instrução de desvio apenas quando todo o resto estiver
funcionando!
Pense em que informações você precisa guardar para traduzir essas instruções
(note que você precisa saber qual o endereço da instrução correspondente à linha
para onde o controle deve ser desviado...)
*/
/*FUNCAO LIBERACOD:
responsável por liberar a memória
alocada para armazenamento do código
de máquina.
*/
/*************************** INICIO ***************************/
/* Heloisa Pessoa Matricula 3WA */ /*COMPLETA SEUS DADOS AQUI*/
/* Mariana Medeiros Ruddy Santos 1611397 3WA */
#include <string.h>
// #include <conio.h> /*funcao getch()*/
// system("gcc -c code.s");
// system("objdump -d code.o");
#include <stdio.h>
#include <stdlib.h>
#include "geracod.h"
#define codMaqRet 0xc3
#define codMaqGo
#define codMaqIf
funcp geracod(FILE *f){
unsigned char* array = malloc((10*20)*sizeof(char)); /*10: tamanho arbitrario 20: num max de linhas*/
int numLinha = 1, i = 0;
while(leSB (f, numLinha) != NULL){
array[i] = leSB (f, numLinha);
i++;
}
funcp endereco = (funcp)array;
return endereco;
}
/*********** lendo o arquivo em SB ***********/
void leSB (FILE *myfp){
char comando;
unsigned char* codMaq;
if (fscanf(f, "%c",&comando) = "\n"){
numLinha++;
}
else{
switch (fscanf(f, "%c",&comando)){
case 'ret':
codMaq = codMaqRet;
/*fscanf(f, " %c\n",&comando);*/ /*le o que retorna*/
case 'if':
codMaq = codMaqIf;
/*fscanf(f, " %c",&comando);*/ /*le oq vai ser comparado com 0*/
/*fscanf(f, " %c",&comando);*/ /*le linha do case se for menor que 0*/
/*fscanf(f, " %c\n",&comando);*/ /*le linha do case se for igual a 0*/
case 'go':
codMaq = codMaqGo;
/*fscanf(f, " %c\n",&comando);*/ /*le linha para onde vai pular*/
case 'v':
fscanf(f, "\n",&comando);
case 'p':
fscanf(f, "\n",&comando);
default:
printf("ERRO: COMANDO INVALIDO");
}
}
}
/*********** lendo o arquivo em SB com a funcao do prof ***********/
void leSB (FILE *myfp){
if (fscanf(myfp, "et %c%d", &var0, &idx0) != 2){
error("comando invalido", line);
}
else{
codMaq = codMaqRet; /*PODEMOS FAZER UMA FUNCAO add_no_array(codMaq) E CHAMAR AQUI*/
/*ACHO QUE FALTA COISA AQUI*/
}
}
case 'v':
/*FALTA FAZER*/
case 'p': { /* atribuição e op. aritmetica */
char var0 = c, var1, op;
int idx0, idx1;
if (fscanf(myfp, "%d %c= %c%d", &idx0, &op, &var1, &idx1) != 4){
error("comando invalido", line);
}
else{
codMaq = codMaqP; /*PODEMOS FAZER UMA FUNCAO add_no_array(codMaq) E CHAMAR AQUI*/
/*ACHO QUE FALTA COISA AQUI*/
}
}
case 'i': { /* desvio condicional */
char var0;
int idx0, n1, n2;
if (fscanf(myfp, "f %c%d %d %d", &var0, &idx0, &n1, &n2) != 4){
error("comando invalido", line);
}
else{
codMaq = codMaqIf; /*PODEMOS FAZER UMA FUNCAO add_no_array(codMaq) E CHAMAR AQUI*/
/*ACHO QUE FALTA COISA AQUI*/
}
}
case 'g': { /* desvio incondicional */
int n1;
if (fscanf(myfp, "o %d", &n1) != 1){
error("comando invalido", line);
}
else{
codMaq = codMaqIf; /*PODEMOS FAZER UMA FUNCAO add_no_array(codMaq) E CHAMAR AQUI*/
/*ACHO QUE FALTA COISA AQUI*/
}
default: error("comando desconhecido", line);
}
line ++;
fscanf(myfp, " ");
}
}
/*interpretacao do arquivo em SB do prof*/
/*
static void error (const char *msg, int line) {
fprintf(stderr, "erro %s na linha %d\n", msg, line);
exit(EXIT_FAILURE);
}
int main (void) {
int line = 1;
int c;
FILE *myfp;
if ((myfp = fopen ("programa", "r")) == NULL) {
perror ("nao conseguiu abrir arquivo!");
exit(1);
}
while ((c = fgetc(myfp)) != EOF) {
switch (c) {
case 'r': { /* retorno */
/* char var0;
int idx0;
if (fscanf(myfp, "et %c%d", &var0, &idx0) != 2)
error("comando invalido", line);
printf("%d ret %c%d\n", line, var0, idx0);
break;
}
case 'v':
case 'p': { /* atribuição e op. aritmetica */
/* char var0 = c, var1, op;
int idx0, idx1;
/* if (fscanf(myfp, "%d %c= %c%d", &idx0, &op, &var1, &idx1) != 4)
error("comando invalido", line);
printf("%d %c%d %c= %c%d\n", line, var0, idx0, op, var1, idx1);
break;
}
case 'i': { /* desvio condicional */
/* char var0;
int idx0, n1, n2;
if (fscanf(myfp, "f %c%d %d %d", &var0, &idx0, &n1, &n2) != 4)
error("comando invalido", line);
printf("%d if %c%d %d %d\n", line, var0, idx0, n1, n2);
break;
}
case 'g': { /* desvio incondicional */
/* int n1;
if (fscanf(myfp, "o %d", &n1) != 1)
error("comando invalido", line);
printf("%d go %d\n", line, n1);
break;
}
default: error("comando desconhecido", line);
}
line ++;
fscanf(myfp, " ");
}
return 0;
}
*/
funcp geracodtest (){
unsigned char* array = malloc(3*sizeof(char));
array[0] = 0x89;
array[1] = 0xf8;
array[2] = 0xc3;
funcp p = (funcp)array;
/*
0: 89 f8 mov %edi,%eax
2: c3 ret
*/
return p;
}
void liberacod(void *pf){
free(pf); /*??*/
}
int main (void){
funcp p = geracodtest();
printf("end = %d\n", p(900) );
return 0;
}
// int main(int argc, char *argv[]) {
// FILE *myfp;
// funcp funcaoSB;
// // int res;
// /* Abre o arquivo fonte */
// if ((myfp = fopen("programa", "r")) == NULL) {
// perror("Falha na abertura do arquivo fonte");
// exit(1);
// }
// /* compila a função SB */
// funcaoSB = geracod(myfp);
// fclose(myfp);
// /* chama a função */
// // res = (*funcaoSB) (/*....*/); /* passando parâmetro apropriados */
// // ...
// liberacod(funcaoSB);
// // ...
// return 0;
// }