В C как изначально вызывается метод main ()? - PullRequest
49 голосов
/ 12 августа 2010

Как запускается программа на C?

Ответы [ 7 ]

46 голосов
/ 12 августа 2010

Операционная система вызывает функцию main().На самом деле, он обычно называет что-то еще, называемое странной вещью, такой как _init.Компилятор C связывает стандартную библиотеку с каждым приложением, которое предоставляет эту точку входа, определяемую этой операционной системой, и затем вызывает main().

Редактировать: Очевидно, что это было недостаточно подробным и правильным для некоторых людей.

Исполняемый и связываемый формат (ELF) , который используется многими ОС Unix, определяет адрес точки входа.Вот где программа начинает работать после того, как ОС завершает свой вызов exec().В системе Linux это _init.

Из 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    

Из 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

Вы можете видеть, что INIT равенадрес _init.

Код для frame_dummy и __do_global_ctors_aux находится в наборе файлов с именами crtbegin.o и crtend.o (и вариантами этих имен).Это часть GCC.Этот код выполняет различные функции, необходимые для программы на Си, например, устанавливает stdin, stdout, глобальные и статические переменные и другие.

Следующая статья довольно хорошо описывает, что она делает в Linux (взято из ответа ниже с меньшимголосов): http://dbp -consulting.com / tutorials / debugging / linuxProgramStartup.html

Я полагаю, что чей-то ответ уже описал действия Windows.

24 голосов
/ 12 августа 2010

В конце концов это операционная система. Обычно существует некоторая среда между реальной точкой входа и основной функцией, которая вставляется компилятором .

Некоторые подробности (относящиеся к Windows): В PE-файле есть заголовок IMAGE_OPTIONAL_HEADER, который имеет поле AddressOfEntryPoint, которое, в свою очередь, является адресом первого байта кода в файле, который будет выполняться.

9 голосов
/ 12 августа 2010
6 голосов
/ 12 августа 2010

Операционная система вызывает main. В перемещаемом исполняемом файле будет указан адрес, который указывает на местоположение main (дополнительную информацию см. В Unix ABI).

Но , кто вызывает операционную систему?

Центральный процессор на сигнале «СБРОС» (который также включается при включении питания) начнет искать в каком-либо ПЗУ по указанному адресу (скажем, 0xffff) свои инструкции.

Обычно в BIOS выполняется какая-то инструкция перехода, которая настраивает микросхемы памяти, загружает основные драйверы жесткого диска и т. Д. И т. Д. Затем читается загрузочный сектор жесткого диска и next запускается загрузчик, который загружает файл, содержащий основную информацию о том, как читать, скажем, раздел NTFS и как читать сам файл ядра. Среда ядра будет настроена, ядро ​​загружено, а затем - , а затем! - ядро ​​будет переключено на выполнение.

После всей этой тяжелой работы ядро ​​может приступить к загрузке нашего программного обеспечения.

5 голосов
/ 12 августа 2010

Операционная система вызывает функцию, включенную в среду выполнения C (CRT) и связанную с вашим исполняемым файлом. Назовите это "CRT main."

CRT main делает несколько вещей, две наиболее важные из которых, по крайней мере в C ++, должны проходить через массив глобальных классов C ++ и вызывать их конструкторы, а также вызывать функцию main () и возвращать ее возвращаемое значение. в оболочку.

Visual C ++ CRT main делает еще несколько вещей, если память служит. Он настраивает распределитель памяти, что важно при использовании Debug CRT, чтобы помочь найти утечки памяти или неправильный доступ. Он также вызывает main в обработчике структурированных исключений , который фиксирует неправильный доступ к памяти и другие сбои и отображает их.

4 голосов
/ 17 февраля 2014

Вероятно, лучшая информация для вашего вопроса может быть найдена в указанной ниже ссылке http://dbp -consulting.com / tutorials / debugging / linuxProgramStartup.html , лучшая, с которой я сталкивался до настоящего времени.

4 голосов
/ 12 августа 2010

Обратите внимание, что помимо уже опубликованных ответов, вы также можете позвонить main самостоятельно.Обычно это плохая идея, зарезервированная для запутанного кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...