[uquote="Reflector",url="/forum/viewtopic.php?p=4180140#p4180140"][uquote="jcxz",url="/forum/viewtopic.php?p=4180122#p4180122"]Тогда зачем IAR стек в функциях выравнивает? Просто так?

[/uquote]
ARM много чего рекомендует и запрещает, например, у M0 есть инструкция DMB которая не делает ничего, но ARM все равно рекомендует ее использовать. Примерно то же и с выравниванием на 8, оно нужно только когда при прерываниях сохраняются регистры FP[/uquote]Сделаем маленький тест:
Код: Выделить всё
__packed struct {
float x;
double y[2];
} static t __align64 = {1.f, {1., 2.}};
Zf2((double *)t.y);
...
void Zf2(double *p)
{
u32 m[8];
memset(m, 0xEE, sizeof(m));
LogCR0("addr = %08X; SP = %08X; m = %08X", p, __get_SP(), m);
LogCR0("1: y1 = %f; y2 = %f", p[0], p[1]);
__set_SP(__get_SP() + 4);
LogCR0("2: y1 = %f; y2 = %f", p[0], p[1]);
__set_SP(__get_SP() - 4);
}
Функции LogCR0() имеют printf()-подобный интерфейс вызова (изнутри вызывают библиотечную _Printf()) и печатают в поток отладочного вывода.
Результат работы Zf2((double *)t.y) (напечатанный результат):
addr = 1000DB44; SP = 1000CF98; m = 1000CFA0
1: y1 = 1.000000; y2 = 2.000000
2: y1 = 0.000000; y2 = 0.000000
Как нетрудно заметить - в случае с SP не выровненным на 8 (а только на 4) получаем неверный результат.
Листинг Zf2() (на всяк случай):
Спойлер
Код: Выделить всё
void Zf2(double *p)
{
_Z3Zf2Pd: (+1)
0xB510 PUSH {R4,LR}
0xB08A SUB SP,SP,#+40
0x4604 MOV R4,R0
u32 m[8];
memset(m, 0xEE, sizeof(m));
0x22EE MOVS R2,#+238
0x2120 MOVS R1,#+32
0xA802 ADD R0,SP,#+8
0x.... 0x.... BL __aeabi_memset4
LogCR0("addr = %08X; SP = %08X; m = %08X", p, __get_SP(), m);
0x466A MOV R2,SP
0xAB02 ADD R3,SP,#+8
0x4621 MOV R1,R4
0x.... 0x.... ADR.W R0,?_14
0x.... 0x.... BL _Z12ServiceLogCRPKcz
LogCR0("1: y1 = %f; y2 = %f", p[0], p[1]);
0xED94 0x0B02 VLDR D0,[R4, #+8]
0xED8D 0x0B00 VSTR D0,[SP, #+0]
0xE9D4 0x2300 LDRD R2,R3,[R4, #+0]
0x.... 0x.... ADR.W R0,?_15
0x.... 0x.... BL _Z12ServiceLogCRPKcz
__set_SP(__get_SP() + 4);
0x4668 MOV R0,SP
0x1D00 ADDS R0,R0,#+4
0x4685 MOV SP,R0
LogCR0("2: y1 = %f; y2 = %f", p[0], p[1]);
0xED94 0x0B02 VLDR D0,[R4, #+8]
0xED8D 0x0B00 VSTR D0,[SP, #+0]
0xE9D4 0x2300 LDRD R2,R3,[R4, #+0]
0x.... 0x.... ADR.W R0,?_16
0x.... 0x.... BL _Z12ServiceLogCRPKcz
__set_SP(__get_SP() - 4);
0x4668 MOV R0,SP
0x1F00 SUBS R0,R0,#+4
0x4685 MOV SP,R0
}
0xB00A ADD SP,SP,#+40
0xBD10 POP {R4,PC}
IAR ANSI C/C++ Compiler V7.80.4.12462/W32 for ARM
Вывод:
Выравнивание SP на 8 необходимо! А не просто рекомендуемо. Как минимум - если используются функции стандартной си-библиотеки (семейство ...printf() и т.п.). И IAR не просто так выравнивает стек во всех функциях, из которых вызываются другие.