2013-04-22 30 views
6

पर कनवर्ट करें मैं एक सीपीपी प्रोजेक्ट पर काम कर रहा हूं। परियोजना को 64 बिट में माइग्रेट करने की आवश्यकता है। इसमें कुछ इनलाइन असेंबली कोड शामिल हैं जो x64 पर संकलित नहीं हो सकते हैं।इनलाइन असेंबली कोड को C++

void ExternalFunctionCall::callFunction(ArgType resultType, void* resultBuffer) 
{ 
#if defined(_NT_) || defined(__OS2__) 

    // I386 

    // just copy the args buffer to the stack (it's already layed out correctly) 
    int* begin = m_argsBegin; 
    int* ptr = m_argsEnd; 
    int arr[1000], i=0; 
    while (ptr > begin) { 
     int val = *(--ptr); 

     __asm push val 
    } 

    void* functionAddress = m_functionAddress; 

    // call the function & handle the return value. use __stdcall calling convention 
    switch (resultType) { 
    case voidType: 
     __asm { 
      call functionAddress 
     } 
     break; 
    case pointerType: 
    case int32Type: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      mov dword ptr [ebx],eax 
     } 
     break; 
    case floatType: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      fstp dword ptr [ebx] 
     } 
     break; 
    case doubleType: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      fstp qword ptr [ebx] 
     } 
     break; 
    } 

मैं इस "ASM धक्का वैल" विस्थापित करने के लिए ढेर, सारणी का प्रयोग किया है, लेकिन काम नहीं किया: इस समारोह जो विधानसभा कोड होता है। हालांकि, यह किसी संकलन त्रुटि को फेंक नहीं देता है लेकिन तर्क काम नहीं करता है।

तो, मैं पूछना चाहता हूं, मैं "__asm ​​पुश वैल" के बजाय सी ++ में क्या उपयोग कर सकता हूं। किसी भी तरह की सहायता को आभार समझेंगे।

+1

निश्चित रूप से यह कार्यक्रम में एकमात्र असेंबली निर्देश नहीं है? आप धक्का मूल्य का उपयोग कैसे करते हैं? इस पल के लिए आपकी मदद करने के लिए पर्याप्त जानकारी नहीं है। –

+1

आपको अधिक कोड दिखाना होगा ताकि हम जान सकें कि स्टैक पर धक्का दिया गया मूल्य के साथ क्या किया जा रहा है। –

+2

मानक सी ++ में इनलाइन असेंबली भाषा या सीपीयू के स्टैक को सीधे संशोधित करने के लिए कोई भी ऑपरेशन शामिल नहीं है .... यदि आप समझते हैं कि आपका फ़ंक्शन बाद में स्टैक के साथ क्या कर रहा है तो आपको उपयोगी सलाह का अधिक मौका है? यदि यह फ़ंक्शन कॉल या किसी चीज़ के लिए मूल्य तैयार कर रहा है, तो तर्कों की आपूर्ति करने का कोई और तरीका हो सकता है। यह आपके ओएस और/या कंपाइलर के लिए अत्यधिक विशिष्ट है, जिसे आपने नहीं बताया है। –

उत्तर

0

ऐसी कई चीजें हैं जिन्हें आपको हल करने की आवश्यकता है। (मैंने आपके कोड को दूसरे प्रश्न पर देखा)। जैसा कि मैंने समझा है कि यह कोड निर्दिष्ट पते पर स्थित सुंदर अमूर्त फ़ंक्शन को कॉल करने के लिए एक रैपर है, जो स्टैक में कुछ मात्रा में डेटा की अपेक्षा करता है और ArgType में आधारित विभिन्न चीज़ों को वापस कर सकता है।

यदि आप इसे सादे सी के माध्यम से लपेटना चाहते हैं तो आपको अपने स्विच पर उपयोग करने के लिए कई फ़ंक्शन प्रोटोटाइप (वापसी मूल्य के आधार पर) को परिभाषित करना होगा, लेकिन फिर आपको एक और समस्या हल करना होगा, जो अधिक कठिन है।

सी में ऐसी चीजों को पोर्ट करने में समस्या यह है कि आपको स्टैक में धक्का देने के लिए पर्याप्त मात्रा में तर्क (डेटा आकार) नहीं पता है, इसलिए आपको प्रोटोटाइप को परिभाषित करने में परेशानी होगी।

मान लें कि func (char c) निश्चित रूप से स्टैक 1 बाइट (लेकिन डेटा संरेखण के कारण हमेशा सही नहीं) में धक्का देगा .. आपके मामले में आपको समाधान के बारे में सोचना होगा जो बराबर आकार वाले पैरामीटर सेट करेगा डेटा के आकार के लिए आपको ढेर पर होना चाहिए। जो पहली नज़र में कुछ नहीं है जो आप सीधे कर सकते हैं।

यूपीडी। आप इसे func (char [] param) के साथ कर सकते हैं; लेकिन इसमें ऐसे मुद्दे भी हैं जो ऊपर दिए गए उत्तर में समझाए गए थे।

+0

आप जानते हैं, यह बुरा जवाब नहीं है, लेकिन अंतिम अनुच्छेद, विशेष रूप से "आपको समाधान के बारे में सोचना है", यह मेरे लिए खंडहर है। अगर वे कुछ सोच सकते हैं तो ओपी मदद मांगेगा नहीं। उन्होंने स्पष्ट रूप से इसे स्वयं हल करने के लिए बहुत मेहनत की कोशिश की। – StoryTeller

+0

आपको निराश करने के लिए खेद है .. हो सकता है कि आपको 'थोड़ा सोचना' वास्तव में थोड़ा मुश्किल हो, लेकिन मुझे बहाना है कि मैं मूल अंग्रेजी स्पीकर नहीं हूं .. मेरा मतलब है कि मुझे वास्तव में अंतिम चरण के लिए सही समाधान नहीं पता है, और जो मैंने लिखा था वह अधिक प्रशंसनीय सोच था, बल्कि तैयार किए गए उत्तर के बजाय। और एक और बात यह है कि मैंने ओपी प्रश्न (वास्तव में उनमें से दोनों) में जो पढ़ा है, उससे मुझे लगता है कि 'हल करने के लिए बहुत मेहनत की कोशिश की गई' लागू होने पर विचार किया जाएगा। – evilruff

13

समस्या सामान्य रूप से हल नहीं होती है; ऐसा इसलिए है क्योंकि टिप्पणी,

// call the function & handle the return value. use __stdcall calling convention 

32 बिट बुला सम्मेलनों पर निर्भरता को इंगित करता है है।

32 बिट 86 में, stdcall, इसका मतलब है कि सभी तर्क ढेर पर पारित कर रहे हैं, उलटे क्रम में (यानी पिछले आर्ग पहले धकेल दिया जाता है। यही कारण है कि है, अगर arg[0]addr पर तो arg[1], कोई फर्क नहीं पड़ता यह प्रकार है है addr + sizeof(arg[0]) पर)। यही कारण है कि क्यों अपने नमूना में निम्न कोड:

// just copy the args buffer to the stack (it's already layed out correctly) 
int* begin = m_argsBegin; 
int* ptr = m_argsEnd; 
int arr[1000], i=0; 
while (ptr > begin) { 
    int val = *(--ptr); 

    __asm push val 
} 

वास्तव में काम कर सकते हैं - क्योंकि यह बस फर्क नहीं पड़ता वास्तव में क्या है, किस प्रकार का तर्क हैं; यह सब प्रासंगिक है कि उनमें से प्रत्येक एक ज्ञात स्मृति स्थान में है, और लगातार-लगातार-स्मृति में जाना जाता है। यदि आप जानते हैं कि Naddr पर है, तो आप N+1 पर addr + sizeof(arg[N]) पर तर्क कर सकते हैं।

है यही कारण है कि टिप्पणी कहते हैं, "यह पहले से ही बाहर सही ढंग से रखी है" - दुर्भाग्य से, यह 64 बिट मोड में सच नहीं है। इसलिए कोड "पोर्ट" नहीं किया जा सकता है; बंदरगाह के बराबर नहीं है।

कॉलिंग सम्मेलन जो कम से कम आंशिक रूप से पंजीकृत हैं - जैसा कि x64 (64 बिट x86) पर Win64 अलग-अलग व्यवहार करता है।उन लोगों के लिए, यह इस बात पर निर्भर करता है कि किस प्रकार के तर्क बुलाए गए कार्यों को लेते हैं (आप विंडोज़ में, सामान्य प्रयोजन रजिस्टरों में चार पूर्णांक-प्रकार के तर्कों को पास कर सकते हैं और कुछ फ्लोट-टाइप तर्क XMM रजिस्टरों में) कर सकते हैं। इसलिए आपको और को "फ़ंक्शन N तर्क" से हस्ताक्षर किए गए फ़ंक्शन के हस्ताक्षर (प्रोटोटाइप) के बारे में जानने की आवश्यकता है ताकि उपरोक्त की तरह "anycall" प्रकार रैपर से सही ढंग से मार्शल तर्कों को सक्षम किया जा सके। 64 बिट मोड में, प्रत्येक फ़ंक्शन के लिए आप अपने रैपर के माध्यम से कॉल करना चाहते हैं, आपको यह जानने की जरूरत है कि कुल में कितने तर्क हैं, लेकिन सामान्य प्रयोजन के नियमों में कितने भी हैं, XMM regs में कितने हैं, और कैसे ढेर पर कई।

"एक पॉइंटर के माध्यम से एक func कॉल करें और वापसी मूल्य को एक ज्ञात स्थान पर कॉपी करें" भाग पोर्टेबल है और इसे सादे सी/सी ++ में व्यक्त किया जा सकता है। लेकिन बात यह है कि, इस के लिए तर्क हो जाता है इसके बाद के संस्करण के अनुसार, 32 बिट stdcall और किसी भी 64 बिट x86 बुला सम्मेलन मैं की (न Win64/64 है और न ही संयुक्त राष्ट्र * एक्स x86_64 सम्मेलनों की अनुमति देने के पता के बीच किसी भी सरल तरीके से नहीं बंदरगाह करता है एक समारोह के लिए सभी तर्कों के सभी स्थानों और कुल ढेर स्मृति उपयोग दोनों की भविष्यवाणी करने के लिए केवल तर्कों की संख्या और प्रकार दिए गए हैं, लेकिन उनके आदेश नहीं)।

वास्तव में क्या आपको बस इतना करना ऊपर class ExternalFunctionCall इनलाइन विधानसभा के छोटे छोटे नमूना आप दिखाया है पर से की कॉल/उन पर बहुत अधिकनिर्भर करता है। यह जानना विशेष रूप से जरूरी है कि सदस्य m_argsBegin और m_argsEnd कैसे प्रारंभ किए गए हैं और कहां हैं। क्या आप इस बारे में कुछ और विवरण प्रदान कर सकते हैं कि वर्ग कैसा दिखता है (सभी सदस्य चर/कार्य), साथ ही इसके वास्तविक उपयोग के उदाहरण भी?

+0

धन्यवाद फ्रैंक, मैं एक और बात पूछना चाहता हूं। क्या हम इस एएसएम कोड को एएसएम/एस फाइल में अलग नहीं कर सकते? एक अलग एएसएम फ़ाइल x64 पर MASM64.exe के माध्यम से संकलित कर सकते हैं। यदि संभव हो, तो कृपया मुझे बताएं कि हम यह कैसे कर सकते हैं? हमने सीपीपी में अन्य सभी एएसएम कोड माइग्रेट कर दिए हैं, केवल "__asm ​​पुश वैल" शेष है।आप उपरोक्त पूर्ण कार्य का कोड देख सकते हैं। – vsoni

+0

@ user2118116: जैसा कि पहले से ही कहा गया है, "____ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ यह "अधिक" _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ क्षमा करें, यहाँ कोई आसान तरीका नहीं है। इसे 64 बिट पर पोर्ट करने के बारे में आपका सवाल यह कहने जैसा है कि "मेरा x86 कोड इनलाइन असेंबली में 'lcall' का उपयोग करता है और मुझे इसे एआरएम पर पोर्ट करने की आवश्यकता है, इसलिए मैं एआरएम निर्देश को जानना चाहता हूं जो' lcall' 'करता है। –

+0

@ फ्रैंकएच। इस पर पूर्ण एसीके। मैंने ओपी को इसके डुप्लिकेट में सुझाव दिया: 「सबसे अच्छी बात यह है कि आप [libffi] (http://sourceware.org/libffi/) या [dyncall] (http: // dyncall] का उपयोग कर पूरे फ़ंक्शन को फिर से लिखना है। संगठन /) इसके बजाय। 」 – mirabilos

0

मुझे एहसास है कि यह कुछ हद तक पुराना सवाल है, लेकिन मैं बस इस पर ठोकर खाई: xbyak

शायद आप क्या देख रहे हैं?

+0

हाय निक्स, मैं इस संदर्भ से एएसएम कोड को प्रतिस्थापित करना चाहता हूं: int * start = m_argsBegin; int * ptr = m_argsEnd; int arr [1000], i = 0; जबकि (पीटीआर> शुरू) { int val = * (- ptr); __asm ​​पुश वैल } असल में मैं सीपीपी कोड के साथ "__asm ​​पुश वैल" कथन को प्रतिस्थापित करना चाहता हूं। धन्यवाद – vsoni

+0

m_argsBegin और m_argsEnd क्या हैं? –

+0

@ निक्स- इनमें से दोनों int * धन्यवाद – vsoni

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