Vấn đề ở đây là cách symbol
chức năng hoạt động. Chữ ký có chữ ký:
unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String>
Thư viện được tải về cơ bản là một mảng lớn trong một số địa chỉ nhất định có gắn nhãn (tên biểu tượng). Truy vấn biểu tượng tìm kiếm địa chỉ và trả về một con trỏ thẳng đến nó. Một hàm trong thư viện là một chuỗi các lệnh dài, do đó việc truy vấn tên của hàm trả về một con trỏ (hàm) trực tiếp đến đầu. Điều này sau đó có thể được gọi là một con trỏ hàm bình thường. API Rust DynamicLibrary
trả về con trỏ này, tức là, *mut T
trỏ trực tiếp vào đoạn bộ nhớ trong thư viện động (được cho là/hy vọng là loại T
).
Loại fn(...) -> ...
là một con trỏ hàm chính nó, nghĩa là, nó là 8 byte (hoặc 4 byte) lưu trữ địa chỉ bắt đầu của hàm mà nó đại diện. Do đó, gọi số lib.symbol::< fn() -> u8 >("minicall")
là nói "tìm cho tôi địa chỉ có tên là minicall
(là con trỏ đến hàm)", không phải là "tìm cho tôi địa chỉ của thứ gọi là minicall
(là hàm)" . Giá trị trả về của *mut (fn() -> u8)
sau đó là gián tiếp gấp đôi, và dereferencing nó gọi nó là giải thích 8 (hoặc 4) byte đầu tiên của mã chức năng như một con trỏ (tức là chỉ dẫn máy ngẫu nhiên/chức năng prelude), nó không thực hiện chúng.
(Side-lưu ý:. Nó có lẽ sẽ làm việc nếu bạn có #[no_mangle] pub static minicall: fn() -> u8 = the_real_minicall;
trong thư viện của bạn, nhưng có lẽ bạn không muốn điều này)
Các cuộc gọi đến lib.symbol::<T>("minicall")
đang trở lại con trỏ chức năng chính xác chúng ta muốn (có nghĩa là , nó sẽ trả về một con trỏ để bắt đầu mã số minicall
), do đó, nó chỉ trở thành một câu hỏi thể hiện điều này với trình biên dịch. Rất tiếc, hiện không có loại T
nào làm cho *mut T
con trỏ hàm, vì vậy trước tiên, bạn phải đặt T = u8
(ví dụ: lib.symbol::<u8>("minicall")
) và sau đó truyền giá trị trả lại cho loại con trỏ chức năng thích hợp qua transmute::<_, fn() -> u8>(pointer)
.
(tôi trả lời này ngay cả sau khi câu trả lời khác đã được chấp nhận bởi vì tôi không nghĩ rằng nó giải thích nguyên nhân rất tốt, chỉ cần đưa ra các giải pháp.)
Điều cuối cùng, đây không phải là một vấn đề trong trường hợp này, nhưng nó đi rất nhiều người: Rust ABI (quy ước gọi được sử dụng cho các chức năng kiểu fn(...) -> ...
) không giống với C ABI, do đó các hàm được tải từ thư viện động C phải được nhập extern "C" fn(...) -> ...
, không phảifn(...) -> ...
.
Ồ, tôi hiểu rồi, cảm ơn. Các tài liệu không rõ ràng về điều này cả. – Levans
Điều đó rất từ thiện; không có bất kỳ tài liệu nào vào lúc này ... Tôi thậm chí còn thấy '#! [allow (missing_docs)]' trong khi source-diving^_ ^. – Shepmaster