Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

créer dynamiquement des blocs d'instructions exécutables

4 réponses
Avatar
gorgonite
Bonjour,



Je souhaite impl=E9menter la m=E9thode des "preparation sequences" sur une
machine virtuelle, et pour cela je dois cr=E9er des blocs d'instructions
puis les ex=E9cuter.


J'ai test=E9 ce code (compil=E9 avec gcc -O2), et je me prends un message
d'erreur

mmap: Cannot allocate memory


alors que si j'enl=E8ve ce qui concerne blockBis* =E7a a l'air de
fonctionner

pour informations, je suis sur une architecture x86 et un os gnu/linux


si quelqu'un voit ce que je dois corriger, merci par avance :-)

______________________________________

#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int testBlockExecute() {
size_t size =3D (&&block_end - &&block_begin) + (&&block2_end-
&&block2_begin);
size +=3D (&&blockBis_end - &&blockBis_begin);
unsigned char* buf =3D mmap(NULL, size, PROT_EXEC|PROT_READ|
PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (buf =3D=3D MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}

unsigned char* block =3D buf;
memcpy(buf, &&block_begin, &&block_end - &&block_begin);
buf +=3D &&block_end - &&block_begin;
memcpy(buf, &&blockBis_begin, &&blockBis_end -
&&blockBis_begin);
buf +=3D &&blockBis_end - &&blockBis_begin;
memcpy(buf, &&block2_begin, &&block2_end - &&block2_begin);
buf +=3D &&block2_end - &&block2_begin;

if (msync(block,size,MS_INVALIDATE) !=3D 0) {
perror("msync");
exit(EXIT_FAILURE);
}
int i=3D2;
unsigned char* done =3D &&block2_end;
fprintf(stderr,"d=E9but de l'ex=E9cution\n");
goto *block;

block_begin:
i *=3D 3;
block_end:
blockBis_begin:
i *=3D 5;
blockBis_end:
block2_begin: {
goto *done;
}
block2_end:
return i;
}

int main(int argc, char** argv) {
int i =3D testBlockExecute();
return 0;
}

4 réponses

Avatar
Pascal Bourguignon
gorgonite writes:
Je souhaite implémenter la méthode des "preparation sequences" sur une
machine virtuelle, et pour cela je dois créer des blocs d'instructions
puis les exécuter.


J'ai testé ce code (compilé avec gcc -O2), et je me prends un message
d'erreur

mmap: Cannot allocate memory


alors que si j'enlève ce qui concerne blockBis* ça a l'air de
fonctionner

pour informations, je suis sur une architecture x86 et un os gnu/linux


si quelqu'un voit ce que je dois corriger, merci par avance :-)


Ajoute:
printf("size=%un",size);
devant mmap.


[ tmp]$ gcc -O0 -o a0 a.c
[ tmp]$ ./a0
size5
d

Avatar
Charlie Gordon
"gorgonite" a écrit dans le message de news:


Bonjour,

Je souhaite implémenter la méthode des "preparation sequences" sur une
machine virtuelle, et pour cela je dois créer des blocs d'instructions
puis les exécuter.

J'ai testé ce code (compilé avec gcc -O2), et je me prends un message
d'erreur

mmap: Cannot allocate memory

alors que si j'enlève ce qui concerne blockBis* ça a l'air de
fonctionner

pour informations, je suis sur une architecture x86 et un os gnu/linux

si quelqu'un voit ce que je dois corriger, merci par avance :-)



Bonjour,

Ton problème est non trivial : synthétiser des blocs de code
exécutable par juxtaposition de fragments de code est extrêmement
aléatoire.

Dans le cas présent, je soupçonne gcc d'avoir réorganisé les séquences
d'instructions pour les différent "bouts" de code que tu veux extraire
: les labels ne sont alors plus dans un ordre strictement croissant et
en calculer la taille par différence d'adresses peut donner des
nombres négatifs, que mmap interprétera comme des nombres très gands,
proches de SIZE_MAX.

Tu peux vérifier si mon hypothèse est correcte en traçant ton
programme avec strace, donc sans modification de source (qui
conduirait à une génération de code différente)... les arguments de
mmap apparaitront dans la trace.

Pour approfondir ces questions, je te conseille les sources de QEMU de
Fabrice Bellard. C'est ce que tu pourras trouver de plus abouti en la
matière, mais attention, il faut d'accrocher pour suivre... débutants
s'abstenir !

Chqrlie.

http://www.qemu.org/

Avatar
gorgonite
Merci à tous pour vos réponses


On 10 juin, 17:57, "Charlie Gordon" wrote:
Pour approfondir ces questions, je te conseille les sources de QEMU de
Fabrice Bellard. C'est ce que tu pourras trouver de plus abouti en la
matière, mais attention, il faut d'accrocher pour suivre... débutants
s'abstenir !



Je n'ai pas encore eu le temps d'étudier ces sources... je suis en
train de "finir" mon analyse de openjdk, et je m'y mettrai ensuite ;-)


J'ai essayé de construire moi-même les blocs pour qu'ils ne les
déplace pas à l'optimisation... mais bien que rien ne plante, le
résultat renvoyé n'est pas correct
Je pense qu'il y a un problème avec l'initialisation du registre %eax
à i :?



____________________________________________________________
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char* end = NULL;

void containsBloc() {
__asm__ __volatile__ (
";n"
".block_begin: n"
"tmovl $4, %ebxn"
"taddl %ebx, %eax"
);
__asm__ __volatile__ (
"jmp *%0n"
".block_end: "
: : "m" (end)
);
}

int main(int argc, char** argv) {
int i=0;
unsigned char* beginBlock;
unsigned char* endBlock;
unsigned char *buf;
unsigned char *beginBuf;
size_t size;

end = &&end;
__asm__ __volatile__("movl $.block_begin, %
%eax" :"=a"(beginBlock) );
__asm__ __volatile__("movl $.block_end, %%eax" :"=a"(endBlock) );
size = endBlock - beginBlock;
buf = mmap(NULL, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|
MAP_ANONYMOUS, -1, 0);
if (buf == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
beginBuf = buf;
memcpy(buf, beginBlock, size);
buf += size;
if (msync(beginBuf, size, MS_INVALIDATE) != 0) {
perror("msync");
exit(EXIT_FAILURE);
}

__asm__ __volatile__ ("jmp *%0" : : "m" (beginBuf));

end:
printf("%dn",i);
return 0;
}

Avatar
gorgonite
j'ai enfin quelque chose qui semble fonctionner (avec toutes les
optimisations), et sans trop d'assembleur... :-)


mais il me reste un problème de taille... les performances ne sont pas
forcemment au rendez-vous :s

j'ai surtout comparé avec l'option -02 qui est celle couramment
utilisée ;-)

sur un processeur centrino 1.6Ghz, les temps d'exécution sont
'BASIC' 44s
'RICARDI' 22s
'BLOCK' 36s

ce qui est moins bon que prévu...
(passer deux mois pour faire une optimisation moins performante que
celle de base, c'est un peu déprimant :'( )

sur un processeur amd64 3200+, je suis plutôt content des performances
'BASIC' 36s
'RICARDI' 14,9s
'BLOCK' 14s

même si j'espérais gagner plus... :s


si quelqu'un pouvait m'éclairer à ce sujet, ça m'arrangerait :-D

-------------------------------------


// vim:set ts=4 sw=4 :

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <sys/types.h>
#include <signal.h>
#include <sys/mman.h>
#include <fcntl.h>

#define STACK_SIZE 255

typedef enum {
LOAD_0 = 0x00,
LOAD_1 = 0x01,
LOAD_N = 0x02,
ADD = 0x03,
SUB = 0x04,
MUL = 0x05,
DIV = 0x06,
NOT = 0x07,
DUP = 0x08,
DUP_2 = 0x09,
DUP_3 = 0x0a,
DUP2 = 0x0b,
POP = 0x0c,
IF = 0x0d,
GOTO = 0x0e,
END = 0x0f
} ByteCode;

const char* byteCodeName[1+END] = {
"LOAD_0",
"LOAD_1",
"LOAD_N",
"ADD",
"SUB",
"MUL",
"DIV",
"NOT",
"DUP",
"DUP_2",
"DUP_3",
"DUP2",
"POP",
"IF",
"GOTO",
"END"
};


/*** ***/
static int* sp;
static ByteCode* ip;
static int (*pputs)(const char*);
static int (*pfprintf)(FILE*,const char*,...);
/*** ***/

#ifdef BASIC_INTERPRET
void basicInterpret(const ByteCode* ip, int** sp_global) {
#ifdef DEBUG
puts("debut execution");
#endif
int* sp = *sp_global;
while (*ip != END) {
#ifdef DEBUG
fprintf(stderr,"%st%pn",byteCodeName[*ip],ip);
#endif
switch(*ip) {
case LOAD_0:
*sp = 0;
ip++;
break;
case LOAD_1:
*sp = 1;
ip++;
break;
case LOAD_N:
ip++;
*sp = *((int*) ip);
ip += 1 + sizeof(int);
#ifdef DEBUG
fprintf(stderr,"%dn",*sp);
#endif
break;
case ADD: {
int temp = *(sp--);
*sp += temp;
ip++;
break;
}
case SUB: {
int temp = *(sp--);
*sp -= temp;
ip++;
break;
}
case MUL: {
int temp = *(sp--);
*sp *= temp;
ip++;
break;
}
case DIV: {
int temp = *(sp--);
*sp /= temp;
ip++;
break;
}
case NOT: {
*sp = !(*sp);
ip++;
break;
}
case DUP: {
int temp = *sp++;
*sp = temp;
ip++;
break;
}
case DUP_2: {
int arg1 = *sp--;
int arg2 = *sp;
*sp++ = arg1;
*sp++ = arg2;
*sp = arg1;
ip++;
break;
}
case DUP_3: {
int arg1 = *sp--;
int arg2 = *sp--;
int arg3 = *sp;
*sp++ = arg1;
*sp++ = arg3;
*sp++ = arg2;
*sp = arg1;
ip++;
break;
}
case DUP2: {
int arg1 = *sp--;
int arg2 = *sp--;
int arg3 = *sp;
*sp++ = arg2;
*sp++ = arg1;
*sp++ = arg3;
*sp++ = arg2;
*sp = arg1;
ip++;
break;
}
case POP: {
sp--;
ip++;
break;
}
case IF: {
#ifdef DEBUG
fprintf(stderr,"%dn",*sp);
char _wait;
scanf("%c",&_wait);
#endif
if (*sp == 0) {
ByteCode* addr = *((ByteCode**) ip+1);
ip = addr;
} else {
ip += 1 + sizeof(ByteCode*);
}
#ifdef DEBUG
fprintf(stderr,"%pn",ip);
#endif
break;
}
case GOTO: {
ByteCode* addr = *((ByteCode**) ip+1);
ip = addr;
#ifdef DEBUG
fprintf(stderr,"%pn",ip);
#endif
break;
}
case END:
break;
}
}
#ifdef DEBUG
puts("fin de execution");
#endif
*sp_global = sp;
}
#endif

#ifdef RICARDI_INTERPRET
void ricardiInterpret(const ByteCode* ip, int** sp_global) {
int* sp = *sp_global;
const void* gotoAddr[1+END] = {&&load0, &&load1, &&loadN, &&add,
&&sub, &&mul, &&div, &&not, &&dup, &&dup_2, &&dup_3, &&dup2, &&pop,
&&_if, &&_goto, &&end};

// debut execution
#ifdef DEBUG
puts("debut execution");
#endif
goto *gotoAddr[*ip];

// constantes
load0:
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
*sp = 0;
ip++;
goto *gotoAddr[*ip];

load1:
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
*sp = 1;
ip++;
goto *gotoAddr[*ip];

loadN:
ip++;
*sp = *((int*) ip);
ip += 1 + sizeof(int);
#ifdef DEBUG
fprintf(stderr,"%dn",*sp);
#endif
goto *gotoAddr[*ip];


// arithmetic
add: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int temp = *(sp--);
*sp += temp;
ip++;
goto *gotoAddr[*ip];
}

sub: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int temp = *sp--;
*sp -= temp;
ip++;
goto *gotoAddr[*ip];
}

mul: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int temp = *sp--;
*sp *= temp;
ip++;
goto *gotoAddr[*ip];
}

div: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int temp = *sp--;
*sp /= temp;
ip++;
goto *gotoAddr[*ip];
}

// logic
not:
*sp = !(*sp);
ip++;
goto *gotoAddr[*ip];

// manipulation de pile
dup: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int temp = *sp++;
*sp = temp;
ip++;
goto *gotoAddr[*ip];
}

dup_2: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int arg1 = *sp--;
int arg2 = *sp;
*sp++ = arg1;
*sp++ = arg2;
*sp = arg1;
ip++;
goto *gotoAddr[*ip];
}

dup_3: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int arg1 = *sp--;
int arg2 = *sp--;
int arg3 = *sp;
*sp++ = arg1;
*sp++ = arg3;
*sp++ = arg2;
*sp = arg1;
ip++;
goto *gotoAddr[*ip];
}

dup2: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
int arg1 = *sp--;
int arg2 = *sp--;
int arg3 = *sp;
*sp++ = arg2;
*sp++ = arg1;
*sp++ = arg3;
*sp++ = arg2;
*sp = arg1;
ip++;
goto *gotoAddr[*ip];
}

pop: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
sp--;
ip++;
goto *gotoAddr[*ip];
}

// branchement
_if: {
#ifdef DEBUG
puts(byteCodeName[*ip]);
fprintf(stderr,"%dn",*sp);
char _wait;
scanf("%c",&_wait);
#endif
if (*sp == 0) {
ByteCode* addr = *((ByteCode**) ip+1);
ip = addr;
} else {
ip += 1 + sizeof(ByteCode*);
}
#ifdef DEBUG
fprintf(stderr,"%pn",ip);
#endif
goto *gotoAddr[*ip];
}

_goto: {
ByteCode* addr = *((ByteCode**) ip+1);
ip = addr;
#ifdef DEBUG
fprintf(stderr,"%pn",ip);
#endif
goto *gotoAddr[*ip];
}

end:
#ifdef DEBUG
puts(byteCodeName[*ip]);
#endif
*sp_global = sp;
return;
}
#endif


#ifdef BLOCK_INTERPRET
static void* gotoAddr[1+END];
static unsigned char *endOfInterpret = NULL;

void bloc_LOAD_0() {
__asm__ __volatile__ (
";n"
".load0_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[LOAD_0]);
#endif
*sp = 0;
ip++;
__asm__ __volatile__ (
";n"
".load0_end:"
);
goto *gotoAddr[*ip];
}

void bloc_LOAD_1() {
__asm__ __volatile__ (
";n"
".load1_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[LOAD_1]);
#endif
*sp = 1;
ip++;
__asm__ __volatile__ (
";n"
".load1_end:"
);
goto *gotoAddr[*ip];
}

void bloc_LOAD_N() {
__asm__ __volatile__ (
";n"
".loadN_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[LOAD_N]);
#endif
ip++;
*sp = *((int*) ip);
#ifdef DEBUG
pfprintf(stderr,"%dn",*sp);
#endif
ip += 1 + sizeof(int);
__asm__ __volatile__ (
";n"
".loadN_end:"
);
goto *gotoAddr[*ip];
}

void bloc_ADD() {
int temp;

__asm__ __volatile__ (
";n"
".add_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[ADD]);
#endif
temp = *(sp--);
*sp += temp;
ip++;
__asm__ __volatile__ (
";n"
".add_end:"
);
goto *gotoAddr[*ip];
}

void bloc_SUB() {
int temp;

__asm__ __volatile__ (
";n"
".sub_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[SUB]);
#endif
temp = *(sp--);
*sp -= temp;
ip++;
__asm__ __volatile__ (
";n"
".sub_end:"
);
goto *gotoAddr[*ip];
}

void bloc_MUL() {
int temp;

__asm__ __volatile__ (
";n"
".mul_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[MUL]);
#endif
temp = *(sp--);
*sp *= temp;
ip++;
__asm__ __volatile__ (
";n"
".mul_end: n"
);
goto *gotoAddr[*ip];
}

void bloc_NOT() {
__asm__ __volatile__ (
";n"
".not_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[NOT]);
#endif
*sp = !(*sp);
ip++;
__asm__ __volatile__ (
";n"
".not_end:"
);
goto *gotoAddr[*ip];
}

void bloc_DUP() {
int temp;

__asm__ __volatile__ (
";n"
".dup_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[DUP]);
#endif
temp = *sp++;
*sp = temp;
ip++;
__asm__ __volatile__ (
";n"
".dup_end:"
);
goto *gotoAddr[*ip];
}

void bloc_DUP_2() {
int arg1,arg2;

__asm__ __volatile__ (
";n"
".dup_2_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[DUP_2]);
#endif
arg1 = *sp--;
arg2 = *sp;
*sp++ = arg1;
*sp++ = arg2;
*sp = arg1;
ip++;
__asm__ __volatile__ (
";n"
".dup_2_end: "
);
goto *gotoAddr[*ip];
}

void bloc_DUP_3() {
int arg1,arg2,arg3;

__asm__ __volatile__ (
";n"
".dup_3_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[DUP_3]);
#endif
arg1 = *sp--;
arg2 = *sp--;
arg3 = *sp;
*sp++ = arg1;
*sp++ = arg3;
*sp++ = arg2;
*sp = arg1;
ip++;
__asm__ __volatile__ (
";n"
".dup_3_end: "
);
goto *gotoAddr[*ip];
}

void bloc_DUP2() {
int arg1,arg2,arg3;

__asm__ __volatile__ (
";n"
".dup2_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[DUP2]);
#endif
arg1 = *sp--;
arg2 = *sp--;
arg3 = *sp;
*sp++ = arg2;
*sp++ = arg1;
*sp++ = arg3;
*sp++ = arg2;
*sp = arg1;
ip++;
__asm__ __volatile__ (
";n"
".dup2_end: "
);
goto *gotoAddr[*ip];
}

void bloc_POP() {
__asm__ __volatile__ (
";n"
".pop_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[POP]);
#endif
sp--;
ip++;
__asm__ __volatile__ (
";n"
".pop_end: "
);
goto *gotoAddr[*ip];
}

void bloc_IF() {
ByteCode* addr;
unsigned char* bloc;

__asm__ __volatile__ (
";n"
".if_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[IF]);
pfprintf(stderr,"%dn",*sp);
#endif
if (*sp == 0) {
ip++;
addr = *((ByteCode**) ip);
ip += sizeof(ByteCode*);
bloc = *((unsigned char**) ip);
ip = addr;
if (bloc != NULL) {
__asm__ __volatile__ (
"jmp *%0"
: : "m"(bloc)
);
} else {
#ifdef DEBUG
pputs("not block for if");
#endif
goto *gotoAddr[*ip];
}
} else {
ip += 2 + sizeof(ByteCode*) + sizeof(unsigned char*);
}
#ifdef DEBUG
// pfprintf(stderr,"%pn",ip);
#endif
__asm__ __volatile__ (
";n"
"t.if_end: "
);
goto *gotoAddr[*ip];
}


void bloc_GOTO() {
ByteCode* gotoIp;
unsigned char* gotoBlock;

__asm__ __volatile__ (
";n"
".goto_begin: "
);
#ifdef DEBUG
// pfprintf(stderr,"%pt%xn%pn",ip,*ip,ip+1);
pputs(byteCodeName[GOTO]);
#endif
gotoIp = *((ByteCode**) ip+1);
#ifdef DEBUG
// pfprintf(stderr,"ip = %pt",gotoIp);
// pfprintf(stderr,"%dn",byteCodeName[(int) *gotoIp]);
#endif
ip += 1 + sizeof(ByteCode*);
gotoBlock = *((unsigned char**) ip);
ip = gotoIp;
#ifdef DEBUG
// pfprintf(stderr,"block = %pn",gotoBlock);
#endif
if (gotoBlock != NULL) {
__asm__ __volatile__ (
"jmp *%0"
: : "m"(gotoBlock)
);
} else {
#ifdef DEBUG
pputs("not block for goto");
#endif
goto *gotoAddr[*ip];
}
__asm__ __volatile__ (
";n"
"t.goto_end: "
);
}

void bloc_END() {
__asm__ __volatile__ (
";n"
".end_begin: "
);
#ifdef DEBUG
pputs(byteCodeName[END]);
#endif
__asm__ __volatile__ (
"jmp *%0n"
".end_end: "
: : "m"(endOfInterpret)
);
}

void blockInterpret(int n) {
unsigned char *begin[1+END], *end[1+END];
size_t blockSize[1+END], sizeOfBlock, sizeOfBlock2, sizeOfBlock3;
unsigned char *buf, *beginBuf, *buf2, *beginBuf2, *buf3, *beginBuf3;
ByteCode* init_ip = ip;
int i;

__asm__ ("movl $.endInterpret, %0" :"=m"(endOfInterpret) );
__asm__ ("movl $.load0_begin, %0" :"=m"(begin[LOAD_0]) );
__asm__ ("movl $.load0_end, %0" :"=m"(end[LOAD_0]) );
__asm__ ("movl $.load1_begin, %0" :"=m"(begin[LOAD_1]) );
__asm__ ("movl $.load1_end, %0" :"=m"(end[LOAD_1]) );
__asm__ ("movl $.loadN_begin, %0" :"=m"(begin[LOAD_N]) );
__asm__ ("movl $.loadN_end, %0" :"=m"(end[LOAD_N]) );
__asm__ ("movl $.add_begin, %0" :"=m"(begin[ADD]) );
__asm__ ("movl $.add_end, %0" :"=m"(end[ADD]) );
__asm__ ("movl $.sub_begin, %0" :"=m"(begin[SUB]) );
__asm__ ("movl $.sub_end, %0" :"=m"(end[SUB]) );
__asm__ ("movl $.mul_begin, %0" :"=m"(begin[MUL]) );
__asm__ ("movl $.mul_end, %0" :"=m"(end[MUL]) );
__asm__ ("movl $.not_begin, %0" :"=m"(begin[NOT]) );
__asm__ ("movl $.not_end, %0" :"=m"(end[NOT]) );
__asm__ ("movl $.dup_begin, %0" :"=m"(begin[DUP]) );
__asm__ ("movl $.dup_end, %0" :"=m"(end[DUP]) );
__asm__ ("movl $.dup_2_begin, %0" :"=m"(begin[DUP_2]) );
__asm__ ("movl $.dup_2_end, %0" :"=m"(end[DUP_2]) );
__asm__ ("movl $.dup_3_begin, %0" :"=m"(begin[DUP_3]) );
__asm__ ("movl $.dup_3_end, %0" :"=m"(end[DUP_3]) );
__asm__ ("movl $.dup2_begin, %0" :"=m"(begin[DUP2]) );
__asm__ ("movl $.dup2_end, %0" :"=m"(end[DUP2]) );
__asm__ ("movl $.pop_begin, %0" :"=m"(begin[POP]) );
__asm__ ("movl $.pop_end, %0" :"=m"(end[POP]) );
__asm__ ("movl $.goto_begin, %0" :"=m"(begin[GOTO]) );
__asm__ ("movl $.goto_end, %0" :"=m"(end[GOTO]) );
__asm__ ("movl $.if_begin, %0" :"=m"(begin[IF]) );
__asm__ ("movl $.if_end, %0" :"=m"(end[IF]) );
__asm__ ("movl $.end_begin, %0" :"=m"(begin[END]) );
__asm__ ("movl $.end_end, %0" :"=m"(end[END]) );

for(i=0 ; i<=END ; i++) {
gotoAddr[i] = begin[i];
}

blockSize[LOAD_0] = end[LOAD_0] - begin[LOAD_0];
blockSize[LOAD_1] = end[LOAD_1] - begin[LOAD_1];
blockSize[LOAD_N] = end[LOAD_N] - begin[LOAD_N];
blockSize[ADD] = end[ADD] - begin[ADD];
blockSize[SUB] = end[SUB] - begin[SUB];
blockSize[MUL] = end[MUL] - begin[MUL];
blockSize[NOT] = end[NOT] - begin[NOT];
blockSize[DUP] = end[DUP] - begin[DUP];
blockSize[DUP_2] = end[DUP_2] - begin[DUP_2];
blockSize[DUP_3] = end[DUP_3] - begin[DUP_3];
blockSize[DUP2] = end[DUP2] - begin[DUP2];
blockSize[POP] = end[POP] - begin[POP];
blockSize[IF] = end[IF] - begin[IF];
blockSize[GOTO] = end[GOTO] - begin[GOTO];
blockSize[END] = end[END] - begin[END];

sizeOfBlock = blockSize[LOAD_0] + 2*blockSize[DUP] +
blockSize[LOAD_1] + blockSize[LOAD_N] + blockSize[GOTO];
buf = mmap(NULL, sizeOfBlock, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (buf == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
beginBuf = buf;

sizeOfBlock2 = blockSize[IF] + blockSize[DUP] + blockSize[LOAD_1] +
blockSize[SUB] + 3*blockSize[POP] + blockSize[DUP_2] +
blockSize[DUP_3] + blockSize[DUP2] + blockSize[ADD] + blockSize[GOTO];
buf2 = mmap(NULL, sizeOfBlock2, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (buf2 == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
beginBuf2 = buf2;

sizeOfBlock3 = 2*blockSize[POP] + blockSize[END];
buf3 = mmap(NULL, sizeOfBlock2, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (buf3 == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
beginBuf3 = buf3;

memcpy(buf,begin[LOAD_0],blockSize[LOAD_0]); buf +=
blockSize[LOAD_0];
memcpy(buf,begin[DUP],blockSize[DUP]); buf += blockSize[DUP];
memcpy(buf,begin[LOAD_1],blockSize[LOAD_1]); buf +=
blockSize[LOAD_1];
memcpy(buf,begin[DUP],blockSize[DUP]); buf += blockSize[DUP];
memcpy(buf,begin[LOAD_N],blockSize[LOAD_N]); buf +=
blockSize[LOAD_N];
memcpy(buf,begin[GOTO],blockSize[GOTO]); buf += blockSize[GOTO];

memcpy(buf2,begin[IF],blockSize[IF]); buf2 += blockSize[IF];
memcpy(buf2,begin[DUP],blockSize[DUP]); buf2 += blockSize[DUP];
memcpy(buf2,begin[LOAD_1],blockSize[LOAD_1]); buf2 +=
blockSize[LOAD_1];
memcpy(buf2,begin[SUB],blockSize[SUB]); buf2 += blockSize[SUB];
memcpy(buf2,begin[DUP_3],blockSize[DUP_3]); buf2 += blockSize[DUP_3];
memcpy(buf2,begin[POP],blockSize[POP]); buf2 += blockSize[POP];
memcpy(buf2,begin[DUP_2],blockSize[DUP_2]); buf2 += blockSize[DUP_2];
memcpy(buf2,begin[ADD],blockSize[ADD]); buf2 += blockSize[ADD];
memcpy(buf2,begin[DUP2],blockSize[DUP2]); buf2 += blockSize[DUP2];
memcpy(buf2,begin[POP],blockSize[POP]); buf2 += blockSize[POP];
memcpy(buf2,begin[POP],blockSize[POP]); buf2 += blockSize[POP];
memcpy(buf2,begin[GOTO],blockSize[GOTO]); buf2 += blockSize[GOTO];

memcpy(buf3,begin[POP],blockSize[POP]); buf3 += blockSize[POP];
memcpy(buf3,begin[POP],blockSize[POP]); buf3 += blockSize[POP];
memcpy(buf3,begin[END],blockSize[END]); buf3 += blockSize[END];

*init_ip++ = LOAD_0;
*init_ip++ = DUP;
*init_ip++ = LOAD_1;
*init_ip++ = DUP;
*init_ip++ = LOAD_N;
*((int*) init_ip) = n;
init_ip += 1 + sizeof(int);
*init_ip++ = GOTO;
ByteCode** gotoDestination = (ByteCode**) init_ip;
init_ip += sizeof(ByteCode*);
*((unsigned char**) init_ip) = beginBuf2;
init_ip += 1 + sizeof(unsigned char*);
*gotoDestination = init_ip;

ByteCode* valGotoDestination2 = init_ip;
*init_ip++ = IF;
ByteCode** endOfIf = (ByteCode**) init_ip;
init_ip += sizeof(ByteCode*);
*((unsigned char**) init_ip) = beginBuf3;
// *((unsigned char**) init_ip) = NULL;
init_ip += 1 + sizeof(unsigned char*);
*init_ip++ = DUP;
*init_ip++ = LOAD_1;
*init_ip++ = SUB;
*init_ip++ = DUP_3;
*init_ip++ = POP;
*init_ip++ = DUP_2;
*init_ip++ = ADD;
*init_ip++ = DUP2;
*init_ip++ = POP;
*init_ip++ = POP;
*init_ip++ = GOTO;
ByteCode** gotoDestination2 = (ByteCode**) init_ip;
init_ip += sizeof(ByteCode*);
*((unsigned char**) init_ip) = beginBuf2;
init_ip += 1 + sizeof(unsigned char*);
*endOfIf = init_ip;
*gotoDestination2 = valGotoDestination2;

*init_ip++ = POP;
*init_ip++ = POP;
*init_ip++ = END;

// fprintf(stderr,"%pt%xn",gotoDestination2,*gotoDestination2);

#ifdef DEBUG
fprintf(stderr,"begin executionn");
#endif
__asm__ __volatile__ (
"jmp *%0n"
".endInterpret:"
: : "m" (beginBuf)
);
#ifdef DEBUG
fprintf(stderr,"end executionn");
#endif
return;
}
#endif

int main(int argc, char** argv) {
pputs = &puts;
pfprintf = &fprintf;
int i,n;
if (argc > 1) {
n = atoi(argv[1]);
} else {
n = 2;
}

ip = (ByteCode*) malloc(STACK_SIZE*sizeof(ByteCode));
sp = (int*) malloc(STACK_SIZE*sizeof(int));

#ifndef BLOCK_INTERPRET
ByteCode* init_ip = ip;

*init_ip++ = LOAD_0; // u0
*init_ip++ = DUP;
*init_ip++ = LOAD_1; // u1
*init_ip++ = DUP;
*init_ip++ = LOAD_N; // n
*((int*) init_ip) = n;
init_ip += 1 + sizeof(int);
ByteCode* beforeTest = init_ip;
*init_ip++ = IF;
ByteCode** endOfIf = (ByteCode**) init_ip;
init_ip += sizeof(ByteCode*);
*init_ip++ = DUP;
*init_ip++ = LOAD_1;
*init_ip++ = SUB; // n++
*init_ip++ = DUP_3;
*init_ip++ = POP;
*init_ip++ = DUP_2;
*init_ip++ = ADD;
*init_ip++ = DUP2;
*init_ip++ = POP;
*init_ip++ = POP;
*init_ip++ = GOTO;
*((ByteCode**) init_ip) = beforeTest;
init_ip += 1 + sizeof(ByteCode*);
*endOfIf = init_ip;
*init_ip++ = POP;
*init_ip++ = POP;
*init_ip++ = END;
#endif
*sp = -1;

#ifdef BASIC_INTERPRET
basicInterpret(ip,&sp);
#endif
#ifdef RICARDI_INTERPRET
ricardiInterpret(ip,&sp);
#endif
#ifdef BLOCK_INTERPRET
blockInterpret(n);
#endif
printf("%dn",*sp);

return 0;
}