stm32程序编译后map文件函数地址和函数实际运行地址不一致问题探究

1. 先描述一下情况

stm32f103,keil-mdk编译后,生成的map文件如下,发现编译出来的所有函数地址,竟然是奇数地址

运行调试,实际情况如下,发现调试器显示(或者直接查看内存区),显示的函数地址如下,竟然都是偶数地址了,和上面的地址相差1,每个函数都是如此。

那么程序的编译地址和实际在存储器中运行的地址不一致?为什么呢。

为了回答这个问题,我们先来学一下基本相关知识

2. 基本相关知识

指令集方面:arm一般高端处理器,比如cortex-a系列,都是32位的arm指令。而cortex-m0,1,3,4等低端处理器,也叫做单片机,为了增加代码密度(同样存储器内可以存更多指令),用的是thumb指令集(而且仅支持这个指令集),这个指令集大多数指令是16位的,少数是32位的。这就是为什么上面的调试图中,看到指令都是两个字节,而有的是4个字节。比较老的arm7,arm9等处理器,支持thumb指令和arm指令,需要通过指令告诉处理器,显式的进行指令转换,这个因此需要编译器提供支持。具体细节看我这篇文章https://biao2488890051.blog.csdn.net/article/details/122374552

arm中指令在存储器中真实地址,总是2字节或者4字节对齐的。

因为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为奇数。参考文章:STM32 ARM IAR 函数指针跳转处理要点 - 上下求索之 - 博客园

3. 问题原因

那么问题来了,编译器编译出来的函数地址(会通过跳转进来才能执行的)是奇数,不就没有2字节对齐了了嘛,其实这是下载器做了一个程序整体的移位,把地址整体-1放入的实际存储地址,这也所有的指令就是2字节对齐的,但是指令中的跳转的地址还是奇数,执行到这行指令的时候,加载给pc或者blx rx指令的地址是个奇数,但是实际跳转时候,pc会自动-1,因此就能自动跳转到正确的函数入口地址啦,同时,又不违背thumb指令定义和指令真是地址的2字节对齐访问要求。

因此map文件中,确实是函数的编译地址,但是实际放入存储器中的地址,都是实际-1的了。

我们再来做一个实验,我这里准备做一个gcc做独立编译程序的动态加载功能。gcc加了编译选项(这个可以参数这个文章STM32F gcc编译全纪录_人之生-CSDN博客_gcc编译stm32程序)后,生成的跳转指令的目标地址确实都是奇数了(动态加载函数的内部函数跳转都是自动正确了),但是该函数实际存放的是偶数存储空间,如下图所示:

版权声明:本文为CSDN博主「标biao」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/kangkanglhb88008/article/details/122354721

生成海报
点赞 0

标biao

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

STM32F2————配置时钟延迟不准的问题

STM32F2配置时钟问题 笔者在本科毕业设计使用STM32F207芯片,但是在配置时钟时出现了问题。 问题 我按照F1写代码的延时函数放在F2竟然不准了 换个办法 使用Systick时钟也是不准,原因是笔者代

为什么重写printf函数没有用?

以前在网上找了无数方法去重写printf函数,但发现都没效果,今天偶然发现重写printf函数可以了,原因是以前没有勾选微库(Use MicroLlB)! 这里