Почему в сгенерированной сборке есть мертвый цикл для обработчика прерываний Cortex-M?

#gdb #microcontroller #cortex-m #cortex-m3 #thumb

#gdb #микроконтроллер #cortex-m #cortex-m3 #большой палец

Вопрос:

Я изучаю Cortex-M с помощью IDE MDK uVision. Я написал простой SysTick_Handler() способ заменить СЛАБОЕ значение по умолчанию SysTick_Handler() , которое представляет собой простой мертвый цикл.

Мой SysTick_Handler() :

введите описание изображения здесь

Разборка:

введите описание изображения здесь

Меня смущает выделенная строка сборки. Это просто мертвый цикл.

Почему он там? Почему набор инструментов все еще генерирует его, несмотря на то, что я уже перезаписал СЛАБУЮ реализацию по умолчанию своей собственной SysTick_Handler ?

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

Но странно то, что если я удалю точку останова в этой строке, тогда можно будет получить доступ к моему коду. Как это возможно?

Комментарии:

1. Похоже, что разборка не соответствует вашей функции должным образом, т. Е. Отключена на несколько байтов. Это также повлияло бы на точку останова. Мертвый цикл часто используется в качестве обработчика прерываний по умолчанию для немаскируемых прерываний. Таким образом, следует ожидать, что такой код будет найден где-то в вашем двоичном файле.

2. Я согласен с @Codo. Вполне возможно, что отладчик каким-то образом перепутал СЛАБУЮ ссылку и принял неправильный адрес.

3. Да, я сохранил реализацию по умолчанию, которая является мертвым циклом. Это действительно вводит в заблуждение, если отладчик может быть сбит с толку таким образом…

4. дизассемблеры изо всех сил пытаются просто разобрать машинный код, при оптимизации кода нет причин когда-либо предполагать, что высокий уровень и низкий уровень совпадают, а тем более полагаться на это. Отключите отображение языка высокого уровня, и вы будете золотыми, хорошо с такой архитектурой, которая имеет половину шансов на дизассемблирование машинного кода… Если вы хотите точно установить точку останова, не используйте отладчик с графическим интерфейсом, разберитесь сами и используйте что-то вроде openocd с интерфейсом telnet.

5. Это похоже на другой обработчик, который представляет собой бесконечный цикл, nop там, чтобы выровнять его по границе слова.

Ответ №1:

(Спасибо всем подсказкам, предоставленным сообществом. Думаю, теперь я могу это объяснить.)

Мертвый цикл является частью моей main() функции, которая похожа на приведенную ниже. main() Функция находится чуть выше моей SysTick_Handler в том же файле C.

 int main (void)
{
    LED_Initialize();
    SysTick->VAL = 0x9000;                                                                                   
    //Start value for the sys Tick counter
    SysTick->LOAD = 0x9000;                                                                                  
    //Reload value 
    SysTick->CTRL = SYSTICK_INTERRUPT_ENABLE|SYSTICK_COUNT_ENABLE;  //Start and enable interrupt
    while(1)
    {
        ;  // <========= This is the dead loop I saw!
    }
}
  

Для двойного подтверждения я изменил цикл while на следующий:

 int main (void)
{
    volatile int32_t jj = 0;
    LED_Initialize();
    SysTick->VAL = 0x9000;                                                                                  //Start value for the sys Tick counter
    SysTick->LOAD = 0x9000;                                                                                 //Reload value 
    SysTick->CTRL = SYSTICK_INTERRUPT_ENABLE|SYSTICK_COUNT_ENABLE;  //Start and enable interrupt
    while(1)
    {
        ;
        jj =0x12345; // <====== add some landmark value
    }
}

  

Сгенерированный код теперь выглядит так:

введите описание изображения здесь

Хотя он по-прежнему находится под SysTick_Handler . Я помещаю туда точку останова, чтобы проверить, что происходит на самом деле:

введите описание изображения здесь

введите описание изображения здесь

Это R1 константа 0x12345 . Это R0 локальная переменная jj . Мы видим R1 , что содержит значение ориентира 0x12345 , которое добавляется в R0 ( jj ) . Так что это должно быть частью моего while(1) цикла в main() .

Итак, дизассемблирование выполнено правильно. Только то, что отладчику не удалось обеспечить правильное чередование между исходным кодом и дизассемблированием.

И, кстати, не забудьте перестроить цель после изменения кода, иначе отладчик uVision IDE не будет отражать последние изменения….