При создании встроенного программного обеспечения встроенного программного обеспечения для запуска непосредственно из ПЗУ, я часто избегаю называть точку входа main()
, чтобы подчеркнуть рецензенту кода особый характер кода.В этих случаях я предоставляю настроенную версию модуля запуска среды выполнения C, так что его вызов на main()
легко заменить другим именем, например BootLoader()
.
I (или моим поставщиком).почти всегда приходится настраивать запуск среды выполнения C в этих системах, поскольку для ОЗУ нередко требуется код инициализации для правильной работы.Например, типичные микросхемы DRAM требуют удивительного количества конфигурации своего управляющего оборудования и часто требуют значительной (тысячи тактов шины) задержки, прежде чем они будут полезны.Пока это не будет завершено, может даже не быть места для размещения стека вызовов, поэтому код запуска может не вызывать какие-либо функции.Даже если устройства ОЗУ работают при включении, почти всегда имеется некоторое количество аппаратного обеспечения для выбора микросхемы или ПЛИС или двух, которым требуется инициализация, прежде чем можно будет безопасно запустить среду инициализации C.
Когдапрограмма, написанная на языке C, загружается и запускается, некоторый компонент отвечает за создание среды, в которой вызывается main()
.В Unix, Linux, Windows и других интерактивных средах большая часть этих усилий является естественным следствием компонента ОС, который загружает программу.Однако даже в этих средах необходимо выполнить определенную работу по инициализации, прежде чем можно будет вызвать main()
.Если код действительно C ++, тогда может потребоваться значительный объем работы, который включает в себя вызов конструкторов для всех экземпляров глобальных объектов.
Подробности всего этого обрабатываются компоновщиком и его файлами конфигурации и управления,Компоновщик ld (1) имеет очень сложный управляющий файл, в котором точно указано, какие сегменты включить в вывод, по каким адресам и в каком порядке.Поиск управляющего файла компоновщика, который вы неявно используете для своей цепочки инструментов, и чтение его могут быть поучительными, как и справочное руководство для самого компоновщика и стандарта ABI, которым должны следовать ваши исполняемые файлы.
Редактировать: Чтобы более прямо ответить на вопрос, заданный в более общем контексте: «Можете ли вы называть foo вместо main?»Ответ: «Может быть, но только из-за хитрости».
В Windows исполняемый файл и DLL имеют практически одинаковый формат файла.Можно написать программу, которая загружает произвольную DLL-библиотеку с именем во время выполнения, находит в ней произвольную функцию и вызывает ее.Одна такая программа на самом деле поставляется как часть стандартного дистрибутива Windows: rundll32.exe
.
Поскольку файл .EXE можно загружать и проверять с помощью тех же API, которые обрабатывают файлы .DLL, вВ принципе, если в .EXE есть раздел EXPORTS с именем функции foo
, то для ее загрузки и вызова можно написать аналогичную утилиту.Конечно, вам не нужно делать ничего особенного с main
, поскольку это будет естественной точкой входа.Конечно, среда выполнения C, которая была инициализирована в вашей утилите, может отличаться от среды выполнения C, которая была связана с вашим исполняемым файлом.(Google для «DLL Hell» для подсказки.) В этом случае ваша утилита может быть умнее.Например, он может выступать в качестве отладчика, загружать EXE-файл с точкой останова на main
, запускать до этой точки останова, а затем изменять ПК так, чтобы он указывал на или на foo
, и продолжать оттуда.
Некоторый подобный обман может быть возможен в Linux, так как .so файлы также похожи в некоторых отношениях на настоящие исполняемые файлы.Конечно, подход, действующий как отладчик, можно заставить работать.