STM32 ARM IAR 函数指针跳转处理要点
问题: 如何实现A.bin 的程序调用B.bin的程序?
问题:IAR里面可以单步调试但是不能全速运行。
问题: 如何实现动态链接库
来源 https://bbs.21ic.com/icview-134389-999-1.html
问:
IAR调试的时候能单步执行,但是全速运行就会出现Hard Fault Exception
这是为什么啊???
花了快两天时间了,都没有解决问题。
还有更奇怪的是执行下面代码之后出现赋值不成功:
U32 FunBase;
FunBase = (U32)RAM_FLASH_START; // RAM_FLASH_START 是一个 void * 的函数首地址
RAM_FLASH_START 函数地址是0x6800EC10,但是执行上面的代码之后FunBase的值为 0x6800EC11 ,为什么会自动加 1 呢???
解决:
问题已经解决了,看来还是得靠自己
先把问题重新详细的描述一遍:
我把Nor Flash里的一个函数代码数据(函数首地址是:0x6400EC10)拷贝到RAM的 0x2000FC00,
然后把0x2000FC00加载给PC指针(为了让代码在RAM里运行),接着运行代码就出现了Hard Fault
Exception,而用 IAR 单步执行的时候能正常运行。同时我将一个函数地址值赋给一个unsigned int
变量之后发现自动加了1。对于这些问题先看权威指南里是怎么说的吧。
一,PC指针(程序计数器R15)(权威指南)
R15是程序计数器,在汇编代码中称为“PC指针”。因为CM3内部使用了指令流水线,读PC时返回的值
是当前指令的地址+4。比如说:
0x1000: MOV R0, PC ; R0 = 0x1004
如果向PC中写数据,就会引起一次程序的分支(但是不更新LR寄存器)。CM3中的指令至少是半字
对齐的,所以PC的LSB总是读回0。然而,在分支时,无论是直接写PC的值还是使用分支指令,都必
须保证加载到PC的数值是奇数(即LSB=1),用以表明这是在Thumb状态下执行。倘若写了0,则视
为企图转入ARM模式,CM3将产生一个fault异常。这些可以总结为读PC指针时,返回LSB总是为0;
写PC指针时,一定要保证LSB为奇数。
二,函数地址(自己总结的)
正如上面所说,写PC指针的时候必须保证LSB为奇数,如果执行跳转指令的时候,将一个函数指针
加载给PC,这时候就必须保证这个函数地址的LSB为奇数,而且还必须是(4*n+1)(n=0,1,2,3)
这样的奇数,只有这样运行程序才不会跑飞。在以后的编程中,如果执行函数跳转的时候,一定要
保证这个函数地址的低四位的值为(4*n+1)(n=0,1,2,3)。
基于上面两点,就可以很好的解释所出现的问题了,如果将0x2000FC00加载给PC指针,肯定会出现
Hard Fault Exception,因为 0x2000FC00 的 LSB = 0;但是如果将 0x2000FC01加载给PC指针,程
序就能正常运行了,这就应证了权威指南里所说的写PC指针的时候必须保证加载给PC的值的LSB为1
。
而之前的为什么用IAR单步执行能成功,原因是IAR的调试器做了处理,使得每一次调试的时候对PC
指针的LSB做了一个奇偶变换;当全速运行的时候,调试器不管用了,直接由CPU接管,这个时候将
函数地址加载给PC的值的LSB为偶数,当然导致程序跑飞了。
还有为什么将一个函数地址值赋给一个unsigned int 变量之后会自动加一呢,这个是Cortex-M3的一
个特性,也就是说读取一个函数地址值返回的LSB为0,当赋值给一个变量的时候会加1,这是为了将
这个变量值加载给PC指针之后保证PC指针的LSB为1。
问题解决了,希望对碰到同样问题的朋友能有所帮助。同时如果总结的不好,大家可以一起交流交流。