Как мне перейти / перейти к произвольному адресу в Clang? - PullRequest
0 голосов
/ 07 декабря 2018

Я использую 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}");
}

Пошагово, значения в регистрах, похоже, меняются так же, как и раньше.Но версия ARMCC переходит на загрузчик на BLX, а версия Clang сбрасывается.Адрес, извлеченный из таблицы векторов, в обоих случаях одинаков.

Я видел упоминания о том, что Clang не допускает такого рода вещей, как комментарий к этому ответу .Но должен быть способ вернуться к загрузчику.Что мне не хватает?Есть ли какие-либо настройки в компоновщике, которые мне нужно включить, чтобы разрешить такое поведение?


Обновление

Некоторые комментарии приводят меня к поиску лучшего способа сброса, который приводит меня к эта статья , в которой обсуждается сброс процессора путем записи в бит SYSTEMRESETREQ регистра управления прерываниями и сбросом приложения (AIRCR).Что привело меня к поиску этой функции в заголовочном файле 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();
  }
}

Однако приложение по-прежнему перезагружается без запуска загрузчика.

Дополнительная информация

Загрузчик и приложение - это отдельные проекты.Приложение работает под управлением ОС Keil RTX со слоем CMSIS.Я думаю, что приложение работает в собственном адресном пространстве и не знает о загрузчике.Поэтому, когда он сбрасывается, он сбрасывается только в пределах своего собственного адресного пространства, и загрузчик никогда не запускается.

Я попытался сообщить приложению о загрузчике, добавив это в мой файл разброса.

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

1 Ответ

0 голосов
/ 08 декабря 2018

какая версия 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.

...