__attribute __ ((конструктор)) путаница в порядке вызова

Ответ здесь демонстрирует, что __attribute __ ((конструктор)) не называется после статической инициализации он вызывается в порядке объявления.

Тогда какова его цель, если ее вызов не гарантируется, когда все данные инициализированы? Мы также могли бы иметь наш ((конструктор)) код в конструкторе Foo.

Я ищу способ иметь в общей библиотеке код, который будет выполняться после инициализации всех статических данных и вызова статических конструкторов. Я видел, как люди рекомендовали __attribute __ ((конструктор)) в качестве замены DllMain; как мы видим, это неправильно, потому что некоторые статические данные все еще могут быть не инициализированы.

Конечно, в одном файле (блоке компиляции) статику можно расположить. Но в типичной программе файлов много. Есть ли способ гарантировать, что ((конструктор)) в одном файле будет определенно вызываться после инициализации всех остальных статик в общей библиотеке?

Если я помещу файл со статической инициализацией (конструктор, объект и т. Д.) В конец командной строки gcc:

g++ -shared -fPIC source1.o source2.o MyLastInitChance.o

гарантированно ли статические конструкторы этого файла будут вызываться последними? Я экспериментировал, и когда я меняю порядок исходных файлов, порядок printfs меняется; но указано ли оно где-то и гарантированно ли оно будет одинаковым для разных систем компиляции / компьютеров?

Например, цитата:

Во время компоновки драйвер gcc помещает crtbegin.o непосредственно перед всеми перемещаемыми файлами и crtend.o сразу после всех перемещаемых файлов.

Насколько я понимаю, приведенная выше цитата подразумевает, что порядок файлов .o, передаваемых компоновщику, определяет порядок статической инициализации. Я прав?

Еще одно интересное возможное решение, возможно, - написать плагин GCC, который регулирует статическую инициализацию (например, добавляет код в раздел .ctors и т. Д.). Но это всего лишь идея, которую, может быть, кто-то сможет расширить.

Еще одно возможное решение представлено здесь. Короче говоря, для изменения порядка записей .ctors в исполняемом файле (библиотеке) можно использовать внешний инструмент после сборки. Но я не эксперт в формате ELF; Интересно, возможно ли и достаточно ли просто настроить файлы .so таким образом.

Меня интересует решение конкретной проблемы или доказательство того, что ее невозможно решить (по крайней мере, почему приведенные выше решения не работают).


person queen3    schedule 19.06.2012    source источник
comment
__attribute((constructor))__ имеет больше смысла для чистого C, чем для C ++.   -  person Oliver Charlesworth    schedule 19.06.2012
comment
Вы также можете указать __attribute __ ((constructor (0))) и т. Д. Для указания порядка, в котором вызываются функции.   -  person    schedule 19.06.2012
comment
К сожалению, приоритет 0 приводит к тому, что он вызывается первым, а мне нужно, чтобы он вызывался последним. Не помогают и более высокие приоритеты.   -  person queen3    schedule 19.06.2012
comment
Почему DllMain у вас не работает?   -  person TonyK    schedule 24.06.2012
comment
Что я хотел бы сделать, так это перенести большой существующий устаревший код Windows (который использует DllMain) без его изменения.   -  person queen3    schedule 24.06.2012
comment
@ H2CO3, приоритеты ниже 101 зарезервированы, не используйте их! Приоритеты могут доходить до 65535, только не используйте значения ниже 101   -  person Jonathan Wakely    schedule 27.06.2012
comment
@Jonathan Wakely, возможно ли, что приоритет 101 - это то, что нужно OP?   -  person    schedule 27.06.2012
comment
Нет, потому что меньшие числа указывают на более высокий приоритет. (никто не читает документация в наши дни ?!) Может быть, приоритет 65535, поэтому он запускается позже, а не раньше. Но я думаю, что это не поможет, даже приоритет 65535 не требует упорядочивания относительно статики в других единицах перевода.   -  person Jonathan Wakely    schedule 27.06.2012
comment
Да, 65535 означает просто приоритет по умолчанию.   -  person queen3    schedule 28.06.2012


Ответы (4)


Вы можете попробовать использовать скрипты компоновщика для ld. Подробнее об этом можно узнать здесь , но я думаю, что вы ищете

.ctors : { *(SORT(.ctors)) MyLastInitChance.o(SORT(.ctors)) }
.dtors : { *(SORT(.dtors)) MyLastInitChance.o(SORT(.dtors)) }

в блоке SECTIONS{...}. Это должно изменить порядок .ctors разделов, чтобы предоставленный файл называл его конструкторами последним. Очевидно, что доступны и более продвинутые решения, если вы в них нуждаетесь;)

ПОДСКАЗКА: написание собственного скрипта ссылки утомительно. Используйте параметр --verbose ld, который распечатывает используемый скрипт ссылки и изменяет его. Затем добавьте свой сценарий связывания с помощью переключателя -T.

person j_kubik    schedule 25.06.2012
comment
Баунти заканчивается завтра, и у меня не было времени поэкспериментировать со сценариями компоновщика, но это близко к тому, что мне нужно, и выглядит многообещающим, спасибо. Я обязательно это проверю. - person queen3; 28.06.2012
comment
После исследований objdump дает .ctors быть пустыми (только FFFFFFFF), .init_array имеет некоторые данные, но, похоже, их перестановка не затрагивает. Интересно, нужно ли мне переставить данные _ CTOR_LIST_. Я думаю, что gcc помещает одну функцию инициализации в .init_array, и эта функция проходит __CTOR_LIST__. - person queen3; 29.06.2012

Самым большим преимуществом attribute ((constructor)) __ является приоритет, связанный с каждым блоком, который особенно помогает в вашем случае.

У вас есть два блока кодов с опасностью для данных (сначала должен быть выполнен один набор). Этого нельзя добиться с помощью одного статического блока. Использование одного статического блока и одного атрибута ((конструктор)) __ не решит вашу проблему из-за путаницы с порядком.

Лучший способ справиться с проблемой - иметь два атрибута ((конструктор)) __ с двумя разными приоритетами. Переместите существующий блок статической инициализации на более высокий приоритет (0), а другой блок кода - на более низкий приоритет.

person Community    schedule 22.06.2012
comment
Нет, я могу использовать приоритеты только для своего кода, а не для других статических переменных. - person queen3; 22.06.2012
comment
Если вы не можете изменить другие статические переменные, лучше вообще не реализовывать эту функцию, так как это затруднит ремонтопригодность кода. Даже если вы добьетесь того, чего пытаетесь достичь, взломав, вы будете наводнены труднопроходимыми ошибками. Измените свой дизайн или измените другой код - person ; 22.06.2012
comment
Оба решения, выделенные жирным шрифтом, не отвечают на мой вопрос. - person queen3; 22.06.2012
comment
Я знаю ответы на другие вопросы. - person queen3; 23.06.2012
comment
Боюсь, что вы тоже знаете ответ на этот вопрос. Но ответ не в том, кем вы хотите быть. Ответ: НЕТ, вы не можете заказать статический атрибут и атрибут конструктора. Вы должны знать, что ваш вопрос не приведет к созданию новой функции, для реализации новой функции вам следует присоединиться к участникам GCC и реализовать эту функциональность, и это только после того, как вы убедите всех остальных, что такая функциональность действительно необходима! - person ; 23.06.2012
comment
НЕТ, вы не можете заказать - это неправильно, потому что функция заказа - УЖЕ, и это init_priority. Но я не хочу заказывать их все; Я хочу только бежать последним. - person queen3; 23.06.2012
comment
Вы запутались ... Запуск первым / последним на самом деле называется порядком выполнения. Лучше бы вы просто закрыли вопрос, потому что вы не понимаете, о чем спрашиваете ... - person ; 23.06.2012
comment
Порядок исполнения? Вы сказали, что я не могу заказывать. - person queen3; 23.06.2012
comment
В любом случае, меня интересует решение конкретной проблемы ИЛИ доказательство того, что ее невозможно решить. Доказательство здесь означает несколько цитат и / pr доказательных ссылок, а не просто НЕТ. - person queen3; 24.06.2012
comment
1. Чтобы решить проблему, измените свой дизайн или измените другой код. И с атрибутом конструктора, и с приоритетом инициализации вы должны сделать то же самое ‹br/› 2. Это сайт контроля качества, а не тестовый сайт. Для некоторых доказательств на самом деле требуется диссертация на уровне магистра или доктора. - person ; 24.06.2012
comment
Если ответ достаточно сложен, чтобы потребовать диссертацию, я, вероятно, не получу его здесь. Я могу это понять. Закрою вопрос, ваш ответ докажет, что это так. На данный момент это не так. - person queen3; 24.06.2012
comment
Ответ может заключаться в том, что вы можете изменить раздел .ctors (это то, что считали делать даже люди в Mozilla), что я обнаружил, что некоторое время спустя все еще занимаюсь расследованиями (вот почему я также прошу доказательства, например, может быть .ctors - плохой идея). Возможно другое решение. Если вы не хотите тратить свое время, просто не отвечайте, это легко. - person queen3; 24.06.2012
comment
Вы можете переставлять .ctors, и в этом случае это не должно быть так сложно - посмотрите на мой ответ. - person j_kubik; 28.06.2012

См. Это: http://gcc.gnu.org/ml/gcc-help/2011-05/msg00220.html и ответ http://gcc.gnu.org/ml/gcc-help/2011-05/msg00221.html

В частности, цитата из ответа:

Все объекты с атрибутом init_priority создаются до любого объекта без атрибута init_priority.

Обратите внимание, что на самом деле речь идет о __attribute__((init_priority)), а не о __attribute__((constructor)), но я считаю, что они оба фактически используют один и тот же код в gcc, соответственно, в компоновщике gnu. Первый просто соответствует объектам C ++, то есть вызывает их конструктор / деструктор, последний касается пометки определенных функций как конструктора или деструктора.

IMHO, __attribute__((constructor)) существует в основном из-за C, а не C ++.

person mity    schedule 22.06.2012
comment
К сожалению, init_priority вызывает мой код в первую очередь, а мне нужно, чтобы он вызывался в последнюю очередь. Это то же решение, что и конструктор (0), мне это не помогает. Я не могу настроить все статические переменные во всех модулях с атрибутами init_priority, это чушь. - person queen3; 22.06.2012
comment
Да, в моем сообщении говорится, что вы вообще не можете использовать его для этой цели из-за жирного текста. Вам придется назначить приоритет всем другим статическим объектам, что непрактично. - person mity; 22.06.2012

Можете ли вы реализовать шаблон «создание при первом использовании» для этого глобального?

e.g.

Magic& gMagic()
{
    static Magic magic;
    return magic;
}

Он будет построен после всех обычных статических ctors, но до того, как он понадобится любому обычному коду.

person Rafael Baptista    schedule 26.06.2012
comment
Да, это хороший шаблон, спасибо. К сожалению, нет ни одного объекта или функции, которые будут вызываться в загруженной разделяемой библиотеке, которые я могу использовать или обернуть в gMagic () и быть уверенным, что они будут использоваться раньше других объектов. - person queen3; 28.06.2012
comment
Имеет ли ваш последний инициализированный объект какие-то внешние эффекты? Действительно ли его нужно создавать, если он явно не используется? Если нет, то не стоит переживать, что он еще не создан. Когда вам понадобится его создать, он будет: D - person j_kubik; 30.06.2012