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

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

My SysTick_Handler():

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

Разборка:

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

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

Почему это там? Почему инструментальная цепочка все еще генерировала его, несмотря на то, что я уже перезаписал WEAK-реализацию по умолчанию своей собственной SysTick_Handler?

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

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


person smwikipedia    schedule 05.10.2020    source источник
comment
Похоже, дизассемблирование не соответствует вашей функции должным образом, т.е. отстает на несколько байтов. Это также повлияет на точку останова. Мертвая петля часто используется в качестве обработчика прерываний по умолчанию для немаскируемых прерываний. Так что можно ожидать найти такой код где-то в вашем двоичном файле.   -  person Codo    schedule 05.10.2020
comment
Я согласен с @Codo. Вполне возможно, что отладчик как-то перепутал ссылку WEAK и взял не тот адрес.   -  person domen    schedule 05.10.2020
comment
Да, я сохранил реализацию по умолчанию, которая представляет собой мертвую петлю. Это действительно вводит в заблуждение, если отладчик может быть сбит с толку таким образом...   -  person smwikipedia    schedule 05.10.2020
comment
дизассемблеры изо всех сил пытаются просто дизассемблировать машинный код, с оптимизацией кода нет причин когда-либо предполагать, что высокий уровень и низкий уровень совпадают, не говоря уже о том, чтобы полагаться на это. Отключите отображение языка высокого уровня, и вы будете золотыми, ну с такой архитектурой, которая имеет половину шансов на дизассемблирование машинного кода... Если вы хотите точно установить точку останова, не используйте отладчик с графическим интерфейсом, разберитесь сами и используйте что-то типа openocd с telnet интерфейсом.   -  person old_timer    schedule 05.10.2020
comment
Это похоже на другой обработчик, который представляет собой бесконечный цикл, но нет возможности выровнять его по границе слова.   -  person old_timer    schedule 06.10.2020
comment
@old_timer Это очень возможно. Потому что у меня есть несколько других обработчиков мертвых циклов для других источников прерываний. И эта самая мертвая петля, о которой идет речь, может сработать. Я не думаю, что компоновщик все еще должен связывать символ WEAK в этом случае и отладчик, чтобы сделать такую ​​​​ошибку. Но он указан в SysTick_handler, хотя и без фигурной скобки, что делает его еще более странным. Вот такой странный результат приводит простая проба uVision IDE. Я должен сказать, что это разочаровывает.   -  person smwikipedia    schedule 06.10.2020


Ответы (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 не отразит последние изменения....

person smwikipedia    schedule 06.10.2020