среда: linux, пользовательское приложение, созданное с помощью g ++ из пары файлов C++ (результат - ELF)
есть проблема (SIGSEGV) при обходе списка конструкторов
( __CTOR_LIST__ )
(примечание: код, вызываемый через этот список, является своего рода инициализацией системы для каждого класса, нет конструктор-код, который я написал)
__CTOR_LIST__
проблема (SIGSEGV) не существует, когда я перехожу через GDB через программу
для отладки я ищу способ добавить собственный код code перед зов
"_do_global_ctors_aux"
какие-нибудь намеки на это?
Благодарность,
Уве





Возможно, вас укусит так называемое «Фиаско статического порядка инициализации».
По сути, когда существует более одной единицы трансляции (то есть исходный файл C++), и каждый файл определяет глобальный объект, компилятор / компоновщик C++ не может определить, какую из них построить в первую очередь. Если x зависит от того, что y создается первым, но случайно компиляция / компоновка приводит к тому, что x создается раньше y, программа обычно аварийно завершает работу. См. Пункт [10.12] C++ FAQ Lite для получения более подробной информации. Пункт [10.13] содержит решение - идиому «построить при первом использовании».
Тому есть много возможных причин. В диапазоне от того, что вы обращаетесь к еще не созданным объектам (поскольку порядок создания объектов в разных единицах перевода не определен), что я считаю весьма вероятным в этом случае, и варьируется до ошибки в вашей среде сборки.
Чтобы собственная функция вызывалась перед другой функцией-конструктором, у вас есть атрибут constructor (priority), описанный здесь. GCC сохраняет приоритет для каждой секции ввода конструктора файлов. И это связывает их в порядке приоритетов. В сценарии компоновщика моей системы Linux этот код выглядит следующим образом (выведите его с помощью ld -verbose):
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
Вы хотели бы дать ему низкий приоритет, чтобы он выполнялся перед другими зарегистрированными функциями ctor, имеющими более высокий приоритет. Однако на первый взгляд кажется, что конструкторы без номера будут выполнены первыми. Не совсем уверен. Лучше всего попробовать. Если вы хотите, чтобы ваша функция вызывалась даже до _do_global_ctors_aux, вы должны выпустить исходную функцию _init, которая обычно выполняется, когда ваша программа загружается загрузчиком ELF (посмотрите опцию -init для ld). Прошло какое-то время с тех пор, как я испортил его, но я помню, что он должен выполнять некоторые важные детали инициализации, поэтому я не буду пытаться его заменить. Попробуйте использовать атрибут конструктора, с которым я связан. Однако будьте очень осторожны. Ваш код, возможно, будет выполнен до того, как будут созданы другие важные объекты, такие как cout.
Обновлять: Я провел тест, и он фактически выполняет функции ctor в обратном порядке. Таким образом, функции ctor, которые связаны первыми, выполняются позже. Этот код находится в crtstuff.c исходного кода gcc:
func_ptr *p;
for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
(*p) ();
Сделал небольшой тест:
void dothat() { }
struct f {
f() { dothat(); }
} f_;
void doit() __attribute__((constructor (0)));
void doit() { }
int main() { }
Связывание с --print-map дает, среди прочего, следующий вывод:
.ctors 0x080494f4 0x10
*crtbegin.o(.ctors)
.ctors 0x080494f4 0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtbegin.o
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
.ctors 0x080494f8 0x4 /tmp/ccyzWBjs.o
*(SORT(.ctors.*))
.ctors.65535 0x080494fc 0x4 /tmp/ccyzWBjs.o
*(.ctors)
.ctors 0x08049500 0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtend.o
Обратите внимание, что .ctors.65535 - это раздел, который мы неявно создали с помощью нашего приоритета атрибута 0. Теперь, если вы дадите ему этот приоритет, gcc предупредит, и это совершенно правильно: p
test.cpp:7: warning: constructor priorities from 0 to 100 are reserved for the implementation
Я протестировал его, взломав doit и dothat, и он вызвал их в ожидаемом нами порядке. Повеселись!
Не тот вопрос, который вы задали, но ...
В C++ / g ++ у вас может быть класс, в котором объявленные методы [header] никогда не определяются в исходных файлах [.cc], если эти методы никогда не вызываются.
Как следствие, вы можете скопировать свои текущие файлы кода во временный каталог, выполнить над ними работу по взлому и косой чертой, запустить [ручной] двоичный поиск и довольно быстро локализовать проблему.
Не элегантно, но очень эффективно.
Помимо печально известной проблемы «Статический порядок инициализации», есть также более эзотерические случаи, такие как тот, который недавно указал мне здесь, на SO by Чарльз Бейли (см. Комментарии)..
E.g Mixing: int p [] = { 1,2,3 };
And: extern int * p;
Возникнет аналогичная проблема с загрузкой ядра.