【发布时间】:2017-11-03 02:14:13
【问题描述】:
我有一个非常小的引导加载程序,它位于基于 STM32F405VGT 芯片的定制设计板上运行的主固件前面。它对两个应用程序都有相当少的修改 startup.s 和链接器文件。主应用程序在加载到闪存的根目录时运行良好,但不会从引导加载程序启动。
当单步执行代码时,一旦它尝试启动应用程序,程序就会以 WWDG_IRQHandler 结束,它是 Default_Handler 的别名,只是在无限循环中坐下来旋转(WWDG 对引导加载程序禁用) .
引导加载程序代码:
uint32_t addr = 0x08010000;
/* Get the application stack pointer (First entry in the application vector table) */
uint32_t appStack = (uint32_t) *((__IO uint32_t*) addr);
/* Get the application entry point (Second entry in the application vector table) */
ApplicationEntryPoint entryPoint = (ApplicationEntryPoint)*((__IO uint32_t*)(addr + sizeof(uint32_t)));
/* would expect the value of entryPoint to be 0x802bc9c based on the values in the .map file as well as the actual values downloaded from the image using openocd. Instead, it comes back as 0x802bc9d, not sure if this is related to THUMB code */
/* Reconfigure vector table offset register to match the application location */
SCB->VTOR = addr;
/* Set the application stack pointer */
__set_MSP(appStack);
/* Start the application */
entryPoint();
这是应用程序的 .ld 文件:
/* Include memory map */
/* Uncomment this section to use the real memory map */
MEMORY
{
BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 32K
USER_PROPS (rw) : ORIGIN = 0x08008000, LENGTH = 16K
SYS_PROPS (r) : ORIGIN = 0x0800C000, LENGTH = 16K
APP_CODE (rx) : ORIGIN = 0x08010000, LENGTH = 448K
SWAP (rx) : ORIGIN = 0x08070000, LENGTH = 384K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
BOOT_RAM (xrw) : ORIGIN = 0x2001E000, LENGTH = 8K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
/* Uncomment this section to load directly into root memory */
/*
MEMORY
{
APP_CODE (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
*/
/* Highest address of the user mode stack */
_estack = 0x20020000; /* end of 128K RAM */
/* Entry Point */
ENTRY(Reset_Handler)
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x000; /* required amount of heap (none) */
_Min_Stack_Size = 0x400; /* required amount of stack */
SECTIONS
{
/* The startup code goes first into EEPROM */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >APP_CODE
/* The program code and other data goes into EEPROM */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >APP_CODE
/* Constant data goes into EEPROM */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >APP_CODE
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >APP_CODE
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >APP_CODE
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >APP_CODE
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> APP_CODE
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
引导加载程序 .ld 是相同的,除了所有对 APP_CODE 的引用都替换为 BOOTLOADER
这是引导加载程序的 startup.s 文件。应用程序的 startup.s 文件是相同的,除了 Boot_Reset_Handler 被称为 Reset_Handler :
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Boot_Reset_Handler
.weak Boot_Reset_Handler
.type Boot_Reset_Handler, %function
Boot_Reset_Handler:
ldr sp, =_estack /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
bx lr
.size Boot_Reset_Handler, .-Boot_Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
* @param None
* @retval None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Boot_Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
...
我想指出,这不是与Bootloader for Cortex M4 - Jump to loaded Application 的重复,尽管问题看起来很相似,但该帖子的作者没有充分解释问题是如何解决的。
一切都是使用用于嵌入式开发的标准 gcc 工具构建的。
【问题讨论】:
-
实际跳转/调用周围的反汇编是什么样的?
-
以及应用程序的向量表的反汇编。
-
您是否正在链接 CMSIS 和/或类似于
system_stm32f4xx.c的文件?该文件可能有一个名为SystemInit()的函数,它将SCB->VTOR设置为与您期望的值不同的值。您可能需要编辑该文件并设置VECT_TAB_OFFSET的值以满足您的期望。 -
@kkrambo 你或多或少是正确的。有一个类似的函数,但不在同一个文件中,它确实重置了向量表。一旦我删除了该调用,它就会按预期工作。谢谢。
-
那是什么功能?!
标签: c assembly linker arm embedded