2010-07-05 6 views
0

Je comprends un peu comment "int a = b + abs (c)" peut être traduit en instructions d'assemblage simples et ensuite traduire cela en un blob binaire. Mais comment cela peut-il être exécuté et interagir dynamiquement avec la mémoire?Principes de base JIT

- modifier -

Je sais que C ne dispose pas d'une fonction eval. Mais ce qu'il est compilé à fait. Je veux dire que c'est ce qui rend Java comme JITs, et d'ailleurs, l'injection de code malveillant possible non? Par exemple, la fonction abs() est juste un pointeur, qui pourrait être appelé en suivant le protocole cdecl. Les nouvelles fonctions devraient pouvoir être exposées en passant des pointeurs de fonction cdecl. Ce que je ne comprends pas, c'est comment ce nouveau code peut être injecté à l'exécution.

Je demande cela plus comme une curiosité académique de longue date, puis à résoudre le plus efficacement un problème réel.

- par exemple -

Dire que j'ai un morceau de code python intégré qui est appelé à partir d'un programme natif un grand nombre, et qui appelle aussi un natif de liaison notify():

def add(a, b): 
    notify() 
    return a+b 

pour que cela soit un point à faire, la fonction devrait probablement contenir tout à fait un peu plus de code (et de façon plus utile), mais porte avec moi. Un profileur (ou des notes de l'extrémité C-liaisons) a également identifié que tous les appels sont des nombres entiers avec avec à la fois avec l'ensemble des paramètres et de la valeur de retour. Cela correspond à:

int add(int a, int b) { 
    notify(); 
    return a + b; 
} 

Ce qui pourrait être compilé dans un x86 quelque chose cdecl semblable à ceci:

:_add 
push ebp ;setting up scope 
mov ebp, esp 
call _notify ;or more likely by a pointer reference 
mov eax, [ebp + 8] 
mov edx, [ebp + 12] 
add eax, edx 
pop ebp 
ret 

Puis finalement assemblés en une chaîne binaire. Bien sûr, il faudrait implémenter un compilateur de base pour chaque plate-forme pour aller aussi loin. Mais ce problème mis à part, disons que j'ai maintenant un pointeur de caractère vers ce code x86 binaire valide. Est-il possible d'extraire d'une manière ou d'une autre un pointeur de fonction cdecl utilisable pour le programme natif?

Désolé pour l'intention claire de ma question

+2

C est normalement mis en œuvre comme un langage compilé - vous semblez poser des questions sur la façon dont les déclarations C peuvent être interprétées. Typiquement, ils ne peuvent pas être. –

Répondre

1

En supposant que vous avez le code déjà compilé dans un bloc de mémoire, et vous avez l'adresse du bloc, il peut être casté à un pointeur de fonction:

typedef int (*func)(int, int); 
... 
char * compiledCode = ...; 
func f = (func) compiledCode; 

et la fonction peut être appelée:

int x = f(2, 3); 
+0

Way plus simple que je pensais. Grand merci! – Imbrondir

1

C est dénuée de toute fonction « eval », qui est à la fois une limitation et l'une des choses qui lui permet d'être efficace. Si tout ce que vous devez faire est d'évaluer les expressions mathématiques avec un petit ensemble de fonctions mathématiques intégrées comme abs() et non du code C arbitraire, il est relativement facile d'écrire un tel évaluateur d'expression.

Voici un lien vers un passé Thread sur un sujet similaire: c expression Evaluator

+0

Pour les expressions mathématiques simples avec des exigences de performance modérées, vous auriez tout à fait raison. Mis à jour avec la question originale avec des clarifications – Imbrondir

+0

Votre question n'est toujours pas claire. Voulez-vous juste ajouter de nouvelles fonctions qui peuvent être appelées, mais qui ne supportent que l'évaluation d'expression? Ou voulez-vous le langage C complet (constructions en boucle, etc.)? Dans ce dernier cas, la seule solution portable consiste à écrire un interpréteur C complet ou un compilateur qui génère du code à exécuter sur une machine virtuelle (que vous devez également implémenter). Si vous ne cherchez pas la portabilité, et que votre plateforme a des bibliothèques partagées/chargement dynamique, vous pouvez lancer le compilateur C et l'éditeur de liens pour construire une nouvelle bibliothèque puis le charger ... –

+0

Donc, fondamentalement, la seule façon de lancer la machine code compilé, est de créer une bibliothèque partagée et le charger? – Imbrondir

1

le programme doit être dans la région de mémoire qu'al ralentit l'exécution.

Sur Linux, vous pouvez le faire:

void *address; 
functype proc; 
int prot, flags; 

prot = PROT_READ|PROT_WRITE|PROT_EXEC; 
flags = MAP_PRIVATE|MAP_ANONYMOUS; 
address = mmap(NULL, length, prot, flags, -1, 0); 
if (address == NULL) error; 

memcpy(address, program, length); 
link(address, program_info); 

proc = (functype)address; 
Questions connexes