Использование заголовков C в коде C ++ в GNU. Ошибка при включении встроенной сборки: невозможное ограничение в asm

У меня странный. Я работаю над встроенной системой, используя файлы заголовков поставщиков. Я компилирую файлы с помощью GCC 4.6.3. Я хочу использовать C ++ для своего кода, у меня ошибка, которую я не могу понять. Я запускаю программу-пример поставщика, и все, что я сделал, это изменил имя файла main.c на main.cpp. В результате, я полагаю, файлы заголовков интерпретируются компилятором C ++. Одна из них содержит следующие строки:

__attribute__((naked)) static return_type signature \
  { \
     __asm( \
         "svc %0\n" \
         "bx r14" : : "I" (number) : "r0" \
     ); \
}

Файлы компилируются правильно, если имя файла main.c, я предполагаю, что это связано с тем, что файл обрабатывается компилятором C. Если я использую C ++, я получаю следующее сообщение:

error: impossible constraint in 'asm'

Но опять же, у меня нет проблем с компилятором C. Мне нужно вызвать функции, которые используют это определение в файлах C ++. Я подумал о написании функций-оберток, которые остаются на стороне c и связываются с ними, но это было бы настоящей болью и менее эффективным. Какие-либо предложения?


person Kendrick Taylor    schedule 29.03.2013    source источник
comment
Если он находится в файле заголовка, вы не забыли extern "C" его?   -  person Jesus Ramos    schedule 30.03.2013
comment
Я попробовал это в качестве последней черты, но не ожидал, что это сработает. Насколько мне известно, extern C влияет только на компоновку, а не на компиляцию. Я думаю, что у меня ошибка компиляции, а не ошибка связывания. Спасибо за предложение. stackoverflow.com/questions/1041866/   -  person Kendrick Taylor    schedule 30.03.2013
comment
Понятно, я пропустил часть этого макроса: P   -  person Jesus Ramos    schedule 30.03.2013
comment
Это может повлиять и на ABI.   -  person PlasmaHH    schedule 30.03.2013
comment
Вы уверены, что компиляция C ++ находит кросс-компилятор, и вы не используете компилятор хоста случайно?   -  person fizzer    schedule 30.03.2013
comment
@fizzer Да, он нашел компилятор C ++. Я вижу, как команды выплевывают.   -  person Kendrick Taylor    schedule 31.03.2013
comment
Извините, если я работаю над очевидным. Вы уверены, что не передаете свой ассемблер ARM локальному компилятору x86, найдя g ++ в PATH?   -  person fizzer    schedule 31.03.2013
comment
@fizzer Да, я уверен на 100%. Путь включен. Ценю трудолюбие. Иногда это шнур питания, но на этот раз нет.   -  person Kendrick Taylor    schedule 31.03.2013
comment
У меня тоже есть эта проблема (в Nordic nRF51 SDK).   -  person Timmmm    schedule 21.05.2014
comment
связанный вопрос, что могло бы дать лучший код. Должна быть возможность просто встроить svc инструкции.   -  person artless noise    schedule 07.02.2016


Ответы (2)


svc, также известный как swi, является <сильным > ARM / Thumb инструкция программного прерывания. Он принимает только константы, но они отличаются от других констант регистров. Т.е., mov r0, #4096. Вам нужно использовать препроцессор и вставку токена, если вы хотите указать немедленное выполнение. number не может быть переменной или регистром.

#define syscall(number) __attribute__((naked)) static return_type signature \
  { \
     __asm( \
         "svc " #number "\n" \
         "bx r14" : : : "r0" \
     ); \
  }

буду работать. Примечание. # - это строковый препроцессор 'C'. Также обратите внимание, что смотреть на номер SVC, как на I-CACHE, неэффективно, а для проверки требуется D-CACHE. Обычно это всегда constant, а номер функции передается в регистре для более быстрых системных вызовов.

В руководстве по gcc говорится:

'I' - целое число, действительное как непосредственный операнд в инструкции обработки данных. То есть целое число в диапазоне от 0 до 255, повернутое на кратное 2

Это типично для операндов обработки данных - немедленно, раздел A5.1.3 ARM ARM. Операнды SVC являются либо фиксированными 8-битными в режиме большого пальца, либо фиксированными 24-битными в режиме ARM. Возможно, это возможно с каким-то другим ограничением, о котором я не знаю, но, по крайней мере, строковая обработка препроцессора будет работать, пока в макрос передается числовая константа.

Я полагаю, что это удачно, что это сработало с gcc, и не повезло, что g++ нет. Вы можете получить более подробное представление, используя -S и просматривая (и публикуя) вывод с помощью обоих инструментов.

Изменить: ваш код действительно работает с gcc-4.7.2, но number в моем случае const int локальный, возможно, проблема в использовании number. Возможно, у него есть тонкое семантическое изменение с «C» на «C ++».

person artless noise    schedule 31.03.2013
comment
Спасибо за помощь. Своим редактированием вы направили меня на правильный путь. Это был тип данных числа. Константы, которые использовал поставщик, были определены как перечисления, которые меняют тип между C и C ++. Я изменил их на #define, и это работает. Спасибо. - person Kendrick Taylor; 08.04.2013
comment
Вместо того, чтобы менять целую кучу перечислений на #defines, я обнаружил, что могу просто добавить локальную переменную с приведением к целочисленному типу. - person Christopher Mason; 22.05.2013
comment
Спасибо, Кендрик Тейлор, это сработало за меня! Полагаю, мы оба используем nRF51? :) @ChristopherMason, не могли бы вы вставить фрагмент кода? - person Timmmm; 21.05.2014
comment
Это приведение работает для меня: "bx r14" : : "I" ((uint16_t)number) : "r0" Я делаю это в локальном файле и использую порядок включения, чтобы предпочтительно включить его, таким образом избегая необходимости изменять Nordic SDK. - person Christopher Mason; 09.08.2014
comment
Хорошо, вполне возможно, что поведение изменится в зависимости от версии gcc и уровня оптимизации. То есть, сейчас он может работать с приведением, но у вас могут возникнуть проблемы, если вы обновите и / или измените уровни оптимизации. Суть в том, что компилятор должен уметь определять, что значение является константой. Например, компиляция с -O0 может не работать, поскольку компилятор может оставлять данные в регистре. При более высоких уровнях оптимизации более вероятно, что приведение будет работать. - person artless noise; 11.08.2014

Обратитесь к руководству GCC (встроенный ассемблер), чтобы узнать точное значение ограничений для вашей машины. Старые версии GCC были заведомо небрежны при проверке ограничений, возможно, вас это укусило. Странно, что gcc и g++ (одна и та же версия?) Обрабатывают код по-разному, это просто может быть ошибкой компилятора, но я бы посчитал это только после того, как были исчерпаны все другие объяснения.

person vonbrand    schedule 30.03.2013
comment
Спасибо, проверю. И gcc, и g ++ имеют одну и ту же версию. - person Kendrick Taylor; 31.03.2013