Ответ 1
Проблема в том, как работает функция symbol
. Он имеет подпись:
unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String>
Загруженная библиотека в основном представляет собой большой массив в памяти с определенными адресами, помеченными именем (именами символов). Запрос символа ищет адрес и возвращает указатель прямо к нему. Функция в библиотеке - это длинная последовательность инструкций, поэтому запрос имени функции возвращает указатель (функции) непосредственно к началу. Это можно затем назвать нормальным указателем функции. API-интерфейс Rust DynamicLibrary
возвращает этот указатель, то есть *mut T
указывает непосредственно на кусок памяти в динамической библиотеке (предположительно/надеюсь, что тип T
).
Тип fn(...) -> ...
- это сам указатель на функцию, то есть 8 байтов (или 4 байта), сохраняющих адрес начала функции, которую он представляет. Следовательно, вызов lib.symbol::< fn() -> u8 >("minicall")
говорит "найдите мне адрес вещи под названием minicall
(который является указателем на функцию)", он не говорит "найдите мне адрес вещи под названием minicall
(который функция)". Возвращаемое значение *mut (fn() -> u8)
затем является двунаправленным и разыменовывает его для вызова, это интерпретация первых 8 (или 4) байтов кода функции как указателя (например, случайных машинных команд/прелюдии функции), он не выполняется их.
(Боковое примечание: возможно, это сработает, если в вашей библиотеке есть #[no_mangle] pub static minicall: fn() -> u8 = the_real_minicall;
, но вы, вероятно, этого не хотите.)
Вызов lib.symbol::<T>("minicall")
возвращает нужный нам указатель функции (т.е. возвращает указатель на начало кода minicall
), поэтому просто возникает вопрос об этом выражении компилятору, К сожалению, в настоящее время нет типа T
, который делает *mut T
указателем на функцию, поэтому сначала нужно установить T = u8
(т.е. lib.symbol::<u8>("minicall")
), а затем применить возвращаемое значение к соответствующему типу указателя функции через transmute::<_, fn() -> u8>(pointer)
.
(Я отвечаю на это даже после того, как был принят другой ответ, потому что я не думаю, что он объяснил причину очень хорошо, просто дал решение.)
Последнее, в этом случае это не проблема, но он много путешествует: Rust ABI (вызывающее соглашение, используемое для функций типа fn(...) -> ...
), не совпадает с C ABI, поэтому функции загруженные из динамических библиотек C, должны иметь тип extern "C" fn(...) -> ...
, а не fn(...) -> ...
.