Прямой вызов функции C с использованием встроенной сборки GCC - PullRequest
11 голосов
/ 12 августа 2010

Если вы хотите вызвать функцию C / C ++ из встроенной сборки, вы можете сделать что-то вроде этого:

void callee() {}
void caller()
{
    asm("call *%0" : : "r"(callee));
}

Затем GCC выдаст код, который выглядит следующим образом:

movl $callee, %eax
call *%eax

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

Поскольку адрес callee в конечном итоге является константой, можно представить, что можно будет использовать iограничение.Цитирование из GCC онлайн документы :

`i '

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

Если я попытаюсь использовать это следующим образом:

asm("call %0" : : "i"(callee));

Я получаю следующую ошибку изассемблер:

Ошибка: суффикс или операнды недопустимы для `call '

Это потому, что GCC выдает код

call $callee

вместо

call callee

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

Ответы [ 4 ]

11 голосов
/ 13 августа 2010

Я получил ответ из списка рассылки GCC:

asm("call %P0" : : "i"(callee));

Теперь мне просто нужно выяснить, что на самом деле означает %P0, потому что это кажется недокументированной функцией ...

Редактировать : После просмотра исходного кода GCC не совсем ясно, что означает код P перед ограничением. Но, помимо всего прочего, он не позволяет GCC поставить $ перед постоянными значениями. Что именно то, что мне нужно в этом случае.

1 голос
/ 13 января 2016

Может быть, я что-то здесь упускаю, но

extern "C" void callee(void) 
{

}

void caller(void)
{
  asm("call callee\n");
}

должно работать нормально. Вам нужен extern "C", чтобы имя не было оформлено на основе правил искажения имен в C ++.

0 голосов
/ 11 июня 2015

Если вы генерируете 32-битный код (например, опция -m32 gcc), следующий asm inline отправляет прямой вызов:

asm ("call %0" :: "m" (callee));
0 голосов
/ 12 августа 2010

Хитрость заключается в конкатенации строковых литералов.Прежде чем GCC попытается получить какой-либо реальный смысл из вашего кода, он объединит смежные строковые литералы, поэтому, даже если строки сборки не совпадают с другими строками, которые вы используете в своей программе, их следует объединить, если вы это сделаете:

#define ASM_CALL(X) asm("\t call  " X "\n")


int main(void) {
    ASM_CALL( "my_function" );
    return 0;
}

Поскольку вы используете GCC, вы также можете сделать

#define ASM_CALL(X) asm("\t call  " #X "\n")

int main(void) {
   ASM_CALL(my_function);
   return 0;
}

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

редактировать это будет работать только для имен функций C - не C ++, поскольку они искажены.

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