Comment un programme C peut-il démarrer?En C, comment la méthode main() est-elle initialement appelée?
Répondre
Finalement, c'est le système d'exploitation. Habituellement, il y a un certain milieu entre le point d'entrée réel et la fonction principale, ceci est inséré par
compilateur
lieur. Quelques détails (liés à Windows): Il y a un en-tête dans le fichier PE appelé IMAGE_OPTIONAL_HEADER
qui a le champ AddressOfEntryPoint
, qui est à son tour l'adresse du premier octet de code dans le fichier qui sera exécuté.
Il n'est pas inséré par le compilateur, il est inséré par l'éditeur de liens, généralement en liant quelque chose comme 'crt.a (crt .o) 'ou' crt.lib (crt.obj) ', qui fait généralement partie de quelque chose comme' libc.a' ou 'c.lib'. –
@ ChristianHujer vous avez raison, par compilateur je voulais dire bien la chaîne d'outils. – Andrey
vous sûr de __linker__, je suppose que __loader__ fait alors? – roottraveller
Le système d'exploitation appelle la fonction main()
. En fait, il appelle généralement quelque chose d'autre nommé une chose étrange comme _init
. Le compilateur C relie une bibliothèque standard à chaque application qui fournit ce point d'entrée défini par le système d'exploitation, puis appelle main()
. Edit: De toute évidence, ce n'était pas détaillé et correct pour certaines personnes.
Le Executable and Linkable Format (ELF) que de nombreux systèmes d'exploitation Unix utilisent définit une adresse de point d'entrée. C'est là que le programme commence à s'exécuter après que l'OS a terminé son appel exec()
. Sur un système Linux, c'est _init.
De objdump -d:
Disassembly of section .init:
08049f08 <_init>:
8049f08: 55 push %ebp
8049f09: 89 e5 mov %esp,%ebp
8049f0b: 83 ec 08 sub $0x8,%esp
8049f0e: e8 a1 05 00 00 call 804a4b4 <call_gmon_start>
8049f13: e8 f8 05 00 00 call 804a510 <frame_dummy>
8049f18: e8 d3 50 00 00 call 804eff0 <__do_global_ctors_aux>
8049f1d: c9 leave
8049f1e: c3 ret
De readelf -d:
0x00000001 (NEEDED) Shared library: [libstdc++.so.6]
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libpthread.so.0]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x8049f08
0x0000000d (FINI) 0x804f018
0x00000004 (HASH) 0x8048168
0x00000005 (STRTAB) 0x8048d8c
0x00000006 (SYMTAB) 0x804867c
0x0000000a (STRSZ) 3313 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x8059114
0x00000002 (PLTRELSZ) 688 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8049c58
0x00000011 (REL) 0x8049be0
0x00000012 (RELSZ) 120 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x8049b60
0x6fffffff (VERNEEDNUM) 3
0x6ffffff0 (VERSYM) 0x8049a7e
0x00000000 (NULL) 0x0
Vous pouvez voir que INIT est égale à l'adresse de _init.
Le code pour frame_dummy et __do_global_ctors_aux se trouve dans un ensemble de fichiers nommés crtbegin.o et crtend.o (et les variantes de ces noms). Ils font partie de GCC. Ce code fait diverses choses nécessaires pour un programme C comme la configuration des variables stdin, stdout, globales et statiques et d'autres choses.
L'article suivant décrit très bien ce qu'il fait sous Linux (tiré d'une réponse ci-dessous avec moins de voix): http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html
Je crois que quelqu'un d'autre réponse déjà décrit ce que Windows fait.
Notez que, en plus des réponses déjà affichée, il est également possible pour vous d'appeler vous-même main
. Généralement c'est une mauvaise idée réservée au code obscurci.
Ce n'est pas légal en C++, en passant - une autre façon dont C++ n'est pas un sur-ensemble strict. –
Les appels du système d'exploitation principal. Il y aura une adresse dans l'exécutable relocalisable qui pointe à l'emplacement de main (voir l'ABI Unix pour plus d'informations).
Mais, qui appelle le système d'exploitation? L'unité de traitement centrale, sur le signal "RESET" (qui est également affirmé à la mise sous tension), commencera à chercher dans une certaine ROM à une adresse donnée (par exemple, 0xffff) pour ses instructions.
Typiquement, il y aura une sorte d'instruction de saut sur le BIOS, ce qui permet de configurer les puces de mémoire, les pilotes de disque dur de base chargés, etc., etc.Ensuite, le secteur de démarrage du disque dur est lu, et le suivant bootloader est démarré, qui charge le fichier contenant les informations de base sur la façon de lire, disons, une partition NTFS et comment lire le fichier noyau lui-même. L'environnement du noyau sera mis en place, le noyau chargé, puis - et ensuite! - le noyau sera sauté pour l'exécution.
Après tout ce dur travail a été fait, le noyau peut alors procéder au chargement de notre logiciel.
Le système d'exploitation appelle une fonction incluse dans le runtime C (CRT) et liée dans votre exécutable. Appelez cela "CRT principal". CRT principal fait quelques choses, dont les deux plus importantes, au moins en C++, sont de parcourir un tableau de classes C++ globales et d'appeler leurs constructeurs, et d'appeler votre fonction main() et de donner son retour valeur à la coquille.
Le principal CRT Visual C++ fait un peu plus de choses, si la mémoire sert. Il configure l'allocateur de mémoire, important si vous utilisez le CRT de débogage pour vous aider à trouver des fuites de mémoire ou de mauvais accès. Il appelle également principal dans un gestionnaire structured exception qui attrape l'accès de mémoire défectueux et d'autres accidents et les affiche.
Même si vous parlez de C++ et non de C, votre message est éclairant! –
Probablement la meilleure information pour votre question peut être trouvé dans le lien ci-dessous http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html, le meilleur que j'ai rencontré jusqu'à date.
C'est génial! Merci beaucoup! –
- 1. La méthode Objective-C n'est pas appelée
- 2. Pourquoi ma méthode C# n'est pas appelée?
- 3. méthode invoquée ou méthode appelée?
- 4. Combien d'arguments a main() en C/C++
- 5. C++ - arguments à la main
- 6. initialisation de la Force singleton en C++ avant main()
- 7. méthode est appelée
- 8. Fonctions d'appel de main() en C++
- 9. Comment savoir où la méthode javascript est définie et quelle méthode est appelée en utilisant firebug
- 10. Struts quelle méthode est appelée?
- 11. Pourquoi la méthode drawRect n'est pas appelée?
- 12. Pourquoi gprof me dit qu'une fonction appelée une seule fois par main() est appelée 102 fois?
- 13. Afficher la classe Main() en cours d'appel? Comment?
- 14. Initialisation d'un vecteur avant main() en C++
- 15. Méthode WCF appelée deux fois
- 16. Comment obtenir le premier paramètre dans main() en C++?
- 17. comment éviter d'écrire main() trop de fois en C?
- 18. Ruby: quelle méthode est appelée?
- 19. Java Résumé Classe Confusion: la méthode substituée n'est pas appelée
- 20. La meilleure méthode pour avoir une fonction membre C++ est appelée par un rappel C?
- 21. En utilisant Moq pour vérifier qu'une méthode a été appelée
- 22. Comment tester si une méthode de service fluide est appelée
- 23. Paramétrage de la méthode en C#
- 24. DataGridView n'appelle pas la méthode Paint lorsque InvalidateCell est appelée
- 25. Comment la méthode générique appelée peut-elle connaître le type de la déclaration générique?
- 26. Quelle est la syntaxe C# appelée?
- 27. Pourquoi la méthode handle_read n'est-elle pas appelée avec asyncore?
- 28. Transmission des paramètres à la méthode appelée par un NSTimer
- 29. Comment accéder aux paramètres de ligne de commande en dehors de Main en C#
- 30. Obtention d'arguments d'une méthode appelée par Typemock
Vous faites! Vous appelez le principal()! Oui c'est vrai! Oui vous faites! – recursive
Qui regarde les observateurs? – Cascabel
Le sujet est une déclaration mais le corps est une question. –