Проблема здесь в том, как работает функция 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(...) -> ...
.
person
huon
schedule
03.11.2014