2016-02-25 11 views
5

मैं एक जेनेरिक फ़ंक्शन लिखना चाहता हूं जो सिस्टम कॉल करता है। कुछलिनक्स पर सिस्टम कॉल तर्कों का प्रकार क्या है?

long my_syscall2(long number, long arg1, long arg2); 

मैं इसे यथासंभव पोर्टेबल बनना चाहता हूं। कार्यान्वयन सभी आर्किटेक्चर के लिए स्पष्ट रूप से अलग है। क्या समारोह के हस्ताक्षर को भी अलग होना चाहिए? क्या मैं long का उपयोग कर सकता हूं या मुझे कुछ और उपयोग करना चाहिए?

  • गिरी कुछ dark magic का उपयोग करता है: (__SYSCALL_DEFINEx __SC_LONG कॉल प्रकार प्राप्त करने के लिए, __SC_LONG जादू होता है)

    यहाँ संभव समाधान है कि मैंने पाया है। मैंने कहीं कहीं सुना है कि उपयोगकर्ता स्थान में प्रकार हमेशा कर्नेल स्पेस के समान नहीं होते हैं, इसलिए मुझे नहीं पता कि मैं इसका उपयोग कर सकता हूं या नहीं।

  • musl-libc uses long for all architectures that it supports except x32: ([arch] /syscall_arch.h में परिभाषित)।
  • मैं उन सभी प्रोसेसर आर्किटेक्चर और कंपाइलर्स के लिए प्रलेखन ढूंढ सकता हूं जिन्हें मैं समर्थन देना चाहता हूं, रजिस्टर आकार और पूर्णांक प्रकार के आकार देखें और रजिस्टरों के समान आकार वाले किसी भी पूर्णांक प्रकार को चुनें।

तो मुझे लगता है कि सवाल यह है कि "वहाँ कुछ नियम कहता है कि 'सिस्टम कॉल तर्क का प्रकार हमेशा से रहे हैं x32 जैसे कुछ अपवादों के साथ long' या मैं हर वास्तुकला और संकलक के लिए दस्तावेज़ को देखने की जरूरत है है?"

संपादित करें: मुझे पता है कि कुछ सिस्टम कॉल पॉइंटर्स और अन्य प्रकार पैरामीटर के रूप में लेते हैं। मैं सामान्य कार्यों को लिखना चाहता हूं जो जेनेरिक पैरामीटर प्रकारों के साथ किसी भी सिस्टम कॉल को कॉल कर सकते हैं। ये जेनेरिक पैरामीटर प्रकार वास्तविक पैरामीटर प्रकारों को पकड़ने के लिए काफी बड़े होना चाहिए। मुझे पता है कि यह संभव है क्योंकि syscall() फ़ंक्शन मौजूद है।

संपादित 2: यहां इस समस्या का एक और आंशिक समाधान है। इन कार्यों के

क्रियान्वयन वर्तमान में इस तरह दिखेगा:

static __inline long my_syscall2(long number, long arg1, long arg2) 
{ 
    unsigned long ret; 
    __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(number), "D"(arg1), "S"(arg2) 
         : "rcx", "r11", "memory"); 
    return ret; 
} 

दिलचस्प हिस्सा "=a"(ret) है, इसका मतलब है कि syscall वापसी मान कि रजिस्टर a में संग्रहित है चर ret में बचाया जाना चाहिए। स्थानीय चर बनाता है जो एक समारोह लिखने के बजाय, syscall बनाता है, इसके वापसी मूल्य को चर में सहेजता है और चर लौटाता है मैं एक मैक्रो लिख सकता हूं जो syscall बनाता है और परिणाम को कॉलर द्वारा प्रदान किए गए चर में संग्रहीत करता है। यह इस तरह दिखेगा:

#define my_syscall2(RET, NUMBER, ARG1, ARG2) \ 
    __asm__ __volatile__ ("syscall" : "=a"(RET) : "a"(NUMBER), "D"(ARG1), "S"(ARG2) \ 
         : "rcx", "r11", "memory"); 

और यह इस तरह इस्तेमाल किया जाएगा:

long result; 
void * arg1; 
int arg2; 
my_syscall2(result, <syscall number>, arg1, arg2); 

इस तरह से मैं पता करने के लिए रजिस्टर आकार और पूर्णांक प्रकार है कि काफी बड़ा एक मूल्य धारण करने के लिए है की जरूरत नहीं है रजिस्टर का

+0

आप सिस्टम कॉल को कैसे संभालेंगे जो कोई पैरामीटर नहीं लेता है? – edmz

+0

@black मैं 6 कार्यों को परिभाषित करता हूं my_syscall {0-5} – alkedr

+1

यह वास्तव में यहां तक ​​कि अधिक जटिल है जब तक कि आप एक आर्किटेक्चर निर्दिष्ट नहीं करते हैं), लेकिन syscall() मैक्रो और syscall0 के मेरे सार्वजनिक डोमेन कार्यान्वयन का उपयोग करने के लिए स्वतंत्र महसूस करें () -syscall6() https://github.com/technosaurus/BQC पर फ़ंक्शंस ... जिनमें से सभी पैरामीटर – technosaurus

उत्तर

1

कोई सामान्य समाधान नहीं है। आप अपने कोड अल्ट्रा multiarch बनाना चाहते हैं आप बस ऐसे ही कुछ कर सकते हैं:

#if ARCH_WITH_32BIT_REGS 
typedef uint32_t reg_size_int_t; 
#elif ARCH_WITH_64BIT_REGS 
typedef uint64_t reg_size_int_t; 
#elif ARCH_WITH_16BIT_REGS 
typedef uint16_t reg_size_int_t; 
.... 
#endif 

reg_size_int_t syscall_1(reg_size_t nr, reg_size_t arg0); 
... 

लेकिन सबसे आम रूप से प्रयुक्त आर्किटेक्चर के लिए रजिस्टर के आकार में लंबे समय के बराबर है।

3

मेरा सुझाव है कि आप अपने आप को लिखने की बजाय मौजूदा syscall सिस्टम कॉल का उपयोग करें। ऐसा लगता है कि आप वही करना चाहते हैं जो आप चाहते हैं। आपके द्वारा उठाए गए वैध प्रश्नों की चर्चा के लिए मैन्युअल पृष्ठ के "आर्किटेक्चर-विशिष्ट आवश्यकताओं" अनुभाग को देखें।

+2

मजेदार पर्याप्त, 'syscall()' एक नहीं है syscall, लेकिन प्रासंगिक syscall निर्देश के आसपास एक पुस्तकालय रैपर। – EOF

+1

हां, इसे gnu एक्सटेंशन के साथ मानक सी लाइब्रेरी की भी आवश्यकता है और यह इसे वापस करने के बजाय वैश्विक त्रुटि चर में त्रुटि कोड संग्रहीत करता है। मैं मानता हूं, ये प्रमुख मुद्दे नहीं हैं, लेकिन अगर मैं इसका उपयोग न करने का एक आसान तरीका है तो मैं घूम रहा था। – alkedr

+1

आप अपनी विशिष्ट आवश्यकताओं से मेल खाने के लिए 'syscall' स्रोत कोड भी संशोधित कर सकते हैं। –

4

सिस्टम कॉल तर्क रजिस्टरों में पास किए जाते हैं। इस प्रकार एक सीपीयू रजिस्टर के आकार तक सीमित है।32 बिट आर्किटेक्चर पर 32 बिट, 64 बिट आर्किटेक्चर पर 64 बिट है। इस तरह कर्नेल को फ़्लोटिंग पॉइंट नंबर पास नहीं किया जा सकता है। परंपरागत रूप से कर्नेल फ़्लोटिंग पॉइंट निर्देशों का उपयोग नहीं करता है (और ऐसा नहीं हो सकता है क्योंकि एफपीयू राज्य आमतौर पर कर्नेल में प्रवेश पर सहेजा नहीं जाता है) इसलिए अपने सिस्टम कॉल में फ्लोटिंग पॉइंट नंबरों से बचने का प्रयास करें।

सिस्टम कॉल जो छोटे प्रकार के तर्कों का उपयोग करते हैं शून्य या साइन इन का विस्तार करते हैं। सिस्टम कॉल जो बड़े तर्क प्रकारों का उपयोग करते हैं, वे तर्क को एकाधिक रजिस्टरों में विभाजित कर सकते हैं।

सिस्टम कॉल (जैसे mmap()) जिसमें पैरामीटर को एक संरचना के रूप में पैरामीटर के रूप में पारित करके कई पैरामीटर लागू किए जा सकते हैं, लेकिन इसमें एक मापनीय प्रदर्शन ओवरहेड है, इसलिए पांच से अधिक पैरामीटर के साथ सिस्टम कॉल डिज़ाइन से बचें।

दिन के अंत में, उस मूल्य के लिए उपयुक्त प्रकार का उपयोग करें जिसे आप भेजना चाहते हैं। डेटा को सही जगहों पर रखने के साथ libc सौदे को दें।

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