Компиляция Linaro g++ aarch64 вызывает ошибку выравнивания

Я использую linaro g++ для ARM arch64 для компиляции простого файла cpp:

int main()
{
    char  *helloMain      = "main module (crm.c)";
    long  faculty, num    = 12;
    int   stop,mainLoop   = 1; 
    char  word[80]        = "";
}

После objdump сгенерированного файла elf я получил его ассемблерный код:

0000000000001270 <main>:
int main()
{
    1270:   d101c3ff    sub sp, sp, #0x70
    char  *helloMain      = "main module (crm.c)";
    1274:   90000020    adrp    x0, 5000 <_malloc_trim_r+0x160>
    1278:   9111c000    add x0, x0, #0x470
    127c:   f90003e0    str x0, [sp]
    long  faculty, num    = 12;
    1280:   d2800180    movz    x0, #0xc
    1284:   f90007e0    str x0, [sp,#8]
    int   stop,mainLoop   = 1; 
    1288:   52800020    movz    w0, #0x1
    128c:   b90013e0    str w0, [sp,#16]
    char  word[80]        = "";
    1290:   910063e0    add x0, sp, #0x18
    1294:   90000021    adrp    x1, 5000 <_malloc_trim_r+0x160>
    1298:   91122021    add x1, x1, #0x488
    129c:   39400021    ldrb    w1, [x1]
    12a0:   39000001    strb    w1, [x0]
    12a4:   91000400    add x0, x0, #0x1
    12a8:   a9007c1f    stp xzr, xzr, [x0]
    12ac:   a9017c1f    stp xzr, xzr, [x0,#16]
    12b0:   a9027c1f    stp xzr, xzr, [x0,#32]
    12b4:   a9037c1f    stp xzr, xzr, [x0,#48]
    12b8:   f900201f    str xzr, [x0,#64]
    12bc:   b900481f    str wzr, [x0,#72]
    12c0:   7900981f    strh    wzr, [x0,#76]
    12c4:   3901381f    strb    wzr, [x0,#78]
}
    12c8:   52800000    movz    w0, #0x0
    12cc:   9101c3ff    add sp, sp, #0x70
    12d0:   d65f03c0    ret

Перед выполнением этого кода на плате ARMV8 sp инициализируется адресом, выровненным до 0x1000.

Выполнение такого кода вызвало исключение ошибки выравнивания на 12a8: a9007c1f stp xzr, xzr, [x0]

Я заметил, что x0 был добавлен 0x1, поэтому он был выровнен с 0x1 при выполнении инструкции stp.

Почему g++ не выровнял его по 0x10, чтобы избежать такого исключения ошибки выравнивания?

Версия g++:

gcc  4.8.1 20130506 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2013.05 - Linaro GCC 2013.05)

person Logan Ding    schedule 24.04.2014    source источник


Ответы (2)


Из руководства:

-munaligned-access
-mno-unaligned-access

Включает (или отключает) чтение и запись 16- и 32-битных значений с адресов, которые не выровнены по 16- или 32-битам. По умолчанию невыровненный доступ отключен для всех архитектур до ARMv6 и всех ARMv6-M и включен для всех остальных архитектур. Если невыровненный доступ не включен, то слова в упакованных структурах данных будут доступны побайтно за раз.

Для атрибута ARM Tag_CPU_unaligned_access в сгенерированном объектном файле будет установлено значение true или false, в зависимости от настройки этого параметра. Если несогласованный доступ включен, тогда также будет определен символ препроцессора __ARM_FEATURE_UNALIGNED.

AArch64/ARMv8 поддерживает невыровненный доступ из коробки, поэтому GCC предполагает, что он доступен. Если это не так, возможно, вам придется явно отключить его с помощью вышеуказанного переключателя. Также возможно, что предварительная версия, которую вы используете, еще не доработана и присутствуют различные ошибки/проблемы.

ИЗМЕНИТЬ

Как упоминалось в комментариях, соответствующие параметры AArch64:

-mstrict-align
-mno-strict-align

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

Кстати, код ведет себя так, потому что GCC интерпретировал присваивание буквально:

  1. Скопируйте строку (то есть всего один нулевой байт) в начало буфера.
  2. Заполните оставшуюся часть буфера нулями.

Я подозреваю, что если вы включите оптимизации, невыровненный доступ исчезнет. Или, если вы используете char word[80] = {0}, он должен выполнить обнуление за один раз.

person Igor Skochinsky    schedule 24.04.2014
comment
Спасибо. Я тестировал с параметрами munaligned-access и -mno-unaligned-access, файлы elf, кажется, ничем не отличаются, по-прежнему имеют невыровненный доступ. Но замена на char word[80] = {0}; сработала. - person Logan Ding; 25.04.2014
comment
Обратите внимание, что (как описано в ответе ниже) эквивалентная опция AArch64 -mstrict-align ( gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html ) - person James Greenhalgh; 22.05.2014

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

  1. Почему возникло это исключение ошибки выравнивания?

    Как упомянул @IgorSkochinsky, AArch64/ARMv8 поддерживает невыровненный доступ. Но поскольку я работаю в простой среде с голым железом, MMU не был зашифрован, поэтому в этом случае память рассматривается как устройство, а устройство не поддерживает невыровненный доступ. Если MMU включен, это исключение исчезнет.

  2. #P4# #P5#
    #P6#
    #P7#
person Logan Ding    schedule 29.04.2014
comment
Большое спасибо за ваши выводы! У меня возникает исключение невыровненного доступа в U-boot на arm64. Мне интересно, рассматривается ли память как устройство, как вы говорите. - person Eugeniu Rosca; 18.12.2016
comment
Оказывается, моя плата намеренно деактивировала кеши ЦП через конфигурации U-boot CONFIG_SYS_DCACHE_OFF и CONFIG_SYS_ICACHE_OFF. После их удаления ошибка выравнивания исчезла. Спасибо еще раз за ваше сообщение. - person Eugeniu Rosca; 22.12.2016