Naked function, asm inline, et chaînes de caractères [Résolu]

Signaler
Messages postés
37
Date d'inscription
jeudi 22 octobre 2009
Statut
Membre
Dernière intervention
10 décembre 2011
-
stagiairecpp
Messages postés
37
Date d'inscription
jeudi 22 octobre 2009
Statut
Membre
Dernière intervention
10 décembre 2011
-
Bonjour,

Voilà je rencontre un soucis très particulier sous VS pour une situation très particulière.
J'en appelle donc directement aux pro-codeurs adeptes de fonctions de cet acabit (BruNews si tu t'es pas reconnu dans le lot là ... ).

Contexte :
- Fonction naked
- Utilisation de variables globales impossible (aucune variable en section data)
- (Taille du binaire critique)

Problème :
Dans cette fonction j'utilise beaucoup de chaînes passées par pointeurs à des api win32.
Malheureusement pour moi, les fonctions naked interdisent la déclaration directe de chaines (de toutes façons ça terminerait en section data), et je ne peux pas employer de globales (car section data) comme précisé précédemment.
Autre grand malheur, l'assembleur inline de VS (les autres je sais pas) n'autorise pas l'utilisation de token du genre 'DB' (donc section code/text, ce que je souhaite).


Pour l'instant ce que je fais c'est que je déclare en C (ça pourrait aussi se faire directement en asm) un tableau de char en local (donc dans la pile) et je prend soin de sauvegarder ebp et décaler esp en tête de fonction (pour rétablir bien sûr à la fin).
Ensuite, premier cas de figure, j'initialise les octets un par un, ou second cas de figure je les initialise par double mot (donc en tenant compte du low-endian car destiné x86).
Le soucis c'est premièrement que c'est couteux en opcodes (la première solution encore plus que la seconde), et deuxièmement que ça devient très vite carrément illisible (la seconde solution encore plus que la première).

Le top question lisibilité et optimisation de la taille serait donc de trouver le moyen d'imposer au compilateur de faire un db directement dans le code, soit en asm inliné (mais la msdn dit que c'est pas possible), soit en équivalent C (mais je vois pas comment).
L'ultime solution à laquelle j'ai pensé serait de traduire ça directement en opcode puis de pointer dessus à l'aide d'une combinaison astucieuse de label/call/pop. Ca fonctionnerait mais là ça deviendrait vraiment pas bon pour ma santé mentale...

Existe t'il donc à votre connaissance une quelconque astuce ? Ou bien suis je condamné à splitter mon projet en deux sous-projets donc le second serait compilé directement via masm ?

Merci d'avance.

++

6 réponses

Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
10
Salut,

_emit est dispo sous VC pour écrire les octets que l'on veut dans du code.

(Pour le code suivant, attention à désactiver l'édition des liens incrémentale pour que HelloWorldString ne pointe pas sur un jmp).
#include <windows.h>

__declspec(naked) void HelloWorldString()
{
   __asm
   {
      __asm _emit 'H' __asm _emit 'e' __asm _emit 'l' __asm _emit 'l' __asm _emit 'o' __asm _emit ' '
      __asm _emit 'w' __asm _emit 'o' __asm _emit 'r' __asm _emit 'l' __asm _emit 'd' __asm _emit '!' __asm _emit 0
   }
}

__declspec(naked) void __stdcall NakedAsmFunction()
{
   __asm
   {
     push MB_OK
     push HelloWorldString
     push HelloWorldString
     push 0
     call dword ptr MessageBox
     ret
   }
}

int __cdecl WinMainCRTStartup()
{
  NakedAsmFunction();
  return 0;
}
Messages postés
37
Date d'inscription
jeudi 22 octobre 2009
Statut
Membre
Dernière intervention
10 décembre 2011
15
Ps (désolé, pas d'édition possible) :

Quand j'ai dis "pointer dessus à l'aide d'une combinaison astucieuse de label/call/pop", je voulais dire "pusher ça à l'aide d'une combinaison astucieuse de label/call/pop", ce qui serait idéale pour l'utilisation que j'en aurai, à savoir les passer en paramètre.

Mais bon je précise dans une but de cohérence mais ça n'est très probablement pas la solution pour laquelle j'opterai au final...

++
Messages postés
181
Date d'inscription
mardi 6 avril 2010
Statut
Membre
Dernière intervention
7 janvier 2012
4
Salut,
bon moi j'y connais pas grand chose en assembleur, et donc ce que tu dis ne me parle pas trop...

Par contre, je comprends:

Utilisation de variables globales impossible (aucune variable en section data)


Et là peut-être y'aurait-il une quelconque astuce, car a moins que je ne me trompe, si les variables globales (et statiques) ne sont pas initialisées, elles ne partent pas dans le data, mais dans le BSS ;)

Voilà, sinon pour ma part je ne pourrai pas te fournir plus d'aide; mais bon je dis déjà ça au cas ou ça puisse t'aider


C++dialement,
Pop70
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
16
Salut,

il ne faut surtout jamais prendre tout ce qu'on voit pour argent comptant. Quand je montre une initialisation directe d'octets pour former une chaine, c'est pur but didactique, absolument pas une méthode de prog à utiliser partout. Surtout que comme tu le signales c'est souvent couteux en code.

Si taille du binaire est critique, as-tu viré la CRT ?
C'est la première chose à faire.

ciao...
BruNews, MVP VC++
Messages postés
37
Date d'inscription
jeudi 22 octobre 2009
Statut
Membre
Dernière intervention
10 décembre 2011
15
Bonjour à tous,

D'abord, merci à vous trois d'avoir pris le temps de vous pencher sur mon problème.
Ensuite, je suis en visite pour le weekend donc je n'ai pas moyen de faire un quelconque test pour l'instant.

J'ai essayé dans un premier temps de traduire mes chaines en opcodes tout simplement en les copiant à l'EP d'un exe quelconque que j'ouvrais ensuite avec un debugger préalablement configuré pour breaker sur l'EP.
Malheureusement, ça donne lieu à des opcodes de type 'jb short' dont l'asm inline de VS ne veut pas entendre parler en raison du mot clé 'short'. J'ai bien essayé de l'utiliser en majuscules entre un '#undef SHORT' et un 'typedef short SHORT', mais rien à faire.

Donc pour l'instant j'ai opté pour une solution très proche de la tienne rt15, sauf que j'utilise des nop que je viens remplir directement dans le binaire via un petit tool fait vite fait pour l'occasion. Comme c'est un sous-projet du premier que je lance en évennement post-compilation ça n'est pas trop galère mais ça reste un peu obscure pour qui n'a pas suivi l'avancement du projet.
En tous cas ça fonctionne très bien pour l'instant et ça m'a fait gagner presque 1Ko de code pour six pauvres petites chaines.
Pour debugger je pointe directement sur les chaines en dur du sous-projet vu que je suis obligé de changer le prototype des fonctions de toutes façon (essayez un peu de debugger du naked sous VS ...).

@pop70>
Oui effectivement ça part généralement en section bss (quoiqu'il me semble que VS agit différemment, mais comme précisé je n'ai rien pour vérifier dans l'immédiat).
De toutes façons je n'ai pas été précis dans mon explication : en fait ça n'est pas que je ne peux pas utiliser la section data, c'est que je ne peux pas utiliser d'autre section que la code/text.

@BruNews>
Il faut bien évidemment adapter la méthode au besoin, mais en l’occurrence l'initialisation directe d'octets s'impose.
Concernant la crt, le code en est déjà totalement exempt car c'est une condition sine qua non.

@rt15>
Lors de mes recherches je suis tombé sur ce mot clé dans un post concernant les compilateurs Borland. Très enthousiasmé j'ai directement tenté de l'employer sous VS mais rien à faire. En revanche je constate que tu le préfixes d'un underscore, ce que je n'avais pas fait de mémoire.
S'il s'avère que ça fonctionne avec ton orthographe alors ça serait la réponse à ma question.
Je teste ça dès que possible et vous tiens informés.

Merci, et bon weekend.

++
Messages postés
37
Date d'inscription
jeudi 22 octobre 2009
Statut
Membre
Dernière intervention
10 décembre 2011
15
Salut,

Super, ça fonctionne !

Merci.

++