ARMCC: проблемы с memcpy (исключения выравнивания)

Я портирую некоторое программное обеспечение из gcc-toolchain в armcc-toolchain (процессор остается прежним (Cortex-A9)). В C-коде используется memcpy. armcc заменяет вызов memcpy на вызов __aeabi_memcpy. В FAQ говорится следующее о __aeabi_memcpy (Как компиляторы ARM обрабатывают memcpy ()?):

Во многих случаях при компиляции вызовов memcpy () компилятор ARM C вместо этого генерирует вызовы специализированных, оптимизированных библиотечных функций. Начиная с RVCT 2.1, эти специализированные функции являются частью ABI для архитектуры ARM (AEABI) и включают:

__aeabi_memcpy
This function is the same as ANSI C memcpy, except that the return value is void.

Но в отличие от gcc, где вызов memcpy отлично работает во всех моих случаях, с armcc вызов memcpy соответственно __aeabi_memcpy постоянно вызывает исключения выравнивания. Тем временем я обнаружил, что вызов memcpy может обрабатывать вызовы, в которых исходный и целевой адреса не выровнены по 4 байта, а только если они оба не выровнены по 4 байтам. Например:

    volatile uint32_t len = 10;
    uint8_t* src = (uint8_t*)0x06000002;         // 2-byte aligned
    uint8_t* dst = (uint8_t*)(0x06000002 + 20);  // 2-byte aligned
    memcpy(dst, src, len);

буду работать. Но например:

    volatile uint32_t len = 10;
    uint8_t* src = (uint8_t*)0x06000002;         // 2-byte aligned
    uint8_t* dst = (uint8_t*)(0x06000002 + 22);  // 4-byte aligned
    memcpy(dst, src, len);

вызовет исключение выравнивания. Так как я использую указатели типа uint8_t *, я явно говорю компилятору, что адреса могут иметь любое выравнивание. Но очевидно, что этот __aeabi_memcpy не может обрабатывать каждую комбинацию выравниваний. Как я могу решить эту проблему (желательно без изменения всех вызовов memcpy в существующем коде с пользовательской версией memcpy)? Спасибо за помощь.


person user3035952    schedule 22.07.2014    source источник
comment
Вы уверены, что ваш код не создает undefined b? Можете ли вы воспроизвести эту ошибку на минимально допустимом примере?   -  person this    schedule 22.07.2014
comment
Ну что, думаю, два примера минимальны? : D Я использовал эти два примера. Первый работает нормально, второй вызывает исключение выравнивания.   -  person user3035952    schedule 22.07.2014
comment
Я также посмотрел на разборку __aeabi_memcpy и нашел часть, которая вызывает эту проблему. Но я не знаю, почему это реализовано таким образом, и как исправить это для моего кода ...   -  person user3035952    schedule 22.07.2014
comment
Вы всегда можете написать свой собственный memcpy, который копирует с помощью char.   -  person this    schedule 22.07.2014
comment
Что ж, если вы не хотите изменять свой код, тогда единственный вариант - посмотреть флаги компиляции в настройках вашего проекта ARM и изменить их. В качестве альтернативы я бы предположил, что есть специальный #pragma, который вы можете добавлять перед каждым вызовом memcpy.   -  person barak manos    schedule 22.07.2014
comment
Кстати, вы, вероятно, можете исправить это, заменив memcpy на memmove (если вы не против понижения производительности).   -  person barak manos    schedule 22.07.2014
comment
@ user3035952 Я также нашел часть, которая вызывает эту проблему, не могли бы вы сбросить сборку в своем вопросе?   -  person ouah    schedule 22.07.2014


Ответы (2)


Если вы не хотите менять код, есть два варианта:

1) Отключите невыровненные исключения на вашем Cortex-A9. Это полностью решает проблему, но может снизить производительность.

2) Патчить библиотеку. Вы можете переименовать символ __aeabi_memcpy в файле lib, с которым вы связываетесь. Затем вы можете реализовать свой собственный __aeabi_memcpy, который обнаруживает ошибку выравнивания, обрабатывает ее с помощью специальной процедуры или переходит к исходной функции memcpy. Если вы используете Linux, вам даже не нужно переименовывать символ. Компоновщик позволяет вам переопределять функции.

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

О, и вам следует отправить отчет об ошибке. Поведение, которое вы видели, определенно является ошибкой. Memcpy должен нормально работать с любым выравниванием.

person Nils Pipenbrinck    schedule 22.07.2014
comment
В ситуации, когда вы получаете невыровненное исключение, вы получите некорректное поведение без исключения (поскольку невыровненный доступ будет читать четыре выровненных байта и изменять их порядок). Полностью согласен, это серьезная ошибка в реализации. Воняет. - person gnasher729; 22.07.2014
comment
Я думаю, что отключение невыровненных исключений только скроет проблему, но не решит ее. - person barak manos; 22.07.2014
comment
Спасибо. Я думаю, что gnasher прав в отношении отключения невыровненных исключений. Отключение невыровненных исключений приведет к неправильному поведению. Невыровненные исключения вызваны, например, инструкцией LDR или STR, которая пытается загрузить или сохранить что-то с адреса, который не имеет правильного выравнивания, то есть 4-байтового выравнивания. Когда я отключу это исключение, они больше не будут появляться, но LDR, вероятно, загрузит 4 байта данных, а не только 1 байт соответственно. STR будет хранить 4 байта вместо 1 байта, что не то, что я хотел, т.е. неправильное поведение. - person user3035952; 22.07.2014

возможно, это все еще помогает: ARM-компилятор armcc должен иметь параметр, с помощью которого вы можете указать компилятору не выполнять невыровненный доступ, а также не использовать встроенные библиотеки, которые будут делать это:

--no_unaligned_access

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472k/chr1359124947629.html

person Martin Keßler    schedule 03.11.2014