Неправильный memset в голом металлическом ELF, собранном с помощью gcc-arm-none-eabi toolchain - PullRequest
0 голосов
/ 20 сентября 2019

Я собираю приложение «голое железо» для процессора ARM Cortex-M3 с gcc-arm-none-eabi-8-2019-q3.Я заметил, что производительность memset довольно плохая.Я использую полную реализацию newlib (не newlib nano).Когда я разбираю ELF-файл, он не содержит правильную реализацию ассемблера memset, которую я вижу в исходном файле newlib newlib/libc/machine/arm/aeabi_memset-thumb.S.Я могу сказать, потому что в реализации быстрой сборки, о которой я только что упомянул, используется инструкция stmia, которой нет, когда я смотрю на разборку моего приложения.

Как мне получить оптимизированный aeabi_memset-thumb.S для использования?

Вот фрагмент вывода сборки, в котором показаны используемые мной параметры.Я пробовал несколько вариантов опции mabi и удалял no-builtin, но вывод все еще не использует оптимизированный memset.

Building file: blah.c
Invoking: GNU ARM Cross C Compiler
arm-none-eabi-gcc -mcpu=cortex-m3 -march=armv7-m -mthumb -mabi=aapcs -O2 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-builtin  -g  -std=gnu11 -MMD -MP -MF"blah.d" -MT"blah.o" -c -o "blah.o" "blah.c"
Finished building: blah.c

Building target: gcc_app.elf
Invoking: GNU ARM Cross C Linker
arm-none-eabi-gcc -mcpu=cortex-m3 -march=armv7-m -mthumb -mabi=aapcs -O2 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-builtin  -g -T "blah.ld" -Xlinker --gc-sections -Wl,-Map,"gcc_app.map" --specs=nosys.specs -v -o "gcc_app.elf"  ./blah.o
Using built-in specs.
Reading specs from /home/blah/tools/gcc-arm-none-eabi-8-2019-q3-update/bin/../lib/gcc/arm-none-eabi/8.3.1/../../../../arm-none-eabi/lib/nosys.specs
rename spec link_gcc_c_sequence to nosys_link_gcc_c_sequence
gcc version 8.3.1 20190703 (release) [gcc-8-branch revision 273027] (GNU Tools for Arm Embedded Processors 8-2019-q3-update) 

Finished building target: gcc_app.elf

ОБНОВЛЕНИЕ:

Когда я включил карту компоновщика с помощью -Xlinker --print-map, я вижу, как компоновщик нашел реализацию для memset:

/home/blah/tools/gcc-arm-none-eabi-8-2019-q3-update/bin/../lib/gcc/arm-none-eabi/8.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m/nofp/libg.a(lib_a-memset.o)

. Для * существует множество libg.a файлов.различные архитектуры и типы с плавающей точкой.

Я разобрал их несколько и обнаружил, что те, которые находятся в подкаталогах softfp, используют реализацию сборки memset, которую я хочу.Например, lib/thumb/v7e-m+fp/softfp/libg.a.

Опция компилятора -print-multi-lib помогла мне определить, как заставить GCC выбрать эту конкретную реализацию во время компоновки.

thumb/nofp;@mthumb@mfloat-abi=soft
thumb/v7/nofp;@mthumb@march=armv7@mfloat-abi=soft
thumb/v7+fp/softfp;@mthumb@march=armv7+fp@mfloat-abi=softfp
thumb/v7+fp/hard;@mthumb@march=armv7+fp@mfloat-abi=hard
thumb/v6-m/nofp;@mthumb@march=armv6s-m@mfloat-abi=soft
thumb/v7-m/nofp;@mthumb@march=armv7-m@mfloat-abi=soft
thumb/v7e-m/nofp;@mthumb@march=armv7e-m@mfloat-abi=soft
thumb/v7e-m+fp/softfp;@mthumb@march=armv7e-m+fp@mfloat-abi=softfp
thumb/v7e-m+fp/hard;@mthumb@march=armv7e-m+fp@mfloat-abi=hard
thumb/v7e-m+dp/softfp;@mthumb@march=armv7e-m+fp.dp@mfloat-abi=softfp
thumb/v7e-m+dp/hard;@mthumb@march=armv7e-m+fp.dp@mfloat-abi=hard
thumb/v8-m.base/nofp;@mthumb@march=armv8-m.base@mfloat-abi=soft
thumb/v8-m.main/nofp;@mthumb@march=armv8-m.main@mfloat-abi=soft
thumb/v8-m.main+fp/softfp;@mthumb@march=armv8-m.main+fp@mfloat-abi=softfp
thumb/v8-m.main+fp/hard;@mthumb@march=armv8-m.main+fp@mfloat-abi=hard
thumb/v8-m.main+dp/softfp;@mthumb@march=armv8-m.main+fp.dp@mfloat-abi=softfp
thumb/v8-m.main+dp/hard;@mthumb@march=armv8-m.main+fp.dp@mfloat-abi=hard

Код в newlib довольно сложныйв newlib/libc/machine/arm/aeabi_memset.c я вижу:

/* According to the run-time ABI for the ARM Architecture, this
   function is allowed to corrupt only the integer core register
   permitted to be corrupted by the [AAPCS] (r0-r3, ip, lr, and
   CPSR).

   Therefore, we can't just simply use alias to support the function
   aeabi_memset for the targets with FP register.  Instead, versions
   for these specific targets are written in assembler (in
   aeabi_memset-soft.S).  */

/* NOTE: This ifdef MUST match the one in aeabi_memset-soft.S.  */
#if !defined (__SOFTFP__)

/* Defined in aeabi_memset-soft.S.  */

#else
/* Support the alias for the __aeabi_memset which may
   assume memory alignment.  */
void __aeabi_memset4 (void *dest, size_t n, int c)
        _ATTRIBUTE ((alias ("__aeabi_memset")));

void __aeabi_memset8 (void *dest, size_t n, int c)
        _ATTRIBUTE ((alias ("__aeabi_memset")));

/* Support the routine __aeabi_memset.  Can't alias to memset
   because it's not defined in the same translation unit.  */
void __aeabi_memset (void *dest, size_t n, int c)
{
  /*Note that relative to ANSI memset, __aeabi_memset hase the order
    of its second and third arguments reversed.  */
  extern void memset (void *dest, int c, size_t n);
  memset (dest, c, n);
}
#endif

Это означает, что если определено __SOFTFP__, вы не получите оптимизированные функции memset.

Если я использую следующие параметры компилятора -mcpu=cortex-m3 -mthumb -mfloat-abi=softfp -march=armv7e-m+fp тогда он должен заставить компоновщик подобрать libg.a с оптимизированным memset, но CMSIS злится на меня за то, что я пытался это сделать, и не может выполнить мою сборку:

  #if defined (__VFP_FP__) && !defined(__SOFTFP__)
    #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
  #endif

Я думаю, это имеет смысл, посколькуCortex-M3 не имеет FPU.Кажется, что newlib просто не поддерживает оптимизированный для сборки memset, если у вас нет FPU?Я не ясно, на каких основаниях они приводят.При сборке моего проекта я могу переопределить newlib с помощью оптимизированного memset, создав его локально, кажется, что он работает, но есть ли потенциальные проблемы и какие другие оптимизации производительности я мог бы упустить в newlib?

...