IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Interfaçage C - Assembleur


Sujet :

C

  1. #1
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 11
    Points : 12
    Points
    12
    Par défaut Interfaçage C - Assembleur
    Bonjour,
    Etant débutant en assembleur (mais pas en langage C) je cherche pour des histoires de controle de flot d'execution un peu d'assembleur.
    Voila un des mes programmes de test qui ne fonctionne pas totalement.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
     
    void works(){
    	printf("Mon adresse: 0x%08x\n",works);
    	printf("That works !\n");
    	__asm__("jmp ici");
    }
     
     
    int main(int argc, char** argv){
    	int a=0;
    	__asm__("xor %bx,%bx");
    	__asm__("jz	works");
    	__asm__("ici:");
     
    	printf("Si je suis le premier c'est perdu...\n");
     
    	printf("Ok\n");
    	printf("%i\n",a);
    	return EXIT_SUCCESS;
    }
    Cependant voici mon probleme. Lorsque je lance mon binaire, j'obtient la sortie suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Mon adresse: 0x080483f4
    That works !
    Si je suis le premier c'est perdu...
    Ok
    -1215659260
    Erreur de segmentation
    Merci de votre aide.

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Salut

    Voici comment une fonction telle que celle-ci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void hello(void)
    {
    	printf("hello !");
    }
    est assemblée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	push	ebp
    	mov	ebp, esp
    	sub	esp, 8
    	mov	DWORD PTR [esp], OFFSET FLAT:LC0
    	call	_printf
    	leave
    	ret
    En fait, EBP est la base de la pile et ESP la position courante (l'adresse où la prochaine valeur sera empilée). Lorsqu'on lance une fonction, elle créée son propre cadre de pile ; elle positionne ESP au niveau de la position courante. Mais pour ne pas perdre la valeur d'origine d'EBP, elle l'empile d'abord. Car une fois que la fonction se termine, le cadre de pile revient à son stade précédent. EBP doit donc revenir à sa valeur d'origine.
    Ceci est important pour bien structurer l'exécution d'un programme, pour y mettre les variables locales et l'adresse retour. Appeler une fonction, c'est comme empiler une assiette. Si une fonction appelle une fonction, qui appelle elle-même une fonction, c'est comme si on empilait deux assiettes sur la première assiette. Lorsqu'une fonction prend fin, on retire l'assiette qui se trouve au sommet, et le microprocesseur exécute l'instruction qui suit l'appel de la fonction (celle d'où l'on vient).
    Chaque assiette contient ses propres données : les données locales et l'adresse de retour.

    Dans ton programme, tu appelles la fonction par un "jz" (qui est un jmp conditionnel et non un appel) et dans la fonction appelée tu reviens dans celle d'origine par un "jmp". Du coup, les données dans la pile ne sont plus cohérentes, c'est comme si il y avait un décalage. Ton plantage est dû au fait qu'une mauvaise valeur est dépilée et correspond probablement à une adresse retour.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2011
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2011
    Messages : 15
    Points : 23
    Points
    23
    Par défaut
    Lorsque une fonction C est lancé, elle se créé un cadre de pile. La cadre de pile de la fonction appelante est restitué lorsqu'un return est effectué, en faisant le "jmp ici", tu empêches la fonction de faire un return et donc de restituer le cadre de pile du main. Comme le C place les variables sur la pile et que le pointeur de pile n'est pas en bonne place au retour à ici, l'accès à a ne se fait pas au bon endroit d'où une erreur de segmentation.
    J'espère que ce raisonnement est juste, je ne suis pas un expert en assembleur.
    Bonne chance.

  4. #4
    Membre à l'essai
    Inscrit en
    Octobre 2006
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 11
    Points : 12
    Points
    12
    Par défaut
    Ok merci je vais tenter de voir comment je peux arranger ca. Merci pour ces réponses claires. C'est vrai que j'ai du mal a voir en assembleurs quels sont les registres que l'on peut manipuler sans crainte

  5. #5
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 81
    Points : 128
    Points
    128
    Par défaut
    Dans ce document sur l'Assembleur 8086, au chapitre 4 sur les sous-programmes (page 47), il y a le principe de fonctionnement expliqué en détail.

  6. #6
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Novembre 2009
    Messages : 91
    Points : 133
    Points
    133
    Par défaut
    plutot qu'un "jz => jmp", pourquoi ne pas directement utiliser les instructions d'appel /retour ( call => ret) de l'assembleur ?
    Il me semble qu'avec ces instructions, tes registres sont modifiés tout seuls sans que tu n'ai a les toucher toi même.

  7. #7
    Membre confirmé
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Al_th
    Il me semble qu'avec ces instructions, tes registres sont modifiés tout seuls sans que tu n'ai a les toucher toi même.
    Pas tout seul ! il faut que la fonction appelées le fasse.
    Et s'il y a des paramètres de passé à la fonction,
    Selon la convention d'appel de la fonction, c'est soit la fonction appelée qui retir les paramètres de la pile (appel standard) soit au code qui appelle la fonction de le faire (appel C).

  8. #8
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Novembre 2009
    Messages : 91
    Points : 133
    Points
    133
    Par défaut
    Pas tout seul ! il faut que la fonction appelées le fasse.
    Tient ?!
    Il me semblait que call empilait lui même l'adresse de l'execution suivante, et que ret dépilait l'adresse de retour et la mettait dans IP...

    Comme quoi, on en apprend tout les jours x)

  9. #9
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 400
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 400
    Points : 23 780
    Points
    23 780
    Par défaut
    « CALL » (ou les instructions équivalentes sur les autres microprocesseur, tel que JSR chez Motorola) empile effectivement l'adresse de retour avant de faire le saut et RET dépile la première chose qu'il trouve pour la placer dans le pointeur de programme.

    Par contre, ça n'empile pas les autres registres, et heureusement parce que ça finirait par faire beaucoup, et ce serait pénible pour renvoyer des infos. Seule exception, les interruptions (logicielles ou par IRQ) sauvegardent parfois, selon le micro-processeur, le contexte également.

    Ton appel de fonction avec des jump n'est certes pas propre, mais c'est plutôt le fait de modifier BX qui doit ficher la pagaille dans le reste du programme.

    Au passage, sur quel système d'exploitation travailles-tu et avec quel compilateur ? Parce qu'il est peu probable que tu travailles encore en mode réel 16 bits…

Discussions similaires

  1. Tutoriels, F.A.Q : la rubrique Assembleur de Developpez.com
    Par Alcatîz dans le forum Assembleur
    Réponses: 3
    Dernier message: 07/06/2007, 19h14
  2. [CR][ASP] interfaçage
    Par grosjej dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 15/04/2004, 10h20
  3. ecrire son OS (assembleur ??)
    Par Anonymous dans le forum Programmation d'OS
    Réponses: 9
    Dernier message: 25/11/2002, 19h25
  4. Random en Assembleur
    Par funx dans le forum Assembleur
    Réponses: 9
    Dernier message: 02/09/2002, 17h05
  5. Quel désassembleur/assembleur pour un exe Windows ?
    Par Anonymous dans le forum x86 32-bits / 64-bits
    Réponses: 6
    Dernier message: 17/04/2002, 10h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo