Вызов вилки перед основным

Позволяет ли стандарт POSIX вызывать fork() до main() - например, в экземпляре С++ static или в функции __attribute__((constructor)) C?

Ответы

Ответ 1

В управляющей странице fork нет указаний, которые запрещены, и я не могу думать о причине, чтобы это было.

В самом деле, нет ничего особенного в отношении main в отношении POSIX; это просто, что C решает начать свои программы в функции с этим именем, а С++ почти почти то же самое. Но что касается POSIX, то, как только ваш процесс завершен, ваш процесс завершен. Это могло быть написано на любом старом языке, и fork все равно придется работать.

В C (не С++!) Это невозможно для вас, чтобы написать код, который выполняется перед main (потому что инициализаторов для static переменные должны быть постоянными в этом контексте), так что для C это немного спорный вопрос, Однако, выходя за пределы абстракции C на мгновение, в POSIX по-прежнему нет ничего, что помешало бы вашему компилятору включить код во время выполнения C, который выполняет fork перед входом main. Напомним, что "истинная" точка входа на самом деле не является main; "истинная" точка входа выполняет некоторые инициализации библиотеки и еще до вызова main, чтобы начать вашу часть программы.

Ответ 2

Позволяет ли стандарт POSIX вызывать fork() до main() [...]?

Это зависит от того, что вы имеете в виду.

Программы C

POSIX посредством включения стандарта C указывает, что запуск программы C происходит, когда среда (операционная система) вызывает main(). Определенная POSIX семантика программы C начинается с этой точки; по определению, они не включают предварительные вызовы любой другой функции. Если такие вызовы действительно происходят, то они не являются частью "программы" в этом смысле, поэтому программа не может вызывать fork() до main().

С другой стороны, POSIX явно не запрещает процесс, в котором программа C запускает выполнение fork() или любую другую функцию до начала определенной семантики C. В том смысле, что то, что запрещено, разрешено POSIX. Если ваш вопрос о том, нарушают ли GCC __attribute__((constructor)) или подобные объекты POSIX, то нет, они не делают, хотя их поведение не определяется POSIX.

С другой стороны, POSIX не дает утвердительного разрешения и не указывает, каким образом исходный код C указывает, что это должно произойти. Если ваш вопрос касается того, определяет ли POSIX конкретное средство, которое __attribute__((constructor)) или аналогичные средства используют для обеспечения своего рекламируемого поведения, или требует ли оно, чтобы соответствующие системы должны обеспечивать механизм, с помощью которого такие объекты могут работать, тогда нет, это не, Не предоставление такого механизма не по своей сути приведет к тому, что система не сможет соответствовать POSIX.

Программы на С++

POSIX определяется в терминах командного языка оболочки и ISO C. Он не требует реализаций для поддержки любой поддержки на С++, но, конечно же, это не запрещает. Таким образом, второй и третий параграфы предыдущего раздела относятся ко всем аспектам программ на С++.

Для того, что стоит, однако, как C, С++ указывает, что программы начинаются с main(). Это имеет аналогичный смысл в С++, как в C, но в отличие от C, С++-реализации могут предоставить механизмы, с помощью которых пользовательский код может быть запущен до первого оператора main(). В частности, конструктор переменной со статической продолжительностью может работать до того, как будет выполнен первый оператор main(), но независимо от того, выполняет ли он его выполнение (С++ 11, 3.6.2/4). Поэтому в этом смысле определяется реализация, независимо от того, может ли семантика программы С++ включать вызов fork() перед первым выражением main().

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

Другие программы

POSIX еще меньше говорит о других видах программ, чем о программах на С++, за исключением сценариев оболочки. Конечно, сценарии оболочки вообще не имеют main() вообще, и у них нет прямого доступа к библиотеке C, для которой явно fork().

Ответ 3

Вы можете использовать fork с момента полной загрузки и инициализации libc.

Простая тестовая программа может показать, что это верно:

 #include <stdio.h>

 void before(void) __attribute__ (( constructor ));
 void after(void) __attribute__ (( destructor ));

 int main(void)
 {
   puts("main");

   return 0;
 }

 void before(void)
 {
   puts("before");
 }

 void after(void)
 {
   puts("after");
 }

Вывод:

 $ LD_DEBUG=files ./a.out
      26032:    
      26032:    file=libc.so.6 [0];  needed by ./a.out [0]
      26032:    file=libc.so.6 [0];  generating link map
      26032:      dynamic: 0x00007f58c7703ba0  base: 0x00007f58c7341000   size: 0x00000000003c8a00
      26032:        entry: 0x00007f58c7361950  phdr: 0x00007f58c7341040  phnum:                 10
      26032:    
      26032:    
      26032:    calling init: /lib/x86_64-linux-gnu/libc.so.6
      26032:    
      26032:    
      26032:    initialize program: ./a.out
      26032:    
 before
      26032:    
      26032:    transferring control: ./a.out
      26032:    
 main
      26032:    
      26032:    calling fini: ./a.out [0]
      26032:    
 after

Загружена библиотека, выполнена инициализация, поэтому она должна быть безопасной для использования fork с функцией тегов с конструктором.