2009-11-18 5 views
1

Cela va sonner super-hackish, mais est-ce que quelqu'un connaît un moyen de combiner des corps de méthode à l'exécution en C++? Je suis actuellement sur le chemin de saisir l'adresse des fonctions, puis memcopy à la mémoire exécutable, mais il a le problème de prolog/epilog indésirable. Essentiellement j'ai quelques douzaines d'opérations simples qui prennent les mêmes arguments et ne retournent rien et je veux construire une fonction à l'exécution de ces opérations simples.Combinaison de corps de fonctions au moment de l'exécution

+1

@Hippiehunter: oui ça sonne vraiment hack – RageZ

+2

@RageZ: Oui, mais ça a l'air plutôt joli. Des fruits interdits, je suppose. – bcat

+0

Vous voulez dire que vous voulez enchaîner les opérations de fonctions? – Alon

Répondre

3

Je ne vois aucune utilité pratique pour cela, sauf pour le diable :-)

Alors, vous devriez d'abord décider d'une plate-forme. Il n'y a pas moyen de faire cela de manière multi-plateforme. En fait, il peut être assez difficile de le faire d'une manière qui fonctionne sur plusieurs compilateurs, même sur la même plate-forme. Ensuite, le type de processeur, bien sûr :-)

alors vous devriez vérifier en quelque sorte que le code que vous copiez peut être déplacé. Tout ne peut pas être déplacé comme vous le souhaitez.

Vous devez très bien comprendre les conventions d'appel, afin de vous assurer de ne pas gâcher la pile. Connaître le prolog/epilog généré par votre compilateur.

Vous pouvez probablement tricher en ajoutant au début et à la fin des fonctions des séquences de code qui ne font rien, mais vous pouvez utiliser comme signature puis chercher (par exemple nop; nop; nop; xor ax, ax; nop; pousser ax; pop ax; nop; nop; nop;). Assurez-vous que le compilateur n'est pas optimisé :-)

Assurez-vous que vous pouvez écrire/exécuter ce code. Les processeurs et systèmes d'exploitation modernes ne permettent normalement pas d'écrire dans un segment de code, ou d'exécuter un segment non-code. Vous devrez donc savoir quelles sont les façons de changer les droits (100% OS spécifiques). Ensuite, amusez-vous à combattre des choses comme «randomisation de la disposition de l'espace d'adressage», «randomisation de la pile», «prévention de l'exécution des données», «randomisation du tas».

Quoi qu'il en soit, beaucoup de travail. Et inutile, sauf pour profiter d'un bon défi et en même temps apprendre quelques assemblages et OS internes. O pour se prouver comme "1337", mais ensuite, demander sur stackoverflow comment le faire n'est pas tout à fait "1337", si vous me demandez :-)

Quoi qu'il en soit, bonne chance.

+0

L'exécution du tas n'est pas un problème (quelques appels et tout ce qui est exécutable) et je l'ai déjà fait dans des cas simples. Je suppose que j'étais brûlé par des instructions non relocalisables. Mais maintenant qu'il a été mentionné les instructions rares ou setjmp sonne comme un excellent moyen de copier les emplacements de mémoire. Je vais donner à votre réponse la réponse parce que c'est la plus complète mais la réponse complète semble exiger beaucoup de techniques. – Hippiehunter

+0

Salut Mihai - ça vous dérange si je vous demande si vous avez complètement abandonné tout support pour votre très cool produit ansi econsole? Je ne pouvais pas l'installer dans la dernière éclipse Luna. J'ai été capable de mettre quelques trucs dans la zone du plugin manuellement et d'afficher les icônes mais la console n'a pas rendu les codes d'échappement. Dit qu'il avait une dépendance Java 6 SE mais je pense que Luna est 7. Je ne sais pas si c'est un facteur. Votre site est en panne? J'ai vu un commentaire de quelqu'un d'autre qu'ils ont eu la même erreur en essayant d'installer à partir du marché (après que j'ai visité le bundle et votre github proj). – clearlight

+0

Non, je le supporte toujours. On dirait que mon FAI a eu quelques problèmes, mais je pensais que c'était temporaire. J'ai préparé un site alternatif sur GitHub, et si les erreurs continuent, je le déplacerai là. Mais cela ne devrait rien avoir avec Java 6 ... Pouvez-vous s'il vous plaît déposer un bug (avec un message d'erreur) sur https://github.com/mihnita/ansi-econsole/issues? Ou laissez un commentaire ici si vous n'avez pas de compte github: https://mihai-nita.net/java/ Merci beaucoup. –

3

Pourquoi ne pas utiliser l'assemblage?

+0

puisque c'est à l'exécution, (corrigez-moi si je me trompe) je devrais faire le travail d'un assembleur à l'exécution, je suppose que je ne suis pas intéressé par tant de travail. – Hippiehunter

0

Il est un poids lourd de peu, donc il ne peut pas être ce que vous cherchez, mais vous pouvez toujours essayer d'utiliser LLVM pour JIT votre code.

4

Une solution simple pour réaliser ce que vous voulez est de stocker des pointeurs de fonction dans un tableau.
Ensuite, vous pouvez créer à l'exécution des listes de pointeurs de fonctions (vos scripts).
Vous exécutez le script en itérant la liste et en appelant les fonctions.

+0

Cette approche n'évite pas les appels. – Gonzalo

2

Ça ne marchera pas, mais je vous dis ce que je sais. Vous pouvez obtenir la position actuelle du compteur de processus avec setjmp() et travailler dans la structure remplie que vous obtenez.

Si je devais faire quelque chose comme vous le demandiez, je mettrais deux setjmp au début et à la fin des routines, allouer de la mémoire exécutable (est-ce possible?) Je pensais que la section texte était en lecture seule les débordements de buffer exploitent le travail en exécutant la pile, donc oui, je suppose que vous le pouvez, sauf si vous avez la technostuff NX) alors copiez le morceau des quatre parenthèses obtenues setjmp. Dans ce processus, vous allez avoir un désordre avec les opcodes qui ne sont pas relocalisables, je suppose, comme s'ils se réfèrent à l'adresse absolue d'autres opcodes dans votre code assembleur. Bien sûr, si vous copiez, cette adresse doit être modifiée en conséquence.

Bonne chance.

+0

@Stefano Borini, à droite. @ Hippiehunter, vous pourriez le faire sur un système fait par Microsoft ou vous-même. – Test

2

Modèles?

Si vous avez ceci:

template <int Operations> 
struct Foo 
{ 

    static void Do(int a, int b) 
    { 
    if (Operations & 1) 
    { 
     /// op 1 
    } 

    if (Operations & 2) 
    { 
     /// op 2 
    } 
    if (Operations & 4) 
    { 
     /// op 3 
    } 
    //... 
    } 
}; 

l'optimiseur jeter les blocs qui ne sont pas pertinents pour votre spécialisation, par exemple

Foo<6>::Do(77,88)

ne traitera les 2e et 3e étape et non générer du code pour le 1er op.

(Vous devriez vérifier la sortie de votre compilateur, mais la plupart devriez pouvoir. J'utilise cela pour vérifier les propriétés du tableau sélectionné, travaillé sous VC6 et plus tard compilateurs comme un charme)

1

Pour une trully dynamique solution ... en les combinant physiquement ensemble:

  • Supposons que vos opérations prennent environ le même nombre d'instructions.
  • Assurez-vous qu'ils laissent les paramètres intacts (à savoir laisser la pile et appeler intacte registres).
  • marque la fin d'une instruction rare.

Vous êtes maintenant prêt à construire un vecteur d'instructions:

struct Op { 
    char code[MAX_OP_SIZE]; 
    public Op(const void (*op)()) { 
     /* fill code with no-ops */ 
     const char* opCode = (char*)op; 
     char* opCodeCopy = &code[0]; 
     while (*opCode != GUARD_INSTRUCTION) { 
      *opCodeCopy++ = *opCode++; 
     } 
    } 
} 

std::vector<Op> combinedOperation; 

combinedOperation.push_back(op1); 
// ... 

void (*combinedOpFunc)(params) = void *()(params)&combinedOperation[0]; // not sure about syntax here 

combinedOpFunc(data); 
// start praying 

Une autre option est de ne pas copier le code du tout. C'est une variation de la réponse de Stano Borini en utilisant setjmp/longjmp. Au lieu d'avoir des sauts dans chaque méthode, nous les installons une fois.

Si votre op ressemblait à:

void op1(paramtype param) { ... } 

rendent vide typedef (* optype) (ParamType);

void op1(paramtype param, OPTYPE nextop, jmp_buf returnFrame) 
{ 
    // ... 
    if (nextop) { 
     // place (paramtype+1) into argument slot 2 (assume +1 does pointer arithmetic) 
     // update program counter to value of paramtype 
    } else { 
     longjmp(returnFrame, 0); 
    } 
} 

Ensuite, faire une liste des opérations:

std::vector<OPTYPE> ops; ops.push_back(&op1); // ... 

et une fonction d'aide

void callOps(const std::vector<OPTYPE>& opList, paramtype param) 
{ 
    OPTYPE firstOp = (OPTYPE)&opList[0]; 
    jmp_buf frame; 
    int ret = setjmp(&frame); 
    if (ret == 0) firstOp(param, firstOp + 1, frame); 
} 

et exécutons-le

callOps(ops, opParameter); 
Questions connexes