STM32的启动文件中,包含了一些可被外部调用的变量,如__Vectors、__Vectors_End等:
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
...
DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
在某些特定场景下,这些变量会很有用,比如确定向量表大小。对于这些符号的含义,网上可以找到一些说明,但是其作用机理,没多少人提及。当然也许是懂汇编的人一眼就能看出,不屑于写出说明。
我们在某个c文件中做如下调用:
extern uint32_t __Vectors;
extern uint32_t __Vectors_End;
extern uint32_t __DEVICE_INFO;
uint32_t *pVectors;
uint32_t *pVectorsEnd;
volatile uint32_t VectorsSize;
void asmVectorDemo(void)
{
pVectors = &__Vectors;
pVectorsEnd = &__Vectors_End;
VectorsSize = (uint32_t)pVectorsEnd - (uint32_t)pVectors;
}
调试观察,可以发现各个变量的真实数值:
__Vectors = 0x20003608 //这个值实际上是__initial_sp的地址,&__initial_sp可以获取到
__Vectors_End = 0x200013A4//
VectorsSize = 0x000000EC
pVectors = 0x08000000 &__Vectors
pVectorsEnd = 0x080000EC &__Vectors_End
由此可以初步得出结论:
汇编文件中DCD分配一个4字节空间,并将变量的地址(取指针)保存下来。对应的标号值就是该指针值
这样,就可以方便地在汇编文件中添加一些固有信息,用于标记固件的版本、编译日期等。举例如下,先在c文件中添加变量:
extern uint32_t __Device_Info;
char * deviceInfo = "this is a demo string";
char * pDeviceInfo;
void asmVectorDemo(void)
{
...
pDeviceInfo = (char*)(*(uint32_t*)__DEVICE_INFO);
}
再修改汇编文件:
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
EXPORT __Device_Info
IMPORT deviceInfo
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD __Device_Info ; Reserved
DCD 0 ; Reserved
...
DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
__Device_Info DCD deviceInfo
调试观察,可以看到:
__Device_Info=0x200013A4
deviceInfo = 0x0800A728 "this is a demo string"
&deviceInfo = 0x200013A4 &deviceInfo
*(uint32_t*)__Device_Info=0x0800A728
pDeviceInfo=0x0800A728 "this is a demo string"
通过对汇编文件中变量的多次寻址、变换,得到了在c文件中定义的变量的内容。
这样做的主要价值,是在做Bootloader启动时、IAP升级时,对升级固件的合法性做全面的校验。Bootloader启动时,并不能直接获取新固件中由C文件定义的变量的地址、内容,而对于特定的cortex-m系列单片机,其启动文件格式的固定的,我们在固定偏移地址0x20处填充了“deviceInfo”的地址,就可以根据这个地址去计算偏移量,从而找到真正的deviceInfo在新固件中的存储位置。