2010-08-12 5 views

Répondre

23

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é.

+1

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'. –

+0

@ ChristianHujer vous avez raison, par compilateur je voulais dire bien la chaîne d'outils. – Andrey

+0

vous sûr de __linker__, je suppose que __loader__ fait alors? – roottraveller

38

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.

+2

'__start', woo. – strager

+4

il n'appelle pas '_init' ou tout autre. il appelle l'adresse du point d'entrée. ça peut être n'importe où. – Andrey

+0

NÉCESSAIRE libstdC++. So.6? Ce n'est pas un programme C! – Jens

4

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.

+4

Ce n'est pas légal en C++, en passant - une autre façon dont C++ n'est pas un sur-ensemble strict. –

6

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.

5

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.

+0

Même si vous parlez de C++ et non de C, votre message est éclairant! –

Questions connexes