J’essaie de comstackr et d’exécuter le programme suivant sans fonction main()
dans C
J’ai compilé mon programme en utilisant la commande suivante.
gcc -nostartfiles nomain.c
Et le compilateur donne un avertissement
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400340
Ok, pas de problème. Ensuite, j’ai exécuté le fichier exécutable (a.out), les deux instructions printf
imprimées avec succès, puis elles ont généré une erreur de segmentation .
Donc, ma question est la suivante: pourquoi la segmentation des erreurs après une exécution réussie des instructions d’impression?
mon code:
#include void nomain() { printf("Hello World...\n"); printf("Successfully run without main...\n"); }
sortie:
Hello World... Successfully run without main... Segmentation fault (core dumped)
Remarque:
Ici, l’ -nostartfiles
gcc empêche le compilateur d’utiliser des fichiers de démarrage standard lors de la liaison
Regardons l’ assemblage généré de votre programme:
.LC0: .ssortingng "Hello World..." .LC1: .ssortingng "Successfully run without main..." nomain: push rbp mov rbp, rsp mov edi, OFFSET FLAT:.LC0 call puts mov edi, OFFSET FLAT:.LC1 call puts nop pop rbp ret
Notez la déclaration ret
. Le point d’entrée de votre programme est déterminé à être nomain
, tout va bien avec cela. Mais une fois que la fonction revient, elle tente de sauter dans une adresse de la stack d’appels … qui n’est pas renseignée. C’est un access illégal et une erreur de segmentation suit.
Une solution rapide serait d’appeler exit()
à la fin de votre programme (et en supposant que C11 nous pourrions aussi bien marquer la fonction comme _Noreturn
):
#include #include _Noreturn void nomain(void) { printf("Hello World...\n"); printf("Successfully run without main...\n"); exit(0); }
En fait, maintenant, votre fonction se comporte à peu près comme une fonction main
normale, car après le retour de main
, la fonction de exit
est appelée avec main
valeur de retour main
.
Dans C, lorsque des fonctions / sous-routines sont appelées, la stack est remplie comme (dans l’ordre):
main () étant le sharepoint départ, ELF structure le programme de manière à ce que les instructions soient envoyées en premier.
Maintenant, le programme est en quelque sorte tronqué sans return-address OR __end__
et en fait, il suppose que tout ce qui existe sur la stack à cet emplacement ( __end__
) est l’adresse de retour, mais malheureusement elle ne fonctionne pas.