Segfault: и разборки различаются между objdump и gdb
[Глубокий вдох.]
У нас есть приложение, которое выводит окно с использованием WxMotif 2.6.3 (библиотека GUI не была - и не является - моим выбором).
Он отлично работает на 32-разрядных системах ix86. У меня была задача конвертировать его в 64-битное приложение. Это всегда seg-faults.
Я нахожусь на RHEL 6, поэтому я скомпилировал gcc 4.4.7. После многого скрежещения зубов проблема кажется очевидной: в wxFrame:: DoCreate, m_mainWidget установлен (правильно); в wxFrame:: GetMainWidget, он возвращается как нулевой указатель. Нулевой указатель приводит к сбою.
Используя gdb, команда, которая устанавливает m_mainWidget,
mov %rax,0x1e0(%rdx) # $rdx = 0x68b2f0
тогда как код, который получает m_mainWidget,
mov 0x1f0(%rax),%rax # $rax = 0x68b2f0
В gdb я могу проверить память и увидеть, что указатель на 0x68b4d0 верен. Почему неправильное смещение?
Чтобы еще больше запутать вещи, когда я использую objdump для дизассемблирования libwx_motifd_core-2.6.so.0.3.1, сборка "получить"
mov 0x1e0(%rax),%rax
В objdump, как get, так и set используют 0x1e0 в качестве смещения. Что происходит?
Я загрузил некоторую релевантную информацию здесь:
GitHub
Я включил небольшую программу, которая реплицирует проблему в моей системе.
Изучая далее, я вижу в разборке wxFrame:: DoCreate, который далее использует m_mainWidget для получения значения с использованием 0x1e0 в качестве смещения (разборка выполняется в компиляции, где я использовал -O0, поэтому код должен вернуться назад в память каждый раз).
"Just for Fun", я добавил новую переменную-член в wxFrame-m_myMainWidget и установил ее сразу после установки m_mainWidget. Затем я получил wxFrame:: GetMainWidget(), чтобы вернуть локальное значение (m_myMainWidget). Разве вы не знаете об этом: Сбой все еще происходит, и GetMainWidget содержит то же смещение +16, когда я разбираюсь изнутри gdb. (Смещение не там, где я использую objdump для демонтажа.)
Ответы
Ответ 1
Основываясь на комментарии @Igor, я просмотрел макеты классов, используя опцию -fdump-class-hierarchy
. Оказывается, что действительно существует несоответствие макета vtable из-за этого условного блока в include/wx/app.h
:
#ifdef __WXDEBUG__
virtual void OnAssert(const wxChar *file,
int line,
const wxChar *cond,
const wxChar *msg);
#endif // __WXDEBUG__
Вам нужно убедиться, что вы скомпилируете свой код с тем же значением __WXDEBUG__
.