搜索
bottom↓
回复: 12

对堆栈8字节对齐问题的讨论 (转)

[复制链接]

出0入0汤圆

发表于 2014-4-2 22:44:29 | 显示全部楼层 |阅读模式

一.为什么要保证堆栈8字节对齐
AAPCS规则要求堆栈保持8字节对齐。如果不对齐,调用一般的函数也是没问题的。但是当调用需要严格遵守AAPCS规则的函数时可能会出错。
例如调用sprintf输出一个浮点数时,栈必须是8字节对齐的,否则结果可能会出错。

实验验证:
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];
int main(void)
{
sprintf(buf,"%.3f\n\r",fff);//A
while(1);
}

1.在A处设置断点,让程序全速运行至A
2.在MDK中修改MSP的值使MSP满足8字节对齐
3.全速运行程序,观察buf中的字符为 1.234 结果正确
4.回到第2步,修改MSP使之只满足4字节对齐而不满足8字节对齐
5.全速运行程序,观察buf中的字符为 -2.000 结果错误

该实验证明了调用sprintf输出一个浮点数必须要保证栈8字节对齐。


二.编译器为我们做了什么
先看一个实验
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];

void fun(int a,int b,int c,int d)
{
int v;
v=v;
}
void test(void)
{}

int main(void)
{
fun(1,2,3,4);
test();//A
//sprintf(buf,"%.3f\n\r",fff);
while(1);
}

0.保证初始的时候堆栈是8字节对齐的
1.在A处设置断点
2.全速运行至A,观察MSP=0x2000025c,没有8字节对齐
3.略微修改一下main函数代码如下,其他部分代码不变

int main(void)
{
fun(1,2,3,4);
//test();
sprintf(buf,"%.3f\n\r",fff);//A
while(1);
}

4.同样在A处设置断点
5.全速运行至A,观察MSP=0x200002d8,这次8字节对齐了

这个实验说明了如果编译器发现了某个函数需要调用浮点库时会自动调整编译生成的汇编
代码,从而保证调用这些浮点库函数时堆栈是8字节对齐的。换句话说如果我们保证了栈
初始的时候是8字节对齐的,那么编译器可以保证以后调用浮点库时堆栈仍是8字节对齐的。

三.os下应该怎样设置任务堆栈
由上面的讨论可知给任务分配栈时需要保证栈是8字节对齐的,不然在该任务中凡是调用sprintf的函数
均会出错,因为栈一开始就是不对齐的。

四.中断中的栈对齐问题
是否保证了栈初始是8字节对齐了就万事大吉了呢。no!大家请看一种特殊的情况:
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];
void fun(int a,int b,int c,int d)
{
int v;
v=v;
}
int main(void)
{
fun(1,2,3,4);
while(1);
}
void SVC_Handler(void)
{
sprintf(buf,"%.3f\n\r",fff);//B
}
mian函数的反汇编如下:
0x080001DC B500 PUSH {lr}
0x080001DE 2304 MOVS r3,#0x04 ;A
0x080001E0 2203 MOVS r2,#0x03
0x080001E2 2102 MOVS r1,#0x02
0x080001E4 2001 MOVS r0,#0x01
0x080001E6 F7FFFFF5 BL.W fun (0x080001D4)
0x080001EA BF00 NOP
0x080001EC E7FE B 0x080001EC

0.保证初始的时候堆栈是8字节对齐的
1.在A处设置断点
2.全速运行至A,观察此时MSP=0x200002e4 未对齐
3.在MDK中将SVC的挂起位置1
4.在B处设置断点
5.全速运行至B,观察此时MSP=0x200002b4 未对齐
6.继续全速执行,观察buf中的字符为:-2.000 出错了

这个实验说明了即使保证栈初始是8字节对齐的,编译器也只能保证在调用sprintf那个时刻栈是8字节对齐的
但不能保证任意时刻栈都是8字节对齐的,如果恰巧在MSP没有8字节对齐的时刻发生了中断,而中断中又调用
了sprintf,这种情况下仍会出错

五.Cortex-M3内核为我们做了什么
Cortex-M3内核提供了一种硬件机制来解决上述这种中断中栈不对齐问题。
CM3中可以把NVIC配置控制寄存器的STKALIGN置位,来保证中断中的栈8字节对齐,
具体实现过程如下:
当发生中断时由硬件自动检测MSP是否8字节对齐,如果对齐了,则不进行任何操作,
如果没有对齐,则自动将MSP减4这样便对齐了,同时将xPSR的第9位置位来记录这个
MSP的非正常的变化,在中断返回若发现xPSR的第9位是置位的则自动将MSP加4调整
回原来的值。

实验验证:
#include "stdio.h"
#include "string.h"
float fff=1.234;
char buf[128];
void fun(int a,int b,int c,int d)
{
int v;
v=v;
}
int main(void)
{
fun(1,2,3,4);
while(1);
}
void SVC_Handler(void)
{
sprintf(buf,"%.3f\n\r",fff);//B
}
mian函数的反汇编如下:
0x080001DC B500 PUSH {lr}
0x080001DE 2304 MOVS r3,#0x04 ;A
0x080001E0 2203 MOVS r2,#0x03
0x080001E2 2102 MOVS r1,#0x02
0x080001E4 2001 MOVS r0,#0x01
0x080001E6 F7FFFFF5 BL.W fun (0x080001D4)
0x080001EA BF00 NOP
0x080001EC E7FE B 0x080001EC

1.在A处设置断点
2.全速运行至A,观察此时MSP=0x200002e4 未对齐
3.在MDK中将SVC的挂起位置1,同时将0xE000ED14处的值由0x00000000改为0x00000200
(即将NVIC配置控制寄存器的STKALIGN置位)
4.在B处设置断点
5.全速运行至B,观察此时MSP=0x200002b0 对齐了
6.观察中断返回时的MSP=0x200002e4 调整回来了
7.继续全速执行,观察buf中的字符为:1.234 正确

这个实验说明了将NVIC配置控制寄存器的STKALIGN置位可以保护中断时栈仍是8字节对齐


六.总结
综上所述,为了能够安全的使用严格遵守AAPCS规则的函数(比如sprintf)需要做到以下几点:
1.保证MSP在初始的时候是8字节对齐的
2.如果用到OS的话需要保证给每个任务分配的栈是保持8字节对齐的
3.如果用的是基于CM3内核的处理器需将NVIC配置控制寄存器的STKALIGN置位

转自http://www.cnblogs.com/sky1991/archive/2012/10/13/2722482.html

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2014-4-2 23:07:35 | 显示全部楼层
rtdef.h
  1. /* Compiler Related Definitions */
  2. #ifdef __CC_ARM                         /* ARM Compiler */
  3.     #define ALIGN(n)                    __attribute__((aligned(n)))
  4. #elif defined (__IAR_SYSTEMS_ICC__)     /* for IAR Compiler */
  5.     #define ALIGN(n)                    PRAGMA(data_alignment=n)
  6. #elif defined (__GNUC__)                /* GNU GCC Compiler */
  7.     #define ALIGN(n)                    __attribute__((aligned(n)))
  8. #elif defined (__ADSPBLACKFIN__)        /* for VisualDSP++ Compiler */
  9.     #define ALIGN(n)                    __attribute__((aligned(n)))
  10. #elif defined (_MSC_VER)
  11.     #define ALIGN(n)                    __declspec(align(n))
  12. #endif /* Compiler Related Definitions */
复制代码
  1. #define RT_ALIGN_SIZE  8
  2. ALIGN(RT_ALIGN_SIZE)
  3. static char finsh_thread_stack[2048];
复制代码

出0入0汤圆

 楼主| 发表于 2014-4-3 11:37:33 | 显示全部楼层

高手,你这是从哪弄的文件啊?指点一下吧

出0入93汤圆

发表于 2014-4-3 12:17:17 | 显示全部楼层

呵呵,只有IAR和VC与众不同……

我一般使用
  1. __align(8) static char finsh_thread_stack[2048];
复制代码

出0入0汤圆

 楼主| 发表于 2014-4-4 23:42:07 | 显示全部楼层
takashiki 发表于 2014-4-3 12:17
呵呵,只有IAR和VC与众不同……

我一般使用

大侠们对话我都听不懂,我问一下VC是什么?    __align(8) static char finsh_thread_stack[2048];在哪使用啊?

出0入93汤圆

发表于 2014-4-5 07:24:40 | 显示全部楼层
565715470 发表于 2014-4-4 23:42
大侠们对话我都听不懂,我问一下VC是什么?    __align(8) static char finsh_thread_stack[2048];在哪使 ...

VC,指得是微软的Visual C++。
__align(8)是用在MDK、RVDS中的,RVCT编译器将它定义为一个关键字,专门用作对齐用的。对齐问题交给编译器就好了,不需要自己去手动关注。

出0入0汤圆

 楼主| 发表于 2014-4-5 11:42:15 来自手机 | 显示全部楼层
进入异常,中断编译器会自动对齐吗?还是需要STKALIGN置位?

出0入0汤圆

发表于 2014-4-5 12:05:30 | 显示全部楼层
弱弱地问句,怎么改MSP的值

出0入0汤圆

 楼主| 发表于 2014-4-5 15:36:00 | 显示全部楼层
takashiki 发表于 2014-4-5 07:24
VC,指得是微软的Visual C++。
__align(8)是用在MDK、RVDS中的,RVCT编译器将它定义为一个关键字,专门用 ...


进入异常,中断编译器会自动对齐吗?还需要STKALIGN置位吗?

出0入93汤圆

发表于 2014-4-5 16:48:55 | 显示全部楼层
565715470 发表于 2014-4-5 15:36
进入异常,中断编译器会自动对齐吗?还需要STKALIGN置位吗?

要保证异常中能用,变量可能要声明成volatile。异常时是对齐的。

出0入0汤圆

 楼主| 发表于 2014-4-5 17:41:56 | 显示全部楼层
takashiki 发表于 2014-4-5 16:48
要保证异常中能用,变量可能要声明成volatile。异常时是对齐的。

对齐和volitale有什么关系?越来越不理解了 。大侠给我推荐点这方面的资料吧!谢谢啦

出0入93汤圆

发表于 2014-4-5 17:52:26 | 显示全部楼层
565715470 发表于 2014-4-5 17:41
对齐和volitale有什么关系?越来越不理解了 。大侠给我推荐点这方面的资料吧!谢谢啦 ...

啥关系都没有。
但是volatile才能保证你的变量在异常态正确的进行写操作。资料我也没有,不过MDK的HELP应该能帮上你的忙,里面说得很清楚了。

出0入0汤圆

 楼主| 发表于 2014-4-8 10:22:48 | 显示全部楼层
takashiki 发表于 2014-4-5 17:52
啥关系都没有。
但是volatile才能保证你的变量在异常态正确的进行写操作。资料我也没有,不过MDK的HELP应 ...

谢谢高手的回答!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-24 17:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表