Неправильная структура стека с G CC и STM32 - PullRequest
2 голосов
/ 03 февраля 2020

Я пытаюсь создать простой обработчик SV C в GNU G CC (не ARM G CC). Если вызывается служба SV C, она правильно вводит SVC_Handler(), но когда я пытаюсь найти номер SV C, используемый для вызова обработчика SV C (svc_number), я получаю значение 248 вместо 1.

Я использую CubeMX IDE и плату Nucleo-F401RE.

Код:

void SVC_Handler(void)
{
     asm volatile (
            "TST lr, #4\t\n"
            "ITE EQ\t\n"
            "MRSEQ r0, msp\t\n"
            "MRSNE r0, psp\t\n"
            "B %[SVC_Handler_Main]\t\n"
            :
            : [SVC_Handler_Main] "i" (SVC_Handler_Main)
            : "r0"
    );

}

void SVC_Handler_Main(unsigned int* svc_args) {
     uint8_t svc_number;

     svc_number = ((char* )svc_args[6])[-2];
     switch(svc_number) { // <- that's where I get 248 instead of 1
     case SVC_ADD:
         SVC_Add_Handler(svc_args[0], svc_args[1]);
         break;
     default:
         break;
     }
}

int __attribute__ ((noinline)) SVC_Service_Add(int x, int y) {
    svc(SVC_ADD);
}

#define SVC_ADD 1

#define svc(code) asm volatile ("SVC %[immediate]"::[immediate] "I" (code))

Я использовал выражение выражения с точкой останова после svc_number, и его значение равно 248 вместо 1 что должно быть.

Сервисные вызовы (SV C) используются главным образом в проекте ОСРВ для программного обеспечения для входа в привилегированный режим. ARM G CC имеет хорошую поддержку для вызовов SV, тогда как в GNU G CC вы должны делать все это самостоятельно. Теория выглядит следующим образом: Когда вызывается SV (в моем случае SVC_Service_Add ()), он вызывает SVC_Handler (). SVC_Handler () проверяет, какой стек используется (основной msp или процесс psp), чтобы найти эту информацию, прочитав бит 2 регистра регистра (LR). В зависимости от этого, MSP или PSP сохраняется в r0. После этого компилятор помещает r0, r1, r2, r3, r12, r14, адрес возврата и xPSR в svc_args, поэтому эти параметры можно использовать в SVC_Handler_Main. svc_args [0] = r0, svc_args [1] = r1, ... svc_args [6] = SP (тот, который нам интересен, тот, где хранится число SV C). Так как стек Cortex M4 является полностью нисходящим, нам нужно сделать [-2], чтобы получить интересующий нас байт svc_args [6]. Поскольку вызов SVC_Handler был выполнен макросом SVC_ADD (0x01), ((char * ) svc_args [6]) [- 2] должен быть равен SVC_ADD, поэтому из SVC_Handler_Main () можно вызывать правильную функцию. Я не получаю 1, я почему-то получаю 248.

Вопрос : почему svc_number равно 248 , тогда как я ожидал 1

1 Ответ

3 голосов
/ 04 февраля 2020
#define svc(code) asm volatile ("SVC %[immediate]"::[immediate] "I" (code))

Создает ассемблер вида svc #1. Обратите внимание, что «1» кодируется в коде операции инструкции. Чтобы найти «1», вам нужно посмотреть на lr и загрузить код операции по этому адресу, а затем проанализировать (маскируя) значение.

Например,

ldr r1,[lr]            ; load svc opcode to r1 (might need an offset)
and r1, r1, #SVC_MASK  ; may need shifts as well.

Это не эффективно, поскольку вы обрабатываете код канал как data . Обычный способ сделать это - определить служебный регистр, например, r7, а затем установить r7 в '# 1' перед инструкцией svc #0. Таким образом, макрос выглядит примерно так:

#define svc(code) asm volatile ("mov r7, %[immediate]\n" \
                                " SVC #0"::[immediate] "I" (code) \
                                 : "r7" /*clobbers r7*)

Вы можете использовать только r0, но если ваша иерархия вызовов становится более сложной, многие функции могут поместить аргументы в r0, r1, r2, r3, а затем вы нужно будет перетасовать их. Вот почему обычно используется r7.


Почему svc_number равно 248, тогда как я ожидал 1

Похоже, вы думали, что это был помещен в стек, и это НЕ дело. Значение 248 - это нечто случайное в стеке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...