Что нужно для запуска процедуры C? - PullRequest
4 голосов
/ 04 января 2011

Цитирование из одной из книг по программированию Unix,

Когда ядро ​​выполняет программу на C, одна из функций exec вызывает специальную start-up routine.Эта функция вызывается до вызова основной функции.Исполняемый программный файл определяет эту подпрограмму как начальный адрес программы;это устанавливается редактором ссылок, когда он вызывается компилятором C.Эта процедура запуска принимает значения из ядра, аргументы командной строки и окружение и настраивает их так, чтобы основная функция вызывалась, как показано ранее.

Зачем нам нужен посредникstart-up routine.Функция exec могла бы сразу вызывать функцию main, а ядро ​​могло напрямую передавать аргументы командной строки и окружение в функцию main.Зачем нам нужен режим запуска между ними?

Ответы [ 4 ]

9 голосов
/ 04 января 2011

Потому что в C нет понятия «подключи».Поэтому, если вы хотите использовать, скажем, malloc(), кто-то должен инициализировать необходимые структуры данных.Программисты C были ленивы и не хотели постоянно писать такой код:

main() {
    initialize_malloc();
    initialize_stdio();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();
    initialize_...();

    ... oh wow, can we start already? ...
}

Так что компилятор C выясняет, что нужно сделать, генерирует необходимый код и все настраиваеттак что вы можете сразу начать с вашего кода.

5 голосов
/ 04 января 2011

Вызов main() - это вещь C, в то время как вызов _start() - вещь ядра, указанная точкой входа в заголовке двоичного формата. (для ясности: ядро ​​не хочет или не должно знать, что мы называем это _start)

Если бы у вас был бинарный файл, отличный от C, у вас, возможно, не было бы функции main(), у вас вообще не было бы понятия «функция».

Таким образом, фактический вопрос будет таким: почему компилятор не дает адрес main() в качестве отправной точки? Это потому, что типичные реализации libc хотят выполнить некоторые инициализации перед тем, как действительно запустить программу, см. Другие ответы для этого.

изменить в качестве примера, вы можете изменить точку входа следующим образом:

$ cat entrypoint.c 
int blabla() { printf("Yes it works!\n"); exit(0); } 
int main() { printf("not called\n"); }

$ gcc entrypoint.c -e blabla

$ ./a.out 
Yes it works!
5 голосов
/ 04 января 2011

Процедура запуска инициализирует CRT (т.е. создает кучу CRT, так что malloc / free работает, инициализирует стандартные потоки ввода / вывода и т. Д.); в случае C ++ он также вызывает конструкторы глобалов. Могут быть другие специфичные для системы настройки, вам следует проверить источники вашей библиотеки времени выполнения для получения более подробной информации.

0 голосов
/ 18 января 2011

Важно также знать, что прикладная программа выполняется в пользовательском режиме, и любая система вызывает, устанавливает привилегированный бит и переходит в режим ядра. Это помогает повысить безопасность ОС, предотвращая доступ пользователей к системным вызовам уровня ядра и множеству других сложностей. Таким образом, вызов printf будет перехватывать, устанавливать бит режима ядра, выполнять код, затем возвращаться в режим пользователя и возвращаться в ваше приложение.

CRT требуется, чтобы помочь вам и позволить вам использовать языки, которые вы хотите в Windows и Linux. он обеспечивает очень фундаментальную загрузку ОС, чтобы предоставить вам наборы функций для разработки.

...