Вызов функции C из функции ARM, определенной с помощью __asm

У меня проблемы с пониманием моего компилятора. Мы используем утилиту Scons для компиляции кода ARM для процессора M0+ (в Windows, если это имеет значение. Это компиляция ARMCC). Я пытаюсь захватить адрес указателя стека во время прерывания, используя ответ на этот вопрос.

Для моего компилятора я получаю следующее: Error: #20: identifier "asm" is undefined Единственный способ, которым я смог заставить его (в основном) компилироваться, заключался в следующем:

  void IRQHandler_real( uint32_t *sp )
  {
     // Do some work
  }

  __asm void IRQHandler( void )
  {
     MOV R0,SP
     ADDS R0, #1
     LDR R1, =IRQHandler_real //<<-- This line fails
     BX R1
  }

Код ошибки

  Error: A1516E: Bad symbol 'IRQHandler_real', not defined or external

Замена двух последних сборочных линий на BL IRQHandler_real приводит к той же ошибке.

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

Я прочитал здесь, что мне нужен вызов "extern C", но Подробностей о том, как это выглядит, я пока не нашел.

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

TL:DR, мне нужно вызвать функцию C из сборки ARM, но я не прошел компилятор.


person MPStoering    schedule 26.06.2018    source источник
comment
Попробуйте добавить подчеркивание в начало IRQHandler_real: _IRQHandler_real   -  person Thomas Jager    schedule 26.06.2018
comment
Я думаю, что код также предназначен для передачи SP вызываемой функции, а не ПК.   -  person supercat    schedule 26.06.2018
comment
Томас, я пробовал как одинарное, так и двойное подчеркивание, оба потерпели неудачу с одной и той же компиляцией.   -  person MPStoering    schedule 26.06.2018
comment
Supercat, я обновил вопрос. Спасибо за улов.   -  person MPStoering    schedule 26.06.2018
comment
Я не понимаю, почему вы добавляете 1 к R0, но я предлагаю проверить, может ли ассемблер обрабатывать синтаксис = при использовании в этом контексте, попробовав ldr r0,=123456789. Если вы можете использовать векторную таблицу в ОЗУ, другой возможностью, которая позволит избежать необходимости в коде, зависящем от компилятора, будет определение структуры struct { uint64_t code; void (*func)(uint32_t *sp);} intBoing, сохранение 0xBF00470849014668 в code, а адрес функции в func. Затем сохраните адрес intBoing плюс 1 в нужный вектор прерывания. Если я правильно понял, кстати, код такой:   -  person supercat    schedule 26.06.2018
comment
Я загружаю этот код в gcc и получаю ошибки, фундаментальные ошибки директивы asm, не говоря уже о том, как она работает с метками. Так что, может быть, вы используете C++, несмотря на тег C в вопросе, или, может быть, вы вообще не используете gcc?   -  person old_timer    schedule 26.06.2018
comment
если суть в том, что вам нужно вызвать C из сборки, почему бы просто не использовать настоящую сборку, а не встроенную, ваша загрузка адреса или bl должна работать, и bl должен иметь диапазон на cortex-m для достижения большинства, если нет вся ваша вспышка должна просто работать.   -  person old_timer    schedule 26.06.2018
comment
добавление одного к указателю стека не имеет смысла, но, возможно, это что-то специфичное для вашей обработки прерываний...   -  person old_timer    schedule 26.06.2018
comment
Весь наш код написан на C. Я поспрашивал в офисе, похоже, мы используем ARMCC 5.06, а не GCC ARM. Я пытался избежать создания нового файла для такого небольшого изменения, но я могу переместить его в новый файл, если нет встроенного решения. Я попытаюсь загрузить структуру в вектор прерывания и проверю это   -  person MPStoering    schedule 26.06.2018


Ответы (2)


Если ваш компилятор является компилятором C++, вам нужно будет использовать extern "C" следующим образом;

extern "C" {
  void IRQHandler_real( uint32_t *sp )
  {
     // Do some work
  }
}
person cleblanc    schedule 26.06.2018
comment
Я ожидаю, что это сработает для VS/C++. К сожалению, это не работает для ARMCC. - person MPStoering; 27.06.2018
comment
@MPStoering, вам может понадобиться окружить его #ifdef __cplusplus, но это задокументировано здесь на веб-сайте ARM. Я не думал, что кто-то больше использует armcc, но я также уверен, что это работает с gcc. - person cleblanc; 27.06.2018

Похоже, что компилятор оценивает код ARM отдельно от всего кода C и после него. Я исправил это, импортировав функцию с помощью команды IMPORT. Мой окончательный код выглядит так:

IMPORT IRQHandler_real
PUSH { R4, lr }
MOV R4, SP; The compiler does this from the C code, I'm assuming to avoid a hardware limitation.
MOV R0, R4
BL IRQHandler_real
POP { R4, PC }
ENDP

Это работает для ARMCC 5.6. Я думаю, что большая часть документации относится к GCC ARM (asm("statement");). Я все еще получаю Warning: #667-D: "asm" function is nonstandard, поэтому я с радостью приму «более правильный» ответ, если он существует.

person MPStoering    schedule 26.06.2018