Я собираю приложение «голое железо» для процессора 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?