[C/C++] appel dynamique de fonction

Fermé
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 - 7 oct. 2008 à 16:51
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 - 9 nov. 2008 à 19:19
Bonjour,
il y a un problème sur lequel je bloque depuis un certain temps, et je voudrais savoir si l'un d'entre vous peut m'aider (même si la solution nécessite de l'assembleur c'est pas un problème, et la portabilité m'importe peu (développement ciblé Windows exlu sous VS 2005 C++))

En fait je souhaite créer une bibliothèque dynamique (DLL) qui soit capable d'appeler des fonctions qui lui sont passées plus tard. Je m'explique

Le développeur qui utilise ma bibliothèque va créer une fonction, par exemple maFonction(int, int char*);
Ensuite, il me donne le pointeur de la fonction, puis il me dit que cette fonction prend 2 int et un char * (ce que l'on a aucun moyen de savoir à la compilation)
La DLL doit être capable d'appeller cette fonction avec les arguments demandés (la bibliothèque génère ces arguments en fonction d'autres entrées utilisateur)

Comment faire?


merci à tous d'avance
@xi@g@me
A voir également:

17 réponses

kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
7 oct. 2008 à 19:06
Salut,

Non ça ne necessite pas d'assembleur :-)
Par contre il faudra que le pointeur de fonction en question fourni par l'utilisateur soit de nombre de paramètres variables, ou plus exactement ne prenne qu'un paramètre: un argument de type va_list (type standard fourni dans stdarg.h représentant une liste d'argument.

Quelques explications ici:
http://www.linux-kheops.com/doc/man/manfr/man-ascii-0.9/man3/va_start.3.txt.html

Un exemple avec une fonction qui additionne deux entiers:
//Fichier source du developpeur
#include <stdarg.h>

int add(va_list args)
{
    int arg1, arg2;
    arg1 = va_arg(args, int);
    arg2 = va_arg(args, int);
    return arg1 + arg2;
}

int main()
{
    int test = exec_user_func(add, 1, 2);
    printf("%d\n", test); // Affichera 3
    return 0;
}

//Fichier dll
#include <stdarg.h>

typedef (int) (*func_variable) (va_list);

int exec_user_func(func_variable func, ...)
{
    int ret;
    va_list args;
    va_start(args, func);
    ret = func(args);
    va_end(args);
}


Bien sûr il faut quand même être sûr du type de retour, c'est la moindre des choses :-)
3
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
8 oct. 2008 à 00:08
salut,
et merci pour ta réponse rapide.

le souci est que je ne souhaite pas que l'utilisateur aie a utiliser va_list car il pourrait lancer ses méthodes de lui même parfois. j'ai pensé a va_list, mais je ne souhaite pas l'utiliser. Je voudrais que l'utilisateur aie a déclarer ses fonctions comme d'habitude (ex : void add(int, int);)

ass-tu une idée?
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
8 oct. 2008 à 08:58
ba là je me demande si c'est faisable.
En C++ ça me semble impossible car la fonction a dans son nom le nombre et type d'argument une fois compilé.
en général, dans ce genre de cas, tu passe par un paramètre générique comme void*.
0
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
8 oct. 2008 à 10:21
De toutes façons même en C je doute que ça soit faisable comme tu le souhaites.
L'idéal comme le Char Snipeur, c'est d'avoir une fonction qui prends en paramètre un pointeur vers une structure, puis de l'appeller par la fonction de dll qui prendra le paramètre en tant que void *.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
8 oct. 2008 à 14:20
salut,
En faisant des recherches sur internet, c'est effectivement ce que j'ai remarqué...
ne peut t-on pas faire en utilisant du code assembleur?

par exemple on fait un push des paramètres et ensuite un call sur la fonction (et un pop pour enlever les paramètres)
0
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
8 oct. 2008 à 14:31
Ca ne change rien. Comment la fonction de la dll va deviner combien de paramètres il faut envoyer, et quels sont leurs types?
0
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
8 oct. 2008 à 16:59
on le lui dit par l'appel d'autres fonctions ^^
0
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
8 oct. 2008 à 18:03
Ah dans ce cas oui. Il faut au préalable (ou durant l'appel) lui signaler le nombre de paramètres que tu lui soumets.
Mais bon c'est pas très propre tout ça :-)
0
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
8 oct. 2008 à 19:22
en fait, un premier appel sert à donner à la DLL le pointeur de la fonction.
Ensuite, c'est assez complexe mais disons que l'utilisateur indique indirectement les paramètres formels de la fonction pour faire simple

une fois toutes les fonctions et leurs paramètres formels envoyés, l'utilisateur appelle une fonction qui lance un algorithme dans la DLL qui est susceptible d'appeler les fonctions transmises par l'utilisateur.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
9 oct. 2008 à 08:36
Aîe ! ma tête...
Bonne chance, et dit nous si tu y arrive.
0
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
9 oct. 2008 à 09:59
Oui moi aussi bobo les neurones là...
0
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
9 oct. 2008 à 14:08
ben en fait, ce qu'il me faudrait c'est savoir comment implémenter du code assembleur dans Visual Studio 2005 et aussi comment faire pour savoir en assembleur ou sont stockées mes variables C.
Après il suffit d'expérimenter ^^'
0
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
9 oct. 2008 à 14:23
Dans VC:
__asm {
    mov eax, ebx
    etc....
}


Pour trouver tes variables, ah ben là.... :-)
C'est tout un truc à apprendre.
Les variables locales aux fonctions sont soit dans la pile soit dans des registres.
Généralement c'est les deux:
Les variables locales sont dans la pile. Mais dès qu'il faut faire un calcul sur ces variables, on les met dans des registres. Une fois le calcul fait, on les remets eventuellement dans la pile.

Mais pour optimiser, parfois le compilo cantone les variables dans les registres.

Quant aux variables globales sont dans des sections du binaire (dans la mémoire donc...quelque part).

Ici tu trouveras des renseignements dans les derniers chapitres : http://www.drpaulcarter.com/pcasm/

Le passage de paramètres, c'est dans la pile. Par défaut avec la convention cdecl, mais sous windows les fonctions de l'api sont en stdcall: http://www.commentcamarche.net/faq/sujet 4874 programmation conventions de passage de parametres sous x86

Voilà voilà. Ca va pas être facile au début :-)
0
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
9 oct. 2008 à 21:06
ok, merci beaucoup pour toutes ces infos ^^
dès que j'ai le temps j'essaye!!! (avec ce prof de génie logiciel on est pas sorti ^^')
0
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
23 oct. 2008 à 15:07
salut à tous
j'avance un peu dans la résolution du problème, mais je suis tombé sur quelques trus assez amusants :

La première chose que j'ai faite est de créer ce petit programme :
(ici je fonctionne en stdcall pour le moment)

#include <stdio.h>

void __attribute__((stdcall)) ecrire(int a)
{
  printf("%d\n", a);
}

void __attribute__((stdcall)) afficher(char * s)
{
  printf("%s\n", s);
}

int main(int argc, char * argv[])
{
  int a = 24;
  int b = 35;
  char * tot = "totohffdfdvfgsjhdhjkgsgbdshfejgtrjhdfbvsdjbfjsvjfsyuedbfhndbsjvfjsdbfjhsdgfjgsjgeyugfhjsgfjsvfjgeygesyfv fgsgfeyu/n \n \%d frrty /t fdthdjhskdvnbnjfherkuiugfdhgbn nsejirhtier  et la ca marche encore ???????h";
  // affichage de 35
  ecrire(b);
  // affichage de toto
  afficher(tot);
  // affichage de 24
  ecrire(a);
}



je compile donc ce code en faisant g++ -S, et j'obtiens ceci (simplifié):

main:
.LFB4:
	leal	4(%esp), %ecx
.LCFI6:
	andl	$-16, %esp
	pushl	-4(%ecx)
.LCFI7:
	pushl	%ebp
.LCFI8:
	movl	%esp, %ebp
.LCFI9:
	pushl	%ecx
.LCFI10:
	subl	$20, %esp
.LCFI11:
	movl	$24, -16(%ebp)
	movl	$35, -12(%ebp)
	movl	$.LC1, -8(%ebp)
	movl	-12(%ebp), %eax
	movl	%eax, (%esp)
	call	_Z6ecrirei
	subl	$4, %esp
	movl	-8(%ebp), %eax
	movl	%eax, (%esp)
	call	_Z8afficherPc
	subl	$4, %esp
	movl	-16(%ebp), %eax
	movl	%eax, (%esp)
	call	_Z6ecrirei
	subl	$4, %esp
	movl	$0, %eax
	movl	-4(%ebp), %ecx
	leave
	leal	-4(%ecx), %esp
	ret


dans la partie déclarations des variables (ou je fais int b = 35; etc), je vois ceci : (LC1 c'est la chaine de caractères)
	movl	$24, -16(%ebp)
	movl	$35, -12(%ebp)
	movl	$.LC1, -8(%ebp)

On comprend donc en toute logique que dans la pile d'appel (ebp) on met de -8 à -5 la chaine de caractères (déclarée en dernier), de -12 à -9 l'entier b et de -16 à -13 l'entier a. J'en déduit donc que le compilateur met les variables dans l'ordre "inverse" de leur déclaration.

Ce qui m'a emmené à faire ceci :


#include <stdio.h>

void __attribute__((stdcall)) ecrire(int a)
{
  printf("%d\n", a);
}

void __attribute__((stdcall)) afficher(char * s)
{
  printf("%s\n", s);
}

typedef void (*f_ptr)();

int main(int argc, char * argv[])
{
  void (*ptr)() = (f_ptr)(ecrire);
  void (*ptr2)() = (f_ptr)(afficher);
  int a = 24;
  int b = 35;
  char * tot = "totohffdfdvfgsjhdhjkgsgbdshfejgtrjhdfbvsdjbfjsvjfsyuedbfhndbsjvfjsdbfjhsdgfjgsjgeyugfhjsgfjsvfjgeygesyfv fgsgfeyu/n \n \%d frrty /t fdthdjhskdvnbnjfherkuiugfdhgbn nsejirhtier  et la ca marche encore ???????h";

  // affichage de 35
  asm("pushl %eax");
  asm("movl -12(%ebp), %eax");
  asm("movl %eax, (%esp)");
  ptr();
  asm ("popl %eax");
  asm("subl $4, %esp");

  // affichage de tot
  asm("pushl %eax");
  asm("movl -8(%ebp), %eax");
  asm("movl %eax, (%esp)");
  ptr2();
  asm("popl %eax");
  asm("subl $4, %esp");

  // affichage de 24
  asm("pushl %eax");
  asm("movl -16(%ebp), %eax");
  asm("movl %eax, (%esp)");
  ptr();
  asm("popl %eax");
  asm("subl $4, %esp");
}



Le principe étant simple, (on créée 2 pointeurs de fonction a paramètre vides (void) qu'on affecte avec les fonctions à utiliser (avec un cast de type à l'aide de f_ptr), ensuite on empile en assembleur les paramètres des fonctions puis on appelle celles-ci grâce au pointeur), le code compile et fonctionne.


Pour pouvoir continuer, j'ai donc voulu écrire une fonction qui prend plusieurs paramètres pour voir comment elle est appelée. Pour ceci, je rajoute les paramètres avant a, b et tot afin d'éviter de changer leur adresse dans la pile d'appel.
j'obtiens donc le code suivant :


#include <stdio.h>

void __attribute__((stdcall)) ecrire(int a)
{
  printf("%d\n", a);
}

void __attribute__((stdcall)) ecrire2(short c, char d, long long x, int a)
{
  printf("%d-%d-%d-%d\n", c, d, x, a);
}

void __attribute__((stdcall)) afficher(char * s)
{
  printf("%s\n", s);
}

typedef void (*f_ptr)();

int main(int argc, char * argv[])
{
  void (*ptr)() = (f_ptr)(ecrire);
  void (*ptr2)() = (f_ptr)(afficher);
  short c = 12;
  char d = 'k';
  long long x = 285145145;
  int a = 24;
  int b = 35;
  char * tot = "totohffdfdvfgsjhdhjkgsgbdshfejgtrjhdfbvsdjbfjsvjfsyuedbfhndbsjvfjsdbfjhsdgfjgsjgeyugfhjsgfjsvfjgeygesyfv fgsgfeyu/n \n \%d frrty /t fdthdjhskdvnbnjfherkuiugfdhgbn nsejirhtier  et la ca marche encore ???????h";
  // affichage de 35
  asm("pushl %eax");
  asm("movl -12(%ebp), %eax");
  asm("movl %eax, (%esp)");
  ptr();
  asm ("popl %eax");
  asm("subl $4, %esp");
  // affichage de toto
  asm("pushl %eax");
  asm("movl -8(%ebp), %eax");
  asm("movl %eax, (%esp)");
  ptr2();
  asm("popl %eax");
  asm("subl $4, %esp");
  // appel de ecrire2
  ecrire2(c, d, x, a);
  // affichage de 24
  asm("pushl %eax");
  asm("movl -16(%ebp), %eax");
  asm("movl %eax, (%esp)");
  ptr();
  asm("popl %eax");
  asm("subl $4, %esp");
}



j'ai rajouté la fonction écrire2, ainsi que les variables de types long long, char et short (tant qu'à faire...)
j'obtiens ceci en assembleur (code complet)


	.file	"test.cpp"
	.text
	.align 2
.globl _Z8afficherPc
	.type	_Z8afficherPc, @function
_Z8afficherPc:
.LFB4:
	pushl	%ebp
.LCFI0:
	movl	%esp, %ebp
.LCFI1:
	subl	$8, %esp
.LCFI2:
	movl	8(%ebp), %eax
	movl	%eax, (%esp)
	call	puts
	leave
	ret	$4
.LFE4:
	.size	_Z8afficherPc, .-_Z8afficherPc
.globl __gxx_personality_v0
	.section	.rodata
.LC0:
	.string	"%d-%d-%d-%d\n"
	.text
	.align 2
.globl _Z7ecrire2scxi
	.type	_Z7ecrire2scxi, @function
_Z7ecrire2scxi:
.LFB3:
	pushl	%ebp
.LCFI3:
	movl	%esp, %ebp
.LCFI4:
	pushl	%ebx
.LCFI5:
	subl	$52, %esp
.LCFI6:
	movl	8(%ebp), %eax
	movl	12(%ebp), %edx
	movw	%ax, -12(%ebp)
	movb	%dl, -16(%ebp)
	movl	16(%ebp), %eax
	movl	%eax, -24(%ebp)
	movl	20(%ebp), %eax
	movl	%eax, -20(%ebp)
	movsbl	-16(%ebp),%ecx
	movswl	-12(%ebp),%ebx
	movl	24(%ebp), %eax
	movl	%eax, 20(%esp)
	movl	-24(%ebp), %eax
	movl	-20(%ebp), %edx
	movl	%eax, 12(%esp)
	movl	%edx, 16(%esp)
	movl	%ecx, 8(%esp)
	movl	%ebx, 4(%esp)
	movl	$.LC0, (%esp)
	call	printf
	addl	$52, %esp
	popl	%ebx
	popl	%ebp
	ret	$20
.LFE3:
	.size	_Z7ecrire2scxi, .-_Z7ecrire2scxi
	.section	.rodata
	.align 4
.LC1:
	.string	"totohffdfdvfgsjhdhjkgsgbdshfejgtrjhdfbvsdjbfjsvjfsyuedbfhndbsjvfjsdbfjhsdgfjgsjgeyugfhjsgfjsvfjgeygesyfv fgsgfeyu/n \n %d frrty /t fdthdjhskdvnbnjfherkuiugfdhgbn nsejirhtier  et la ca marche encore ???????h"
	.text
	.align 2
.globl main
	.type	main, @function
main:
.LFB5:
	leal	4(%esp), %ecx
.LCFI7:
	andl	$-16, %esp
	pushl	-4(%ecx)
.LCFI8:
	pushl	%ebp
.LCFI9:
	movl	%esp, %ebp
.LCFI10:
	pushl	%ebx
.LCFI11:
	pushl	%ecx
.LCFI12:
	subl	$80, %esp
.LCFI13:
	movl	$_Z6ecrirei, -44(%ebp)
	movl	$_Z8afficherPc, -40(%ebp)
	movw	$12, -36(%ebp)
	movb	$107, -33(%ebp)
	movl	$285145145, -32(%ebp)
	movl	$0, -28(%ebp)
	movl	$24, -20(%ebp)
	movl	$35, -16(%ebp)
	movl	$.LC1, -12(%ebp)
#APP
	pushl %eax
	movl -12(%ebp), %eax
	movl %eax, (%esp)
#NO_APP
	movl	-44(%ebp), %eax
	call	*%eax
#APP
	popl %eax
	subl $4, %esp
	pushl %eax
	movl -8(%ebp), %eax
	movl %eax, (%esp)
#NO_APP
	movl	-40(%ebp), %eax
	call	*%eax
#APP
	popl %eax
	subl $4, %esp
#NO_APP
	movsbl	-33(%ebp),%ecx
	movswl	-36(%ebp),%ebx
	movl	-20(%ebp), %eax
	movl	%eax, 16(%esp)
	movl	-32(%ebp), %eax
	movl	-28(%ebp), %edx
	movl	%eax, 8(%esp)
	movl	%edx, 12(%esp)
	movl	%ecx, 4(%esp)
	movl	%ebx, (%esp)
	call	_Z7ecrire2scxi
	subl	$20, %esp
#APP
	pushl %eax
	movl -16(%ebp), %eax
	movl %eax, (%esp)
#NO_APP
	movl	-44(%ebp), %eax
	call	*%eax
#APP
	popl %eax
	subl $4, %esp
#NO_APP
	movl	$0, %eax
	leal	-8(%ebp), %esp
	popl	%ecx
	popl	%ebx
	popl	%ebp
	leal	-4(%ecx), %esp
	ret
.LFE5:
	.size	main, .-main
	.section	.rodata
.LC2:
	.string	"%d\n"
	.text
	.align 2
.globl _Z6ecrirei
	.type	_Z6ecrirei, @function
_Z6ecrirei:
.LFB2:
	pushl	%ebp
.LCFI14:
	movl	%esp, %ebp
.LCFI15:
	subl	$8, %esp
.LCFI16:
	movl	8(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	$.LC2, (%esp)
	call	printf
	leave
	ret	$4
.LFE2:
	.size	_Z6ecrirei, .-_Z6ecrirei
	.section	.eh_frame,"a",@progbits
.Lframe1:
	.long	.LECIE1-.LSCIE1
.LSCIE1:
	.long	0x0
	.byte	0x1
	.string	"zP"
	.uleb128 0x1
	.sleb128 -4
	.byte	0x8
	.uleb128 0x5
	.byte	0x0
	.long	__gxx_personality_v0
	.byte	0xc
	.uleb128 0x4
	.uleb128 0x4
	.byte	0x88
	.uleb128 0x1
	.align 4
.LECIE1:
.LSFDE1:
	.long	.LEFDE1-.LASFDE1
.LASFDE1:
	.long	.LASFDE1-.Lframe1
	.long	.LFB4
	.long	.LFE4-.LFB4
	.uleb128 0x0
	.byte	0x4
	.long	.LCFI0-.LFB4
	.byte	0xe
	.uleb128 0x8
	.byte	0x85
	.uleb128 0x2
	.byte	0x4
	.long	.LCFI1-.LCFI0
	.byte	0xd
	.uleb128 0x5
	.align 4
.LEFDE1:
.LSFDE3:
	.long	.LEFDE3-.LASFDE3
.LASFDE3:
	.long	.LASFDE3-.Lframe1
	.long	.LFB3
	.long	.LFE3-.LFB3
	.uleb128 0x0
	.byte	0x4
	.long	.LCFI3-.LFB3
	.byte	0xe
	.uleb128 0x8
	.byte	0x85
	.uleb128 0x2
	.byte	0x4
	.long	.LCFI4-.LCFI3
	.byte	0xd
	.uleb128 0x5
	.byte	0x4
	.long	.LCFI6-.LCFI4
	.byte	0x83
	.uleb128 0x3
	.align 4
.LEFDE3:
.LSFDE5:
	.long	.LEFDE5-.LASFDE5
.LASFDE5:
	.long	.LASFDE5-.Lframe1
	.long	.LFB5
	.long	.LFE5-.LFB5
	.uleb128 0x0
	.byte	0x4
	.long	.LCFI7-.LFB5
	.byte	0xc
	.uleb128 0x1
	.uleb128 0x0
	.byte	0x9
	.uleb128 0x4
	.uleb128 0x1
	.byte	0x4
	.long	.LCFI8-.LCFI7
	.byte	0xc
	.uleb128 0x4
	.uleb128 0x4
	.byte	0x4
	.long	.LCFI9-.LCFI8
	.byte	0xe
	.uleb128 0x8
	.byte	0x85
	.uleb128 0x2
	.byte	0x4
	.long	.LCFI10-.LCFI9
	.byte	0xd
	.uleb128 0x5
	.byte	0x4
	.long	.LCFI12-.LCFI10
	.byte	0x84
	.uleb128 0x4
	.byte	0x83
	.uleb128 0x3
	.align 4
.LEFDE5:
.LSFDE7:
	.long	.LEFDE7-.LASFDE7
.LASFDE7:
	.long	.LASFDE7-.Lframe1
	.long	.LFB2
	.long	.LFE2-.LFB2
	.uleb128 0x0
	.byte	0x4
	.long	.LCFI14-.LFB2
	.byte	0xe
	.uleb128 0x8
	.byte	0x85
	.uleb128 0x2
	.byte	0x4
	.long	.LCFI15-.LCFI14
	.byte	0xd
	.uleb128 0x5
	.align 4
.LEFDE7:
	.ident	"GCC: (GNU) 4.1.2 20071124 (Red Hat 4.1.2-42)"
	.section	.note.GNU-stack,"",@progbits



je m'intéresse à la partie déclaration des variables, et là :

.LCFI13:
	movl	$_Z6ecrirei, -44(%ebp)
	movl	$_Z8afficherPc, -40(%ebp)
	movw	$12, -36(%ebp)
	movb	$107, -33(%ebp)
	movl	$285145145, -32(%ebp)
	movl	$0, -28(%ebp)
	movl	$24, -20(%ebp)
	movl	$35, -16(%ebp)
	movl	$.LC1, -12(%ebp)



l'entier b (35) a été déplacé a -16, le a à -20 et la chaine de caractères à -12 :S
alors ma question est pourquoi il n'y a plus rien à -8 (une chaine de caractères étant un pointeur sur caractères (machine 32 bits) elle ne prend que 4 octets et donc que de -12 à -9, et aussi pourquoi le long long ne prend que de -32 (jusqu'à -25) et laisse donc de -24 à -21 libre???

est-ce que quelqu'un à une idée? je ne comprend pas le comportement du compilateur

merci d'avance et bon courage :p ^^
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
23 oct. 2008 à 15:45
Salut.
Je suis une quiche grave en assembleur.
Mais pour tes histoires de décalage, j'ai peux être un début de réponse : à cause de l'alignement.
Pour accéder plus vite aux données, des fois le compilateur les décales, car il lit par paquet. Regarde le chapitre 7 de ce livre, c'est à ça que ça m'a fait pensé : https://beuss.developpez.com/tutoriels/pcasm/
Après, il est possible que ça n'est rien à voir. Peut être intercale t'il des données masqué à ces endroits, essai éventuellement de les lire.
0
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
23 oct. 2008 à 16:42
Il n'y a plus à -8 parce que ebx etc ecx on t été pushés.
Donc il y a ces deux registres entre (%ebp) et 8(%ebp).
Par contre entre 21 et 24, c'est le mystère... Peut être l'alignement oui.

En tout cas, comme tu l'as vu le comportement d'un compilateur n'est pas facile à prévoir, donc l'idéal c'est d'utiliser des références évoluées à tes variables.

Voilà comment je verrais bien ton code:
#include <stdio.h>

void __attribute__((stdcall)) ecrire(int a)
{
  printf("%d\n", a);
}

void __attribute__((stdcall)) ecrire2(short c, char d, long x, int a)
{
  printf("%d-%d-%d-%d\n", c, d, x, a);
}

void __attribute__((stdcall)) afficher(char * s)
{
  printf("%s\n", s);
}

typedef void (*f_ptr)();

int main(int argc, char * argv[])
{
  void (*ptr)() = (f_ptr)(ecrire);
  void (*ptr2)() = (f_ptr)(afficher);
  short c = 12;
  char d = 'k';
  long x = 285145145;
  int a = 24;
  int b = 35;
  char * tot = "totohffdfdvfgsjhdhjkgsgbdshfejgtrjhdfbvsdjbfjsvjfsyuedbfhndbsjvfjsdbfjhsdgfjgsjgeyugfhjsgfjsvfjgeygesyfv fgsgfeyu/n \n \%d frrty /t fdthdjhskdvnbnjfherkuiugfdhgbn nsejirhtier  et la ca marche encore ???????h";

__asm__ __volatile__(

  // affichage de 35
  "pushl %1\n"
  "call *(%7)\n"
  "add$4, %esp\n"

  // affichage de toto
  "pushl %0\n"
  "call *(%6)\n"
  "add $4, %esp\n"

  // appel de ecrire2
  ecrire2(c, d, x, a);
  // affichage de 24
  "pushl %2\n"
  "pushl %3\n"
  "pushw %4\n"
  "pushw %5\n"
  "call ecrire2\n"
  "add $0xc, %esp\n";
  :
  : "r" (tot), "r"(b), "r"(a), "r"(x), "r"(d), "r"(c), "r"(ptr2), "r"(ptr)
);



C'est un peu spécial et pas facile à expliquer.
Il faudrait que tu lises ça: https://www.ibm.com/developerworks/linux/library/l-ia/index.html

PS: Je peux pas tester le code ici donc ya sûrement quelques erreurs.
0
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
9 nov. 2008 à 18:49
je crois comprendre ce que tu veux dire...

cela me semble est une solution, mais j'ai encore quelques questions

en utilisant ta méthode, est-ce qu'il serait possible par exemple de préparer l'appel à la fonction en plusieurs parties?
je m'explique : quand la bibli recoit un pointeur de fonction, et ses paramètres je ne peux pas tout faire directement sinon il me faudrait du code assembleur pour chaque cas.
Ce que je voudrais avoir au final serait un mélange de C(++) et d'asm pour empiler dynamiquement mes paramètres en fonction de ceux qui me sont demandés

ex:
param=0
boucle
switch(param)
si (param = char)
code_assembleur_pour_pusher_char
si (param = int)
code_assembleur_pour_pusher_int
etc....
fin switch
param++
si (param = nb_param) quitter_la_boucle
fin_boucle
code_assembleur_pour_appeler_la_fonction
code_assembleur_pour_nettoyer_la_pile_a_la_fin_de_l_appel_de_la_fonction

est-ce que cette solution peut marcher dans une DLL en sachant que les utilisateurs donnent les fonctions a appeler une fois la DLL compilée (donc elle ne sait rien avant)?

merci d'avance
0
kilian Messages postés 8731 Date d'inscription vendredi 19 septembre 2003 Statut Modérateur Dernière intervention 20 août 2016 1 527
9 nov. 2008 à 19:06
Wep à priori il devrait pas y avoir de problème.
0
@xi@g@me Messages postés 68 Date d'inscription lundi 2 juin 2008 Statut Membre Dernière intervention 25 septembre 2018 4
9 nov. 2008 à 19:19
ok merci je vous tiens au jus
+++
0