C ++ ctor вопрос (Linux) - PullRequest
       24

C ++ ctor вопрос (Linux)

1 голос
/ 07 января 2009
  • среда: linux, userpace-приложение, созданное с помощью g ++ из пары файлов C ++ (результат - ELF)

  • существует проблема (SIGSEGV) при обходе списка конструкторов

    ( __CTOR_LIST__ )

(примечание: код, вызываемый через этот список, является своего рода инициализацией системы для каждого класса, не код конструктора, который я написал)

  • когда я правильно понимаю каждую единицу компиляции (каждый .o, созданный из .cpp) создает одну запись в
    __CTOR_LIST__ 
  • проблема (SIGSEGV) не существует, когда я перехожу через GDB через программу

  • для отладки я ищу способ добавить собственный код до вызов

    "_do_global_ctors_aux"

есть намеки на это?

спасибо,

Уве

Ответы [ 3 ]

7 голосов
/ 07 января 2009

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

Чтобы вызвать собственную функцию перед другой функцией конструктора, у вас есть атрибут 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: предупреждение: приоритеты конструктора от 0 до 100 зарезервированы для реализации

Я проверил его, взломав doit и dothat, и он назвал их в порядке, который мы ожидаем. Веселись!

1 голос
/ 07 января 2009

Возможно, вас укусил так называемый "статический порядок инициализации Fiasco".

Обычно, когда существует более одного модуля перевода (то есть исходного файла C ++), и каждый файл определяет глобальный объект, компилятор / компоновщик C ++ не может определить, какой из них создать первым. Если x зависит от y, который создается первым, но случайно компиляция / компоновка приводит к тому, что x создается до y, программа обычно завершается сбоем. См. Пункт [10.12] C ++ FAQ Lite для более подробной информации. Пункт [10.13] содержит решение - идиома «конструкция при первом использовании».

0 голосов
/ 07 января 2009

Не тот вопрос, который вы задали, но ...

В C ++ / g ++ у вас может быть класс, в котором объявленные методы [header] фактически никогда не определяются в исходных файлах [.cc], если эти методы никогда не вызываются.

Как следствие, вы можете скопировать ваши текущие файлы кода во временный каталог, выполнить для них взлом и слэш, выполнить [ручной] двоичный поиск и довольно быстро изолировать проблему.

Не элегантно, но очень эффективно.


Помимо печально известного «Статического порядка инициализации» , есть и более эзотерические случаи, такие как тот, который недавно мне здесь указали на SO от Charles Bailey (см. комментарии).

   E.g Mixing:  int p [] = { 1,2,3 };
          And:  extern int * p;

Создает аналогичную проблему с coredump.

...