Указывает на невыровненный доступ к Clang для совместимости с ARM - PullRequest
3 голосов
/ 08 февраля 2012

Я анализирую формат файла, отображая файл в память и получая к нему доступ через определения структуры C.Формат файла использует упакованные структуры, поэтому я не могу гарантировать, что поле будет выровнено по границе слова.

Синтаксический анализ работает очень хорошо, к сожалению, в некоторых случаях оптимизатор может нанести ущерб.В частности, при компиляции для armv7 существуют определенные инструкции загрузки, которые требуют выравнивания слов, а другие - нет.Рассмотрим этот фрагмент:

#define PACKED __attribute__((packed))

typedef struct PACKED _Box_mvhd {
    union {
        struct {
            int32_t creation_time;
            int32_t modification_time;
            int32_t time_scale;
            int32_t duration;
            ...
        } v0;
    } data;
} Box_mvhd;

Container mvhd = find_single_box(&moov, 'mvhd');
if (mvhd.boxStart) {
    Box_mvhd *mvhdBox = mvhd.mvhd;
    if (0 == mvhdBox.box.version) {
        uint32_t ts = ntohl(mvhdBox->data.v0.time_scale);
        uint32_t dur = ntohl(mvhdBox->data.v0.duration);
        ...
    }
}

В -O0 (отладка) самый внутренний блок выводится как следующая сборка, которая работает правильно:

ldr r1, [r0, #24]
ldr r2, [r0, #20]

В -O2 однако компиляторпонимает, что эти поля являются смежными и генерирует эту сборку:

ldrdeq  r2, r3, [r0, #20]

К сожалению, LDRD всегда генерирует ошибку выравнивания (по спецификации и на практике).Поэтому мне нужен способ эффективно сообщить компилятору об этой проблеме.В идеале это можно сделать с помощью атрибута структуры.Также возможно, что это ошибка компилятора или бэкэнда ARM, но я дам им преимущество сомнения.

Я компилирую с Xcode 4.2 (clang 3.0), ориентируясь на armv7 для iPhone.

Ответы [ 2 ]

4 голосов
/ 08 февраля 2012

Проблема не в том, что поля структуры не имеют необходимого выравнивания, а в том, что вы приводите произвольный указатель на указатель на вашу структуру, а указанный вами указатель не имеет требуется выравнивание структуры. Строго говоря, это неопределенное поведение.

Вместо этого memcpy ваши данные из исходного буфера в вашу структуру. memcpy быстр и гарантированно справится с любым выравниванием, которое вы в него бросаете.

0 голосов
/ 12 сентября 2013

На самом деле, невыровненные указатели на упакованные структуры вполне хороши. Но вам нужно убедиться, что параметры -mcpu и -march установлены правильно во время компиляции. Некоторые процессоры ARM поддерживают невыровненные ldrd, другие - нет.

Да, не выровненный доступ не является стандартным и не является расширением компилятора, но он совершенно безопасен, если вы случайно не передадите указатель на член упакованной структуры другой функции.

Здесь, похоже, проблема в том, что структура внутри объединения не объявлена ​​упакованной. Вы можете проверить выравнивание членов структуры, используя оператор alignof. Это похоже на оператор sizeof. Если оператор alignof сообщает, что выравнивание структуры и ее членов равно 1, а gcc по-прежнему генерирует код, используя ldrd, то вы либо сталкиваетесь с ошибкой компилятора, либо параметры командной строки неверны.

Также обратите внимание, что код для -O0 мог быть неправильным с самого начала! (если только ваша целевая архитектура не поддерживает выравнивание ldr). Использование упакованного атрибута сбрасывает выравнивание членов структуры в 1, что означает, что clang должен был выдать восемь ldrb инструкций вместо двух ldr.

И да, как уже говорили другие, единственный безопасный и переносимый способ доступа к невыровненным данным из простого C без каких-либо расширений компилятора и без риска усложнить поиск ошибок (например, передача невыровненного указателя на функцию) это с помощью memcpy.

...