Почему g cc по умолчанию связывает crtbegin.o и crtend.o с каждым скомпилированным исполняемым файлом - PullRequest
2 голосов
/ 11 марта 2020

Чтобы понять, что можно сказать о входящем и выходящем из реализации POSIX lib c, я делал свой собственный в течение прошлого года или около того, покусывая края реализации единой Unix спецификации, которую я считал быть в моем наборе навыков, пытаясь наметить план движения вперед, и я подошел к моменту, когда следующим шагом будет создание библиотеки времени выполнения.

Теперь я пытаюсь понять логику c, объясняющую, как программы связаны с библиотекой времени выполнения c.

Чтение того, что руководство g cc также говорило о инициализации как текст формата elf и некоторые текстовые сообщения во встроенных системах, я в основном узнал, что код инициализации находится в своих собственных разделах .init и .fini, что crti.o и crtn.o обычно содержат заглушки функций crtbegin и crtend fle sh, вызывая серию функций, указанных в списке указателей функций, которые должен определить скрипт компоновщика.

Это подводит меня к моим вопросам, предполагая, что приведенное выше обобщение является правильным, в чем заключается логика c, лежащая в основе разработки функций init и fini таким образом, в частности описанным ниже способом:

Пролог функции (__init) появляется в разделе .init crti.o; эпилог появляется в crtn.o. Аналогично для функции __fini в разделе .fini. Обычно эти файлы предоставляются операционной системой или библиотекой GNU C, но предоставляются G CC для нескольких целей. Объекты crtbegin.o и crtend.o (для большинства целей) скомпилированы из crtstuff. c. Они содержат, среди прочего, фрагменты кода в разделах .init и .fini, которые переходят к подпрограммам в разделе .text. Компоновщик соберет все части раздела вместе, что приведет к полной функции __init, которая вызывает подпрограммы, которые нам нужны при запуске.

Почему бы функциям библиотеки init и fini просто не вызвать прямой вызов функции инициализации и уничтожения библиотеки напрямую вместо перечисления их в сценарии компоновщика и распределения битов раздела по нескольким объектным файлам?

Кроме того, откуда берутся функции, перечисленные в списке компоновщика. Из приведенной ниже цитаты я предполагаю, что эти функции определены c для crt, чтобы сказать, ассоциировать дескрипторы файла std [in, out, err] с файловыми потоками или инициализировать переменную locale_t равной C locale et c , если это тот случай, когда эти функции хранятся.

Компоновщик должен создать два списка этих функций - список функций инициализации, называемый CTOR_LIST , и список завершения функции, называемые DTOR_LIST .

1 Ответ

0 голосов
/ 11 марта 2020

Почему бы функциям init и fini библиотеки просто напрямую вызывать функции инициализации и уничтожения библиотеки вместо того, чтобы перечислять их в сценарии компоновщика и распределять биты раздела по нескольким объектным файлам?

Они не могут вызывать функции напрямую, потому что не знают функций для вызова. Чтобы знать это, они должны быть сгенерированы во время соединения, что, по сути, является тем, чем они являются: генерируется компоновщиком, объединяющим разделы с одинаковыми именами.

Однако все это есть или, по крайней мере, должно быть, нерелевантная ерунда. В течение десятилетий .{init,fini}_array разделы с __{init,fini}_array_{start,end} символами или DT_{INIT,FINI}_ARRAY _DYNAMIC тегами, указывающими на них, повторяемые кодом, предоставленным в libc / ldso, были правильным способом создания ctors / dtors. Но стартовые файлы G CC (crt{begin,end}*.o) все еще существуют, чтобы делать грязные, в значительной степени неправильные вещи для инициализации их (удаленных) Java времени выполнения, библиотеки транзакционной памяти, таблиц размотки и т. Д. c.

...