我正在为一个嵌入式项目使用,该项目会跳回引导加载程序进行更新。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}");
}跨过一步,寄存器中的值似乎与以前相同。但是ARMCC版本跳转到BLX上的引导加载程序,而Clang版本重置。从向量表中提取的地址在两种情况下都是相同的。
我见过有人提到Clang不允许类似于对这个答案的评论这样的事情。但是必须有一种方法可以跳回引导加载程序。我遗漏了什么?在我需要启用的链接器中有允许这种行为的设置吗?
更新
一些评论使我找到了一种更好的复位方法,它引导我到这篇文章,它讨论通过写入应用程序中断和复位控制寄存器(AIRCR)的SYSTEMRESETREQ位来重置处理器。这导致我在CMSIS头文件中找到了这个函数。我继承了代码,我不知道为什么不使用它。
/**
\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();
}
}但是,没有运行引导加载程序,应用程序仍然重新启动。
更多信息
引导加载程序和应用程序是单独的项目。该应用程序正在运行带有CMSIS层的Keil。我的想法是,应用程序在自己的地址空间中运行,不知道引导程序。因此,当它重置时,它只在自己的地址空间内重置,并且引导加载程序永远不会运行。
我试图向应用程序通知引导加载程序,将其添加到我的分散文件中。
LR_IROM0 0x00 0x00012000 {
ER_IROM0 0x0 0x00012000 {
.ANY (+RO)
}
}但结果是一样的。
澄清一下,我真的想重新设置处理器。我试图跳转到引导加载程序,同时告诉它这不是一个正常的引导,而是一个更新。
工具链版本
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生成组件
C代码:
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();
}ARMCC:
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嘎吱声:
.section .text.run_bootloader,"ax",%progbits
.hidden run_bootloader @ -- Begin function run_bootloader
.globl run_bootloader
.p2align 2
.type run_bootloader,%function
.code 16 @ @run_bootloader
.thumb_func
run_bootloader:
.Lfunc_begin2:
.loc 2 1338 0 @ ../_Primary/source/can_tools.c:1338:0
.fnstart
.cfi_startproc
@ BB#0:
.save {r7, lr}
push {r7, lr}
.Lcfi8:
.cfi_def_cfa_offset 8
.Lcfi9:
.cfi_offset lr, -4
.Lcfi10:
.cfi_offset r7, -8
.pad #8
sub sp, #8
.Lcfi11:
.cfi_def_cfa_offset 16
.Ltmp8:
.loc 2 1343 28 prologue_end @ ../_Primary/source/can_tools.c:1343:28
movs r0, #4
ldr r0, [r0]
.loc 2 1343 26 is_stmt 0 @ ../_Primary/source/can_tools.c:1343:26
str r0, [sp, #4]
.loc 2 1344 52 is_stmt 1 @ ../_Primary/source/can_tools.c:1344:52
ldr r0, [sp, #4]
.loc 2 1344 12 is_stmt 0 @ ../_Primary/source/can_tools.c:1344:12
str r0, [sp]
.loc 2 1345 5 is_stmt 1 @ ../_Primary/source/can_tools.c:1345:5
ldr r0, [sp]
blx r0
.loc 2 1346 1 @ ../_Primary/source/can_tools.c:1346:1
add sp, #8
pop {r7, pc}
.Ltmp9:
.Lfunc_end2:
.size run_bootloader, .Lfunc_end2-run_bootloader
.cfi_endproc
.cantunwind
.fnend
@ -- End function发布于 2018-12-08 03:58:58
什么版本的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的汇编中执行。
https://stackoverflow.com/questions/53671471
复制相似问题