2014-11-01 27 views
10

मैं वर्तमान में DynamicLibrary के साथ खेल रहा हूं।मैन्युअल रूप से एक जंग गतिशील लाइब्रेरी को कॉल करें

मेरी गतिशील पुस्तकालय का कोड (rustc --crate-type dylib dylib.rs साथ संकलित):

// dylib.rs 
#[no_mangle] 
pub fn minicall() -> u8 { 
    3u8 
} 

और कोड इसे कहते हैं:

~> ./caller 
Unsafe bloc ! 
call func ! 
Illegal instruction 

और:

// caller.rs 
use std::dynamic_lib::DynamicLibrary; 

fn main() { 
    let mut v = Vec::new(); 

    DynamicLibrary::prepend_search_path(&::std::os::getcwd()); 

    match DynamicLibrary::open(Some("./libdylib.so")) { 
     Err(e) => panic!("ERROR: {}", e), 
     Ok(lib) => { 
      println!("Unsafe bloc !"); 
      let func = unsafe { 
       match lib.symbol::< fn() -> u8 >("minicall") { 
         Err(e) => { panic!("ERROR: {}", e) }, 
         Ok(f) => { *f }, 
       } 
      }; 
      println!("call func !"); 
      let new_value = func(); 

      println!("extend vec !"); 
      v.push(new_value); 
     } 
    } 

    println!("v is: {}", v); 
} 

मैं इस उत्पादन यहाँ मैं काफी खो गया हूँ। मैं क्या गलत कर रहा हूं ?

उत्तर

8

समस्या यहाँ कैसे symbol समारोह काम करता है।

unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> 

एक भरी हुई पुस्तकालय मूल रूप से एक नाम (प्रतीक नाम) के साथ लेबल निश्चित पते के साथ स्मृति में एक बड़ा सरणी है: यह हस्ताक्षर हैं। प्रतीक के लिए पूछताछ पते को देखती है और इसे सीधे एक सूचक देता है। लाइब्रेरी में एक फ़ंक्शन निर्देशों का एक लंबा अनुक्रम है, इसलिए फ़ंक्शन के नाम के लिए पूछताछ सीधे (फ़ंक्शन) पॉइंटर को प्रारंभ में लौटाती है। इसे तब सामान्य फ़ंक्शन पॉइंटर के रूप में बुलाया जा सकता है। जंग DynamicLibrary एपीआई इस सूचक को वापस कर रहा है, यानी, *mut T डायनेमिक लाइब्रेरी में स्मृति के खंड पर सीधे अंक (जो माना जाता है/आशा है कि T टाइप करें)।

प्रकार fn(...) -> ... एक फ़ंक्शन पॉइंटर स्वयं है, यानी यह 8 बाइट्स (या 4 बाइट्स) है जो इसे प्रस्तुत करने वाले फ़ंक्शन की शुरुआत के पते को संग्रहीत करता है। इसलिए, lib.symbol::< fn() -> u8 >("minicall") पर कॉल करना "मुझे minicall नामक चीज़ का पता ढूंढें (जो एक पॉइंटर 0 फ़ंक्शन पर है)", यह नहीं कह रहा है "मुझे 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) के माध्यम से उचित फ़ंक्शन पॉइंटर प्रकार पर वापसी मान डालना होगा।

(मैं के बाद भी अन्य जवाब स्वीकार कर लिया गया क्योंकि मुझे नहीं लगता कि यह कारण बताया गया है बहुत अच्छी तरह से इस का जवाब दे रहा हूँ, बस समाधान दे दी है।)


अंतिम बात, यह नहीं है इस मामले में एक समस्या है, लेकिन यह लोगों को बहुत यात्रा करता है: जंग एबीआई (fn(...) -> ... प्रकार के कार्यों के लिए इस्तेमाल किया जाने वाला कॉलिंग सम्मेलन) सी एबीआई जैसा नहीं है, इसलिए सी गतिशील पुस्तकालयों से लोड किए गए कार्यों को extern "C" fn(...) -> ..., दिया जाना चाहिएfn(...) -> ... नहीं।

5

मुझे लगता है कि समस्या इस तथ्य से उत्पन्न होती है कि आप असंगत प्रकारों के बीच कास्टिंग कर रहे हैं। विशेष रूप से, dereference *f गलत जगह पर इंगित करने जा रहा है। मैंने यह देखने के लिए जंग कोड में देखा कि लाइब्रेरी का उपयोग कैसे किया जाना चाहिए और src/librustc/plugin/load.rs में एक उदाहरण मिला। मैं अपने उदाहरण है कि कोड अनुकूलित:

let func = unsafe { 
    // Let this return a `*mut u8`, a very generic pointer 
    match lib.symbol("minicall") { 
     Err(e) => { fail!("ERROR: {}", e) }, 
     // And then cast that pointer a function 
     Ok(f) => { std::mem::transmute::<*mut u8, fn() -> u8>(f) }, 
    } 
}; 
println!("call func !"); 
let new_value = func(); 

उत्पादन:

$ ./caller 
Unsafe bloc ! 
call func ! 
extend vec ! 
v is: [3] 
+0

ओह, मैं देखता हूं, धन्यवाद। दस्तावेज इस बारे में बिल्कुल स्पष्ट नहीं है। – Levans

+0

यह बहुत धर्मार्थ है; इस समय वास्तव में कोई दस्तावेज़ नहीं हैं ... मैंने सोर्स डाइविंग^_^के दौरान '#! [अनुमति दें (missing_docs)] 'भी देखा। – Shepmaster

संबंधित मुद्दे