打印
[STM32F1]

关于内存对齐的疑问

[复制链接]
楼主: yearnext
手机看帖
扫描二维码
随时随地手机跟帖
21
cruelfox| | 2017-4-12 13:22 | 只看该作者 回帖奖励 |倒序浏览
int main(void)
{
    struct test_t *test = (struct test_t *)&buffer[1];

    p1 = (void *)&test->func;
    p2 = (void *)&test->param;

    test->func  = inc;
    test->param = (void *)&i;

    if( test->func != NULL && test->param != NULL )
    {
        test->func(test->param);
    }
红色标出的两个地方已经有错了,test这个指针没有4字节对齐,对其中的32-bit成员直接进行写操作是可能引发异常的。为什么说是“可能”而不是“一定”?这取决于编译器怎么处理这段代码。如果编译器认为如此访问 test 必然是4字节对齐的指针,就用一条STR来写入,那必然异常。如果编译器从前面推断出 test 是没有对齐的,可以分解成字节操作来完成这里的赋值(也就是把数写到buffer里面去),是可以通过的。
test这个指针没对齐埋下的祸根,什么时候引发Hard Fault是取决于生成的指令…… 呵呵


使用特权

评论回复
22
yearnext|  楼主 | 2017-4-12 14:39 | 只看该作者
cruelfox 发表于 2017-4-12 13:22
int main(void)
{
    struct test_t *test = (struct test_t *)&buffer[1];

使用特权

评论回复
23
yearnext|  楼主 | 2017-4-12 14:57 | 只看该作者
本帖最后由 yearnext 于 2017-4-12 15:00 编辑
icecut 发表于 2017-4-12 13:07
lz 很有意思.研究的挺深刻....
但是解决办法是写规范的代码让编译器理解,别给你编译错误.
如果编译器不确定 ...

这么写是为了模拟当时的情况
内存是由我的内存管理组件分配的,当时没有考虑对齐问题
话说IAR竟然严谨到了这种程度

使用特权

评论回复
24
icecut| | 2017-4-12 16:51 | 只看该作者
yearnext 发表于 2017-4-12 14:57
这么写是为了模拟当时的情况
内存是由我的内存管理组件分配的,当时没有考虑对齐问题
话说IAR竟然 ...

恩.有时候会这样,但是损失性能.我测试过.
我也常常入坑

使用特权

评论回复
25
justtest111| | 2017-4-12 19:59 | 只看该作者
cruelfox 发表于 2017-4-12 13:22
int main(void)
{
    struct test_t *test = (struct test_t *)&buffer[1];

test内部的成员不是空指针吗,为什么你说是对32位成员进行写操作啊?

使用特权

评论回复
26
戈卫东| | 2017-4-12 21:41 | 只看该作者
这么疯狂恐怖的东西我只能围观学习了。

使用特权

评论回复
27
lxyppc| | 2017-4-12 22:56 | 只看该作者
尽量避免强制类型转换,非要这么做,最好先检查一下

使用特权

评论回复
28
cruelfox| | 2017-4-13 09:26 | 只看该作者
justtest111 发表于 2017-4-12 19:59
test内部的成员不是空指针吗,为什么你说是对32位成员进行写操作啊?

一个指针也要占用32-bit来存放。

使用特权

评论回复
29
linqing171| | 2017-4-15 21:32 | 只看该作者
1 函数的地址,如果是thumb的,最低位会有个1.
2 前面有人汇编分析错误  LDR R1,[R2,#2] 是把R2当指针,+2后指向的地址取数,而不是R2+2=R4去取数。
3 无论指针里面的数是奇数还是偶数,最终生成的都是LDR R1,[R2] 这样的指令,R2为奇数的时候比如0x11223345,如果不发生fault的话,取到的数应该是 (0x11223344 &~0x04)地址的数。很多年前用44B0开发板的时候碰到过类似问题,扩展的RAM的低两位根本就不接。所以后面如果和文件一致的结构体,要么用char*指针,要么pack。

使用特权

评论回复
30
linqing171| | 2017-4-15 21:50 | 只看该作者
7楼的汇编,R4是非对齐指针test,LDRD r1,r0,[r4,#0] 指令 从指针里取8个字节,前4个也就是函数地址存入R1,后四个也就是参数存入R0,然后call R1;
根据16楼的图片说明,LDRD指令在此种情况下会发生此问题。
19楼的是LDR指令,楼主可以看看LDR指令可能和16楼的不同。主要是最后面那个注释。反正在ARM7TDMI核下LDR是可以非整四地址对齐的,只是返回的结果怪异,但是不会进入中断。

其它没有贴汇编代码的,就分析不了了。能看到的都是符合芯片指令集说明的。

使用特权

评论回复
31
myiclife| | 2017-4-15 23:29 | 只看该作者
单片机也能内存对齐?

使用特权

评论回复
32
myiclife| | 2017-4-15 23:31 | 只看该作者
一般都是在电脑上对齐内存,单片机还真没有尝试过。

使用特权

评论回复
33
yearnext|  楼主 | 2017-4-16 09:29 | 只看该作者
linqing171 发表于 2017-4-15 21:50
7楼的汇编,R4是非对齐指针test,LDRD r1,r0,[r4,#0] 指令 从指针里取8个字节,前4个也就是函数地址存入R1 ...

感谢指点!

使用特权

评论回复
34
yearnext|  楼主 | 2017-4-16 09:30 | 只看该作者
myiclife 发表于 2017-4-15 23:29
单片机也能内存对齐?

编译器

使用特权

评论回复
35
dspmana| | 2017-4-16 17:12 | 只看该作者
还真没有注意过这个问题。

使用特权

评论回复
36
dspmana| | 2017-4-16 17:16 | 只看该作者

使用特权

评论回复
37
it_yrj| | 2017-4-28 14:03 | 只看该作者
分析的很到位,这个问题还真是广泛存在,上次在做遥控器开发的时候就遇到了这个坑

使用特权

评论回复
38
whtwhtw| | 2017-4-28 16:23 | 只看该作者
按c语言规范,或者正常写的程序都是字节对齐的,除非用到强制类型转换和_packed

使用特权

评论回复
39
zxmxx| | 2017-5-3 17:54 | 只看该作者

使用特权

评论回复
40
0520kuang| | 2017-5-3 19:04 | 只看该作者
看完一遍,还是糊涂,还请LZ,说明一下最终解决的方法
因为这个问题之前也遇到过类似情况

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则