2012-04-27 2 views
4

GCC 4.5.2 (на Ubuntu 11.10 x64, но компиляция для 32 бит) генерирует неверный код сборки, и мне любопытно, можно ли исправить ошибку без изменения кода, просто применив параметры или что-то вроде что. Обратите внимание, что оптимизация уже -O0.Ошибка генерации кода сборки GCC

У меня есть две функции:

inline long Class::Get() 
{ 
    long v = *(long*)(m_p); 
    m_p += 4; 
    return v; 
} 
inline void Class::Command() 
{ 
    m_p += Get(); 
} 

GCC 4.5.2 генерирует этот сборочный код:

9840  m_p += Get(); 
f689eff5: mov 0x8(%ebp),%eax 
f689eff8: mov 0xd4(%eax),%eax 
f689effe: mov %eax,%esi 
f689f000: mov 0x8(%ebp),%eax 
f689f003: mov %eax,(%esp) 
f689f006: call 0xf66116a0 
f689f00b: lea (%esi,%eax,1),%edx 
f689f00e: mov 0x8(%ebp),%eax 
f689f011: mov %edx,0xd4(%eax) 

Как вы можете видеть, что сохраняет m_p значение в% ЭСИ, а затем добавляет возвращаемое значение к нему используя lea. BUT :: Get() также меняет m_p! о котором GCC, похоже, не знает. Таким образом, ошибка, m_p неверна (на 4 байта меньше ожидаемой), потому что значение в% esi устарело.

я могу это исправить с помощью

inline void Class::Command() 
{ 
    long v = Get(); 
    m_p += v; 
} 

Но мне просто интересно, если я могу применить некоторые прагму или то вроде этого, без изменения кода, чтобы сделать ошибку уйти. Что касается gcc-версии, я застрял в заданной.

+1

Вы не получаете предупреждение о 'long v = * (long *) (m_p);'? Я считаю, что это тип punning и технически UB? Может быть, попробуйте '-fno-strict-aliasing', если вы собираетесь писать небезопасный код вроде этого? –

+0

вы всегда можете отличить ... –

+0

Нет, предупреждения отключены. Но я не вижу, как это связано. И я не пишу такой код, я просто работаю с ним. – queen3

ответ

11

Это не ошибка. Как вы знаете, m_p += Get(); действительно m_p = m_p + Get();. Компилятор может свободно выбирать порядок оценки для добавления. Итак, выберем m_p, затем выполним Get(), после чего сделаем добавление действительным и создадим код, который вы только что опубликовали.

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

+0

Хм, по крайней мере, это выглядит повод для изменения кода, намного лучше, чем просто «ошибка gcc», спасибо. – queen3

+1

Я не думаю, что вы получаете _Undefined_ Behavior от порядка оценки. Это просто не указано. Конечно, описанный вами заказ - это возможный порядок и объясняет результат GCC. – MSalters

+0

@MSalters: точно. Спасибо за разъяснение. –