Нетрадиционные звонки с Inline ASM

Я работаю с запатентованным MCU, который имеет встроенную металлическую библиотеку (маска ПЗУ). Я использую компилятор clang, который использует GCC-подобный встроенный ASM. Проблема, с которой я сталкиваюсь, — это вызов библиотеки, поскольку у библиотеки нет согласованного соглашения о вызовах. В то время как я нашел решение, я обнаружил, что в некоторых случаях компилятор выполняет оптимизацию, которая регистрируется клоббером непосредственно перед вызовом, я думаю, что в моих действиях что-то не так. Вот код, который я использую:

int EchoByte()
{
register int asmHex __asm__ ("R1") = Hex;
asm volatile("//Assert Input to R1 for MASKROM_EchoByte":
:"r"(asmHex)
:"%R1");
((volatile void (*)(void))(MASKROM_EchoByte))(); //MASKROM_EchoByte is a 16-bit integer with the memory location of the function
}

Теперь возникает очевидная проблема: в то время как переменная «asmHex» утверждается для регистрации R1, реальный вызов не использует ее, и поэтому компилятор «не знает», что R1 зарезервирован во время вызова. Я использовал следующий код для устранения этого случая:

int EchoByte()
{
register int asmHex __asm__ ("R1") = Hex;
asm volatile("//Assert Input to R1 for MASKROM_EchoByte":
:"r"(asmHex)
:"%R1");
((volatile void (*)(void))(MASKROM_EchoByte))();
asm volatile("//Assert Input to R1 for MASKROM_EchoByte":
:"r"(asmHex)
:"%R1");
}

Это кажется мне очень уродливым, и как будто должен быть лучший способ. Также я обеспокоен тем, что компилятор может делать какую-то глупость между ними, поскольку сам вызов не имеет никаких признаков того, что ему нужна переменная asmHex. К сожалению, ((volatile void (*) (int)) (MASKROM_EchoByte)) (asmHex) не работает, так как будет следовать соглашению C, которое помещает аргументы в R2 + (R1 зарезервирован для царапин)

Обратите внимание, что изменить библиотеку Mask ROM, к сожалению, невозможно, и слишком много часто используемых подпрограмм, чтобы воссоздать их все в C / C ++.

Ура и спасибо.

РЕДАКТИРОВАТЬ: я должен отметить, что, хотя я мог бы вызвать функцию в блоке ASM, компилятор имеет оптимизацию для функций, которые не требуют вызова, и, вызывая сборку, похоже, что вызова нет. Я мог бы пойти по этому пути, если есть какой-то способ указать, что встроенный ASM содержит вызов функции, но в противном случае адрес возврата, вероятно, будет засорен. Я не смог найти способ сделать это в любом случае.

5

Решение

По комментариям выше:

Самый обычный ответ заключается в том, что вы должны реализовать функцию-заглушку в сборке (в .s файл), который просто выполняет дурацкий вызов для вас. В ARM это будет выглядеть примерно так

// void EchoByte(int hex);

_EchoByte:
push {lr}
mov  r1, r0       // move our first parameter into r1
bl   _MASKROM_EchoByte
pop  pc

Внедрите одну из этих заглушек в каждую подпрограмму mask-ROM, и все готово.

Что это такое? У вас есть 500 подпрограмм с маской и не хотите вырезать и вставить столько кода? Затем добавьте уровень косвенности:

// typedef void MASKROM_Routine(int r1, ...);
// void GeneralPurposeStub(MASKROM_Routine *f, int arg, ...);

_GeneralPurposeStub:
bx   r0

Вызовите эту заглушку, используя синтаксис GeneralPurposeStub(&MASKROM_EchoByte, hex), Это будет работать для любой точки входа в маску-ROM, которая ожидает параметр в r1, любой действительно для дурацких точек входа все равно потребуются собственные заглушки с ручным кодом.

Но если ты действительно, действительно, действительно необходимо сделать это с помощью встроенной сборки в функции C, а затем (как указал @JasonD) все, что вам нужно сделать, это добавить регистр ссылок lr в глухой список.

void EchoByte(int hex)
{
register int r1 asm("r1") = hex;
asm volatile(
"bl  _MASKROM_EchoByte":
: "r"(r1)
: "r1", "lr"   // Compare the codegen with and without this "lr"!
);
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]