【问题标题】:Jumping program counter to new location将程序计数器跳转到新位置
【发布时间】:2017-03-28 18:10:16
【问题描述】:

我正在使用标准代码使用 keil uvision 将其他程序闪存到我的 stm32f4 板的闪存中。我需要在我的板上有两个代码。但是我怎样才能将我的程序计数器从一个位置转移到另一个位置,以便在需要时执行这两个程序。
下面是我正在使用的一段代码,但 PC 没有跳转。我认为跳转到应用程序有问题

#include "usbh_core.h"
#include "usbh_usr.h"
#include "usbh_msc_core.h"
#include "flash_if.h"

USB_OTG_CORE_HANDLE          USB_OTG_Core;
USBH_HOST                    USB_Host;

pFunction Jump_To_Application;
uint32_t JumpAddress;


int main(void)
{

BSP_Init();


FLASH_If_FlashUnlock();



if (STM_EVAL_PBGetState(BUTTON_USER) == Bit_RESET)
{
/* Check Vector Table: Test if user code is programmed starting from address 
   "APPLICATION_ADDRESS" */
 if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
{
  /* Jump to user application */
  JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
  Jump_To_Application = (pFunction) JumpAddress;
  /* Initialize user application's Stack Pointer */
 __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
         __set_PSP(*(__IO uint32_t*) APPLICATION_ADDRESS);

  Jump_To_Application();
}
}

  /* Init Host Library */
 USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USB_Host, &USBH_MSC_cb, &USR_Callbacks);

while (1)
 {
   /* Host Task handler */
    USBH_Process(&USB_OTG_Core, &USB_Host);
 }
}


 #ifdef USE_FULL_ASSERT
    void assert_failed(uint8_t* file, uint32_t line)
   {

    /* Infinite loop */
    while (1)
     {}
    }
     #endif

【问题讨论】:

标签: c arm keil


【解决方案1】:
.global BRANCHTO
BRANCHTO:
   bx r0

编辑

几秒钟的谷歌搜索发现了函数指针的基础知识(在 StackOverflow 上不少于)

void (*funadd) ( void );
void fun ( void )
{
    funadd=(void *)0x12345678;
    (*funadd)();
}

00000000 <fun>:
   0:   e59f2008    ldr r2, [pc, #8]    ; 10 <fun+0x10>
   4:   e59f1008    ldr r1, [pc, #8]    ; 14 <fun+0x14>
   8:   e5821000    str r1, [r2]
   c:   e12fff11    bx  r1
  10:   00000000    andeq   r0, r0, r0
  14:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

正如我的汇编函数显示的那样(基本上是尾部优化)

但是如果你想看到它设置一个返回地址,那么你必须强制它

unsigned int (*funadd) ( void );
unsigned int fun ( void )
{
    funadd=(unsigned int *)0x12345678;
    return((*funadd)()+1);
}

00000000 <fun>:
   0:   e59f201c    ldr r2, [pc, #28]   ; 24 <fun+0x24>
   4:   e59f101c    ldr r1, [pc, #28]   ; 28 <fun+0x28>
   8:   e92d4010    push    {r4, lr}
   c:   e5821000    str r1, [r2]
  10:   e1a0e00f    mov lr, pc
  14:   e12fff11    bx  r1
  18:   e8bd4010    pop {r4, lr}
  1c:   e2800001    add r0, r0, #1
  20:   e12fff1e    bx  lr
  24:   00000000    andeq   r0, r0, r0
  28:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

EDIT2:

void BRANCHTO ( unsigned int );
void fun ( void )
{
    BRANCHTO(0x12345678);
}

00000000 <fun>:
   0:   e92d4010    push    {r4, lr}
   4:   e59f0008    ldr r0, [pc, #8]    ; 14 <fun+0x14>
   8:   ebfffffe    bl  0 <BRANCHTO>
   c:   e8bd4010    pop {r4, lr}
  10:   e12fff1e    bx  lr
  14:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

LR 由 bl 处理到 BRANCHTO,branchto 只是一个尾部优化传递,只是将 lr 推到那里并分支链接然后返回然后弹出然后返回是一种浪费。

可以将分支实现为内联汇编,但内联汇编通常非常丑陋,不那么可移植,只是一团糟,真正的汇编要好得多,还有一些工具链可以让你直接将它提供给编译器是您不知道如何调用汇编程序的情况。我几乎从不运行 Windows,所以没有尽可能多地安装 Kiel(它们曾经包含一个简化的 RVCT 编译器,玩起来很有趣)。

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
  • 虽然这可行,但问题是针对 C 语言,并且使用函数指针而不是汇编程序。行为也会略有不同,调用函数指针将创建分支和链接,而您的版本不会更新LR
  • 当你从 C 调用 BRANCHTO 时,它会设置 LR 进行返回,那里没有问题。 C 编译成汇编语言,然后被汇编成一个对象,获得你想要的最干净的方法是跳过这一步,直接进入汇编程序。要在 c 中执行此操作,您需要创建一个虚拟 void 函数并更改其地址然后调用它。
猜你喜欢
  • 1970-01-01
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
  • 2012-06-15
  • 2017-07-02
  • 2019-10-02
  • 1970-01-01
相关资源
最近更新 更多