Assembly 为什么在从引导加载程序跳转到应用程序之前需要更新堆栈指针

Assembly 为什么在从引导加载程序跳转到应用程序之前需要更新堆栈指针,assembly,arm,embedded,stm32,bootloader,Assembly,Arm,Embedded,Stm32,Bootloader,当从引导加载程序跳到应用程序时,我们通常将堆栈指针更新为应用程序堆栈指针,然后更新程序计数器以重置应用程序的\u处理程序 void jump_to_application(void) { /* Function pointer to the address of the user application. */ fnc_ptr_for_app jump_to_app; jump_to_app = (fnc_ptr_for_app)(*(volatile uint32_t*

当从引导加载程序跳到应用程序时,我们通常将堆栈指针更新为应用程序堆栈指针,然后更新程序计数器以重置应用程序的\u处理程序

void jump_to_application(void)
{
    /* Function pointer to the address of the user application. */
    fnc_ptr_for_app jump_to_app;
    jump_to_app = (fnc_ptr_for_app)(*(volatile uint32_t*) (FLASH_APP_START_ADDRESS+4u));
    __CRC_CLK_DISABLE();
    HAL_DeInit();

    /* Change the main stack pointer. */
    __set_MSP(*(volatile uint32_t*)FLASH_APP_START_ADDRESS);

    jump_to_app();
}
下面是Reset_处理程序的第一行代码,它将堆栈指针初始化为自己的堆栈指针值

Reset_Handler:
ldr   sp, =_estack    /* Atollic update: set stack pointer */

/* Copy the data segment initializers from flash to SRAM */
movs    r1, #0
b   LoopCopyDataInit
但仍然建议使用应用程序的堆栈指针更新堆栈指针


为什么需要它,如果我们在ARM Cortex-M中不更新它而跳转,会有什么副作用?初始堆栈指针存储在向量表的前4个字节中,初始程序计数器存储在后4个字节中。重置时,硬件将从这8个字节加载SP和PC。例如,这允许Cortex-M启动代码用C而不是汇编语言编写

引导加载程序通过将硬件取消初始化为其重置状态,并从应用程序的向量表加载SP和PC,来模拟这种重置行为。这使得应用程序可以像从重置开始一样启动,而不依赖引导加载程序的任何初始化或设置

引导加载程序与应用程序分开编译和链接,并且必须能够加载具有适当起始地址的任何应用程序代码。因此,引导加载程序无法确定或强制任何加载的应用程序代码将设置堆栈指针,因为它可能合理地假设硬件已经设置了堆栈指针。在这种情况下,
\u estack!=*(易失性uint32\u t*)FLASH\u应用程序\u开始\u地址)
在任何情况下

引导加载程序的一个观察结果是,它没有将向量表设置为应用程序的向量表,这有潜在的危险-如果启动代码在没有首先设置向量表的情况下启用中断,则可能会导致引导加载程序中断处理程序被错误调用。更安全的做法是:

// Switch vector table
SCB->VTOR = APPLICATION_START_ADDR ;
之前,跳转到应用程序()
。或者,如果您选择使用HAL:

NVIC_SetVectorTable( NVIC_VectTab_FLASH, APPLICATION_START_ADDR ) ;

让我重申一下我的理解,如果应用程序启动正在进行堆栈指针更新,那么就不需要从引导加载程序设置堆栈指针,但这是一个很好的选择,因为它不会假设与应用程序有关的任何内容。如果我的理解有误,请纠正。非常感谢您建议向量表更新,它将在应用程序启动过程中进行,并确保以正确的方式进行处理。如果应用程序仅在更新重置向量后才启用中断,那么它是在引导加载程序中使用的好方法还是必须使用的方法。@ABLELDHOSE:我不会这样说-不是不正确,而是强调错误。引导加载程序不知道应用程序代码可能做什么,因此在这件事上没有真正的选择。建议“不需要从引导加载器设置堆栈指针”是危险的-相反,对于某些碰巧设置SP的应用程序,引导加载器可能在没有设置堆栈指针的情况下工作。在Cortex-M上,由于正常的重置行为,应用程序很可能不会工作。并非所有Cortex ms都实现了双堆栈指针。实现不是您所认为的那种PITA。而且,不,你不需要这样做。如果您是一个引导加载程序,在启动应用程序时不希望返回,那么应用程序可以完全控制堆栈/处理器,因此不需要做很多事情。如果是RTOS而不是引导加载程序,好的,那么您确实需要处理应用程序的堆栈指针,以便其堆栈不会影响RTO或其他应用程序。副作用是代码可能更易于编写/管理。如果使用HAL或其他库,那么您需要遵守该库的规则,就像在引导加载程序或RTO下一样期望保持常驻状态或获得回报。那么,您为什么在此设备上使用引导加载程序,不是您不能也不是人们不可以,而是引导加载程序在电路编程选项可用的情况下为您做了什么。@旧的\u计时器引导加载程序需要执行FOTA(固件无线)更新。应用程序将把新的fw写入一个临时位置,然后自行复位,引导加载程序将用新固件覆盖实际的应用程序区域。