Вызов функций Rust из встроенной сборки и соглашения о вызовах

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

Насколько я понимаю, соглашения о вызовах в Rust не определены. Итак, при вызове ассемблера я должен использовать соглашение о вызовах C, чтобы что-то было известно.

Я работаю между тремя функциями:

unsafe extern "C" fn f(a) -> b — это голая функция, вызываемая только из Rust. Он полностью ассемблерный и предполагает, что параметры и возвращаемые значения выполняются, как в C (в стеке и помещаются в %eax). Поскольку он помечен как C и вызывается из Rust, компилятор гарантирует, что где бы он ни вызывался, для него будет использоваться соглашение о вызовах C.

unsafe extern "C" fn g() также является голой функцией. Он никогда не вызывается из Rust. Лишь иногда f возвращается к этой функции (то есть ret из f выдает адрес g). Хотя это не настоящая функция C (я знаю, что она вызывается из f и сразу использует регистры, а не f оставленные значения), она всегда будет вызывать функцию ржавчины. По сути, все это помещает параметры в стек, а затем от call до h (с помощью sym h).

unsafe fn h — это последняя функция здесь. Он вызывается только из g через это sym во встроенной сборке. Итак, h следует ожидать вызова с использованием соглашений C, но он может вернуться с соглашениями Rust (фактически h никогда не возвращается).

Тогда мой вопрос:

Будет ли использование call и sym h из моей функции C, g, предупреждать компилятор Rust о необходимости последовательного использования соглашений о вызовах C в h?

Ранее я пометил h как extern "C", несмотря на то, что это чистый код ржавчины. На мой взгляд, это гарантирует, что компилятор уважает аргументы h в стиле C. Но код, похоже, работает в обе стороны. Я не хочу, чтобы это изменилось, если в будущем Rust решит оптимизировать вызов h по-другому (и неправильно).

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

PitaJ 18.03.2024 23:07

Что касается h, я получаю предупреждения при использовании extern "C". Одна вещь, к которой я обращаюсь h, — это указатель на функцию Rust, а затем я вызываю его внутри h. Это генерирует предупреждение о FFI, если h отмечен C.

Derek C. 19.03.2024 02:09
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
191
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование call во встроенном ассемблере не гарантирует, что функция будет использовать соглашение о вызовах C (фактически, компилятор вообще не имеет представления о встроенном ассемблере). Вам нужно использовать extern "C". Использование соглашения о вызовах Rust может показаться эффективным (иногда соглашения о вызовах эквивалентны), но это не гарантировано.

Если вы передаете указатели на функции h(), они также должны быть extern "C", даже если они не вызываются из сборки. Насколько я могу судить, нет никакой гарантии относительно ABI функций соглашения о вызовах Rust, поэтому вы не можете даже передать их, поэтому компилятор вас предупреждает.

Если h() не возвращает, вы можете пометить его как возвращаемый тип !, что заставит компилятор убедиться, что он действительно не возвращает (а если он вызван из Rust, это также позволит ему использовать эту информацию).

Другие вопросы по теме