如何分支/跳转到Clang中的任意地址?

时间:2018-12-07 14:25:04

标签: c gcc arm embedded clang

我将Keil µVision用于嵌入式项目,该项目跳回到引导加载程序进行更新。 Keil以前使用ARMCC作为编译器,以下代码可以正常工作。

void run_bootloader(void)
{
    uint32_t runBootloaderAddress;

    // Read the entry point from bootloader's vector table
    runBootloaderAddress = *(uint32_t*)(0x00000004);
    void (*runBootloader)(void) = (void (*) (void))runBootloaderAddress;
    runBootloader();
}

Keil正在使用较新版本的Clang进行转换,我正在尝试将代码移植过来。现在,在调用runBootloader()时,该代码将导致重置。

生成的程序集当然是不同的。因此,我从清单中拉出了ARMCC生成的程序集,并将其写为内联汇编器。

void run_bootloader(void)
{
    __asm("PUSH     {r4-r6,lr}");

    __asm("MOVS     r0,#0");
    __asm("LDR      r4,[r0,#4]");
    __asm("MOV      r5,r4");
    __asm("BLX      r5");

    __asm("POP      {r4-r6,pc}");
}

逐步执行,寄存器中的值似乎与以前相同。但是,在重置Clang版本时,ARMCC版本跳至BLX上的引导程序。从向量表中提取的地址在两者中是相同的。

我看到有人提到Clang不允许类似comment to this answer这样的事情。但是必须有一种方法可以跳回到引导加载程序。我想念什么?我需要启用链接器中的某些设置才能允许这种行为吗?


更新

一些评论使我寻找一种更好的重置方法,这使我进入this article,其中讨论了通过写入应用程序中断和重置控制寄存器的SYSTEMRESETREQ位({{ 1}})。这导致我在CMSIS头文件中找到此功能。我继承了代码,不知道为什么没有使用它。

AIRCR

但是,应用程序仍然在不运行引导加载程序的情况下重新引导。

更多信息

引导程序和应用程序是单独的项目。该应用程序正在运行带有CMSIS层的Keil RTX OS。我的想法是该应用程序正在其自己的地址空间中运行,并且不知道引导加载程序。因此,当它复位时,它只会在自己的地址空间内复位,并且引导加载程序永远不会运行。

我试图通过将引导加载程序添加到我的分散文件中来通知应用程序。

/**
  \brief   System Reset
  \details Initiates a system reset request to reset the MCU.
 */
__STATIC_INLINE void __NVIC_SystemReset(void)
{
  __DSB();                                                          /* Ensure all outstanding memory accesses included
                                                                       buffered write are completed before reset */
  SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |
                           (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
                            SCB_AIRCR_SYSRESETREQ_Msk    );         /* Keep priority group unchanged */
  __DSB();                                                          /* Ensure completion of memory access */

  for(;;)                                                           /* wait until reset */
  {
    __NOP();
  }
}

但是结果是一样的。

为了澄清,我实际上是在尝试重置处理器。我正在尝试跳至引导加载程序,同时向其传达的信息不是正常引导,而是更新。


工具链版本

LR_IROM0 0x00  0x00012000   {
  ER_IROM0 0x0 0x00012000   {
   .ANY (+RO)
  }
}

生成的程序集

C代码:

PS C:\Keil_v5\ARM\ARMCC\bin> .\armcc.exe --version_number
5060750

PS C:\Keil_v5\ARM\ARMCLANG\bin> .\armclang.exe --version
Product: MDK Plus 5.25 (Flex)
Component: ARM Compiler 6.9
Tool: armclang [5ced1d00]

Target: unspecified-arm-none-unspecified

ARMCC:

void run_bootloader(void)
{
    volatile uint32_t runBootloaderAddress;

    // Read the entry point from bootloader's vector table
    runBootloaderAddress = *(uint32_t*)(0x00000004);
    void (*runBootloader)(void) = (void (*) (void))runBootloaderAddress;
    runBootloader();
}

C语:

                          AREA ||i.run_bootloader||, CODE, READONLY, ALIGN=1

                  run_bootloader PROC
;;;1335   }
;;;1336   void run_bootloader(void)
000000  b570              PUSH     {r4-r6,lr}
;;;1337   {
;;;1338   uint32_t runBootloaderAddress;
;;;1339   
;;;1340   // Read the entry point from bootloader's vector table
;;;1341   runBootloaderAddress = *(uint32_t*)(0x00000004);
000002  2000              MOVS     r0,#0
000004  6844              LDR      r4,[r0,#4]
;;;1342   void (*runBootloader)(void) = (void (*) (void))runBootloaderAddress;
000006  4625              MOV      r5,r4
;;;1343   runBootloader();
000008  47a8              BLX      r5
;;;1344   }
00000a  bd70              POP      {r4-r6,pc}
;;;1345   
                          ENDP

1 个答案:

答案 0 :(得分:0)

什么版本的clang及其如何使用?

void run_bootloader(void)
{
    uint32_t runBootloaderAddress;

    // Read the entry point from bootloader's vector table
    runBootloaderAddress = *(uint32_t*)(0x00000004);
    void (*runBootloader)(void) = (void (*) (void))runBootloaderAddress;
    runBootloader();
}

gcc 8.2.0

00000000 <run_bootloader>:
   0:   2304        movs    r3, #4
   2:   b510        push    {r4, lr}
   4:   681b        ldr r3, [r3, #0]
   6:   4798        blx r3
   8:   bd10        pop {r4, pc}
   a:   46c0        nop         ; (mov r8, r8)

clang / llvm 3.8.0

00000000 <run_bootloader>:
   0:   b580        push    {r7, lr}
   2:   af00        add r7, sp, #0
   4:   2004        movs    r0, #4
   6:   6800        ldr r0, [r0, #0]
   8:   4780        blx r0
   a:   bd80        pop {r7, pc}

两者都应该像使用blx而不是bl时一样正常工作。

如果您需要执行类似的操作,但仍要模拟重置,则

.thumb
mov r0,#0
ldr r1,[r0,#0]
ldr r2,[r0,#4]
mov sp,r1
bx r2

00000000 <.text>:
   0:   2000        movs    r0, #0
   2:   6801        ldr r1, [r0, #0]
   4:   6842        ldr r2, [r0, #4]
   6:   468d        mov sp, r1
   8:   4710        bx  r2

并在未编译的C语言中进行汇编。