Как система (Windows, Linux, Mac OS X) вызывает функцию main() в программе C/C++?
Вопрос
Я ищу более техническое объяснение, чем ОС вызывает функцию.Может ли кто-нибудь мне помочь или указать на веб-сайт или книгу?
Решение
Файл .exe (или его эквивалент на других платформах) содержит адрес «точки входа».В первом приближении ОС загружает соответствующие разделы файла .EXE в оперативную память, а затем переходит к точке входа.
Как говорили другие, эта точка входа не будет «основной», а будет частью библиотеки времени выполнения — она будет выполнять такие действия, как инициализация статических объектов, настройка параметров argc/argv, настройка stdin/stdout/stderr. , и т. д.Когда все это будет сделано, он вызовет вашу функцию main().При выходе из main среда выполнения выполняет аналогичный процесс передачи вашего кода возврата обратно в среду, вызова статических деструкторов, вызова подпрограмм _atexit и т. д.
Если у вас есть инструменты MS (возможно, не бесплатные), то у вас есть весь исходный код среды выполнения, и простой способ просмотреть его — поставить точку останова на закрывающую скобку вашего метода main() и выполнить один шаг назад. во время выполнения.
Другие советы
main()
является частью библиотеки C и не является системной функцией.Я не знаю, для OS X или Linux, но Windows обычно запускает программу с WinMainCRTStartup()
.Этот символ запускает ваш процесс, извлекает аргументы командной строки и среду (argc, argv, end
) и звонки main()
.Он также отвечает за вызов любого кода, который должен выполняться после main()
, нравиться atexit()
.
Просматривая файл Visual Studio, вы сможете найти реализацию по умолчанию. WinMainCRTStartup
чтобы увидеть, что он делает.
Вы также можете определить собственную функцию для вызова при запуске, это делается путем изменения «точки входа» в параметрах компоновщика.Часто это функция, которая не принимает аргументов и возвращает пустое значение.
Что касается окон, функции точки входа:
- Консоль:
void __cdecl mainCRTStartup( void ) {}
- Графический интерфейс:
void __stdcall WinMainCRTStartup( void ) {}
- ДЛЛ:
BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved) {}
Единственная причина использовать их вместо обычного main/WinMain/DllMain — это если вы хотите использовать свою собственную библиотеку времени выполнения (если вам нужен файл меньшего размера или пользовательские функции)
О пользовательских реализациях времени выполнения и других приемах получения PE-файлов меньшего размера см.:
Эксперт C++/CLI (см. стр. 279) содержит очень подробные сведения о различных сценариях начальной загрузки для собственных, смешанных и чистых сборок CLR.
Это зависит от ОС.В OS X в мах-заголовке есть кадр, содержащий начальный адрес регистра EIP (указатель инструкций).
После загрузки двоичного файла ОС запускает выполнение с этого адреса:
cristi:test diciu$ otool -l ./a.out | grep -A 10 LC_UNIXTHREAD cmd LC_UNIXTHREAD cmdsize 80 flavor i386_THREAD_STATE count i386_THREAD_STATE_COUNT [..] ss 0x00000000 eflags 0x00000000 eip 0x00001f8c cs 0x00000000 [..]
Адрес — это адрес функции «старт» из двоичного файла:
cristi:test diciu$ nm ./a.out 0000200c D _NXArgc 00002008 D _NXArgv 00002000 D ___progname 00001fe0 t __dyld_func_lookup 00001000 A __mh_execute_header [..] 00001f8c T start
В Mac OS X первой вызывается функция «start», даже до «main» функции:
(gdb) b start Breakpoint 1 at 0x1f90 (gdb) b main Breakpoint 2 at 0x1ff4 (gdb) r Starting program: /Users/diciu/Programming/test/a.out Reading symbols for shared libraries ++. done Breakpoint 1, 0x00001f90 in start ()
Если вас интересует книга, посвященная Windows и Win32 API, попробуйте
«Программирование приложений для Microsoft Windows» Джеффри Рихтера.
Вы можете посмотреть следующие ссылки: