bonjour à tous,
J'essaye de récupérer l'adresse de retour stockée dans la pile puis de faire un jump sur cette adresse afin de revenir à mon main, je vous montre mon code puis vous explique ma démarche :
int addOne ( int value )
{
char * ptr = (char*)&value; // la variable value est situé a RBP-0x14
void (*adresseDeRetour) (void) = (ptr + 28);
adresseDeRetour();
return ++value; //on arrive jamais ici
}
int main (int argc, char **argv)
{
printf("coucou\n");
int v = addOne(65);
return 0;
}
en regardant via la commande : objdump -M intel -DTCs ./a.out , on voit que ma variable value est stocké à la position RBP-0x14, donc je fais un (ptr + 20) afin d'etre au niveau du RBP qui est stocké dans la RAM, puis je fais + 8 (car RBP est un registre de 8 octet afin de récupérer l'adresse de retour, d'ou le (ptr + 28). Puis je fais adresseDeRetour() afin de ratterrir dans mon main() mais j'ai en sortie :
coucou
Erreur de segmentation
Pour moi au niveau de la RAM quand la fonction addOne est appelé, le processeur fait :
->on stock l'adresse de retour
->on stock RBP
->j'ajoute les arguments de la fonction …
avez vous une idée de comment faire ?
merci d'avance pour votre aide
# .
Posté par beaulieu1 . Évalué à 8.
Salut,
Le plus simple est d'ajouter un niveau d'indirection à adresseDeRetour :
Sinon ton appel saute dans la pile (à l'adresse où se trouve l'adresse de retour).
Autre problème : tu ne restaures pas le cadre de pile de l'appelant. Quand tu rends la main à main() (pour ainsi dire), on reste dans addOne() en réalité et à la fin de main(), on revient après l'appel de addOne(). Ajoute un printf("coucou2\n"); après l'appel à addOne() et tu verras que "coucou2" sera affiché deux fois.
[^] # Re: .
Posté par beaulieu1 . Évalué à 4.
Et bien sûr, tu adaptes l'appel :
(*adresseDeRetour)();
[^] # Re: .
Posté par cosmoff . Évalué à 1.
yes merci énormément pour ta reponse t'as dit tout ce dont j'avais besoin de savoir !
# setjmp et longjmp
Posté par koopa . Évalué à 3.
Plutôt que de bidouiller la pile à la main, tu devrais utiliser les fonctions C,
setjmp()
etlongjmp()
qui sont faites pour ça. Elles permettent de faire un nonlocal goto.http://manpagesfr.free.fr/man/man3/setjmp.3.html
[^] # Re: setjmp et longjmp
Posté par cosmoff . Évalué à 1.
merci pour ta réponse, alors oui c'est du bidouillage mais c'est dans le but de me faire progresser avec le fonctionnement des pointeurs et de la logique de fonctionnement du code
[^] # Re: setjmp et longjmp
Posté par Anthony Jaguenaud . Évalué à 4.
Je ne vois pas le lien entre jouer dans la pile et apprendre les pointeurs.
Le format de la pile, qui dépend de l’ABI du langage et de la plateforme ne sont intéressant qu’en debug ou si on écrit un module en assembleur… à la rigueur pour https://www.root-me.org/ aussi ça peut servir.
Sur du x86, le retour de la fonction, est plutôt (à ma connaissance) contenue dans le registre
AX
enfin maintenant c’estEAX
ouRAX
pour tout ce qui est en dessous de 64bits.[^] # Re: setjmp et longjmp
Posté par Anthony Jaguenaud . Évalué à 2. Dernière modification le 24 juillet 2020 à 14:22.
La valeur de retour dans la pile doit être juste avant
ptr
.Mais ça ne marchera pas car tes registres
SP
etBP
ne seront pas remis à jour correctement.En gros si ça marchait, tu irais finir
main
puis au retour demain
tu retournerais dansaddOne
pour la finir pour retourner encore dansmain
.Avec l’aléa que l’accès à la variable
v
du main est relative auBP
courant… donc tu jardines probablement la pile n’importe où, donc là ou ça casse une adresse de retour.Édit: en fait baulieu à déjà répondu. J’avais lu trop vite.
# appel recursif infini
Posté par moi1392 . Évalué à 2. Dernière modification le 24 juillet 2020 à 14:16.
Ce que tu fais n'est pas un retour à l'appellant, mais un appel de fonction, dans le cas où ton appel serait correct (voir le commentaire de beaulieu1), l'instruction "adresseDeRetour();" aurait pour effet d'appeler la fonction "main", qui à son tour appellerait la fonction "addOne", qui appellerait "main"… jusqu'à ce que ton programme finisse par être tué pour un débordement de pile.
[^] # Re: appel recursif infini
Posté par cosmoff . Évalué à 1.
le programme marche tres bien et il n'y a aucun débordement pile, il se termine correctement.
[^] # Re: appel recursif infini
Posté par moi1392 . Évalué à 2.
effectivement je l'ai lu un peu vite.
ton appel te revoie à la troisième ligne du main (à peu près, à voir dans le code assembleur généré comment a été faite l'affectation de la valeur de retour à v), qui du coup fait un return 0 qui te fait revenir juste après l'appel adresseDeRetour() et tu reviens vers main avec le return ++value; et ton programme se termine.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.