keil中,按4字节对齐给函数指针赋值,跳转时会触发HardFault

2019-12-10 18:32发布

本帖最后由 liansh2002 于 2018-4-9 16:11 编辑
  1. void A(uint32_t flag)             //此函数被定位到0x20003000地址处
  2. {
  3.     ......
  4. }

  5. main()
  6. {
  7.     p = (void(*)(uint32_t))(0x20003000 - 0);
  8.     (*p)(0x1234);
  9.     while(1)
  10.     {
  11.         ........
  12.     }
  13. }
复制代码某函数通过分散加载的方式放在0x20003000地址(通过调试也确认函数地址正确)。调用函数时,通过函数指针方式调用。
比较奇葩的现象是,如果仿真单步执行,函数正常调用,且运行正常。如果直接连续运行,则在调用(*p)(0x1234)时进入HardFault中断。
但是,如果将跳转地址不按照4字节对齐(如0x20002FFF),则不管是连续运行还是单步运行,均正常。

另外使用p=&a;方式赋值时,也能正常运行。对比汇编,这种方式使用的汇编指令时BL.W,而直接给定地址时使用的汇编是BLX。如果原因是汇编指令的问题,仿真单步运行为什么又没问题!
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
15条回答
20061002838
1楼-- · 2019-12-11 00:14
Thumb模式和ARM模式的原因
根据arm spec, 跳转地址最低位( lsb ) 为0表示 arm 指令;最低位为1表示thumb指令。
STM32没有ARM模式,所以不能用四字节对齐的地址
参考:https://blog.csdn.net/beyond702/article/details/51201027
w282529350
2楼-- · 2019-12-11 05:53
你看下keil的编译map,函数地址并不是4字节对齐
jiaowoxiaolu
3楼-- · 2019-12-11 09:43
 精彩回答 2  元偷偷看……
20061002838
4楼-- · 2019-12-11 11:34
补充一条 LZ应该用0x20003000+1这个地址
0x20002FFF这个地址歪打正着是因为那里的flash是空白的,是0xFF,被当做NOP指令处理,因此没造成任何影响。如果那个位置有其他数据,跳过去会出事
liansh2002
5楼-- · 2019-12-11 15:12
20061002838 发表于 2018-4-9 16:22
Thumb模式和ARM模式的原因
根据arm spec, 跳转地址最低位( lsb ) 为0表示 arm 指令;最低位为1表示thumb指 ...

感谢大佬,学习了。google了半天,都没找到关键点,来论坛一问,几分钟就解决了
liansh2002
6楼-- · 2019-12-11 20:55
20061002838 发表于 2018-4-9 16:45
补充一条 LZ应该用0x20003000+1这个地址
0x20002FFF这个地址歪打正着是因为那里的flash是空白的,是0xFF, ...

是的是的,因为在调试,我就试着把地址加一或者减一,减一会刚好跳转到一个空指令地方,加一正好。但是这么做自己心理没底,所以就来论坛问问

一周热门 更多>