Ассемблер IAR BKPT непосредственно в качестве входного операнда

Я пишу флэш-загрузчик для устройства Cortex M4 и хочу «вернуть» значение для управляющего приложения ПК, используя непосредственное значение инструкции точки останова.

В то время как жесткое кодирование немедленно работает нормально:

__asm("bkpt 0x70");
__asm("bkpt %0" : : "i" (0x70));

как только я хочу "вернуть" что-то зависящее от времени выполнения, например

uint8_t status = Flash_EraseAll();
__asm("bkpt %0" : : "i" (status));

Компиляция не работает с

Error[Ta090]: Immediate operand is not constant

Я пытался использовать макросы препроцессора с различными настройками конкатенации, но безрезультатно.

Кто-нибудь понял, как я могу ввести флаги состояния, зависящие от времени выполнения, в блок __asm() в IAR как немедленный? Основываясь на том, что я прочитал здесь, это не совсем возможно, но может быть хитрый хакерский способ сделать это.

P.S.: Да, в качестве обходного пути я мог бы использовать оператор switch, в котором я перечисляю и жестко закодирую каждое возможное состояние, но это просто уродливо и долго.

Ваше решение небезопасно, так как вы изменяете sp в первом операторе ASM. Нажатие, точка останова и восстановление sp должны быть в одном операторе asm.

Timothy Baldwin 05.06.2019 18:13

@TimothyBaldwin Это может объяснить пару странных поступков, которые у меня возникают. Прежде чем я изменю свое редактирование, не могли бы вы пояснить, насколько это небезопасно? Что может случиться с устройством/стеком в рабочем корпусе? Я должен добавить, что __("bkpt 0x0"); это последнее утверждение моего кода

davidanderle 05.06.2019 18:31

Опубликуйте свой ответ как ответ, где люди могут проголосовать за него. Не присваивайте ему особый статус, редактируя его в вопрос. Если это лучше, чем (неполный) существующий ответ, вы можете принять свой собственный ответ.

Peter Cordes 11.06.2019 19:06

@PeterCordes Спасибо за подсказку, я изменил тему.

davidanderle 12.06.2019 10:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
512
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Что-то вроде этого (псевдокод):

__asm("push %0" : : "i" (status));
__asm("bkpt %0" : : "i" (0x70));

Конечно, вы не должны забывать после этого очищать стек.

Поскольку bkpt закодирован только с немедленным, вы, очевидно, не можете изменить это во время выполнения, так как вам придется изменить код.

Хм... Это неплохая идея и кажется достаточно простой. Не думал об этом. Я подожду некоторое время, чтобы увидеть, есть ли у кого-нибудь дополнительные мысли по этому поводу. Спасибо!

davidanderle 28.05.2019 17:10

Обе инструкции должны быть частью одного ассемблерного оператора, иначе компилятор может принять решение поместить некоторые сгенерированные компилятором инструкции между этими операторами. Кроме того, предположительно вам нужно очистить стек после возобновления. (пинг @davidanderle). Кроме того, очевидно, что вам нужно ограничение, отличное от "i" для status, потому что "i" требует константы времени компиляции для замены в качестве немедленной. Вероятно, вы хотите "r"(status), и вы можете снова просто жестко закодировать bkpt 0x70, если только вы не хотите установить число с помощью определения макроса C.

Peter Cordes 11.06.2019 19:04
Ответ принят как подходящий

Основываясь на идее @Деволус, я получил следующее:

    uint32_t status = Flash_EraseAll();
    __asm volatile ("str %0, [sp, #-4]!\n\t"   // Push to stack
                    "bkpt 0x0\n\t"             // Halt CPU
                    "add sp, sp, #4\n\t"       // Restore SP
                    : : "r"(status));          // status as input to __asm()

Инструкции по ассемблеру говорят компилятору поместить переменную состояния в удобный регистр «r» и сохранить содержимое этого регистра по предварительно уменьшенному адресу указателя стека, а затем остановить выполнение ЦП с немедленным 0.

Приложение для вождения будет опрашивать цель, если она будет остановлена ​​(попадание bkpt). Если оно остановлено, прочитав 16-битные данные под текущим ПК (__asm("bkpt 0x00") -> 0xbe00 -> #imm = 0xbe00 & 0x00ff = 0), приложение может убедиться, что выполнение остановилось в нужном месте. место. Затем он будет считывать 32-битные данные по конечному адресу SP, чтобы получить статус выполнения встроенного кода.

Таким образом, вместо статического 8-битного кода непосредственно из bkpt, можно динамически "сообщать" больше информации во внешний мир (32-битный в данном случае).

Как подчеркивается в @ПитерКордес, операторы push и bkpt должны находиться в одной и той же инструкции встроенного ассемблера, иначе компилятор может решить вставить код между операторами. Кроме того, значение SP должно быть восстановлено до значения, предшествующего __asm(), поскольку компилятор берет на себя единоличный контроль над SP.

Вы нигде не упоминаете о восстановлении SP. С этим ассемблером обработчик точки останова должен добавить 4 к SP перед возобновлением работы, иначе встроенный ассемблер модифицировал SP без уведомления компилятора.

Peter Cordes 12.06.2019 12:45

@PeterCordes Это был конец моей программы, поэтому мне не нужно было ничего восстанавливать. Я думаю, если кто-то захочет сделать что-то еще после возобновления выполнения из bkpt, они могут просто добавить «добавить sp, sp, # 4», чтобы отменить то, что сделал str?

davidanderle 12.06.2019 15:05

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

Peter Cordes 12.06.2019 15:11

@PeterCordes Спасибо за помощь, очень признателен!

davidanderle 12.06.2019 15:12

Другие вопросы по теме