2011-11-08 14 views
5

मैं g ++ का उपयोग कर अपने सी ++ प्रोग्राम में naked function का उपयोग करना चाहता हूं। दुर्भाग्य से जी ++, वीसी ++ के विपरीत, नग्न कार्यों का समर्थन नहीं करता है और इसका प्रबंधन करने का एकमात्र तरीका एक अलग फ़ाइल में अपना स्वयं का असेंबली कोड लिखना और अपनी सी ++ फ़ाइलों से लिंक करना है। मैंने x86 के लिए असेंबली और सी/सी ++ फ़ाइलों को मिश्रण करने के लिए कुछ अच्छा ट्यूटोरियल खोजने की कोशिश की लेकिन कोई अच्छा नहीं मिला।मिक्सिंग सी और असेंबली फाइलें

कृपया मुझे बताएं कि क्या आप किसी के बारे में जानते हैं। ध्यान दें कि मैं इनलाइन असेंबली के बारे में नहीं पूछ रहा हूं लेकिन सी और असेंबली फाइलों को जोड़ रहा हूं और असेंबली में सी के बाहरी चर घोषित करने के तरीके और इसके विपरीत सी या असेंबली में उनका उपयोग करने के अलावा, और मेकफ़ाइल का उपयोग करके सी और एएसएम फाइलों को जोड़ने के तरीके भी ।

+0

कोशिश करें और इसे और अधिक विशिष्ट बनाएं - यह अपेक्षाकृत व्यापक और अस्पष्ट है - अन्यथा यह शायद "वास्तविक प्रश्न नहीं" के रूप में बंद हो जाएगा। एएसएम टेम्पलेट इत्यादि बनाने के लिए 'gcc -S ...' का उपयोग करने के बारे में आपके पिछले प्रश्नों में पहले की सलाह को भी याद रखें। –

+0

जीसीसी में एक ही नस में '__attribute __ ((नग्न)) है, लेकिन x86 :( –

उत्तर

16

सी ++ फ़ाइल में:

extern "C" void foo(); // Stop name mangling games 

int main() { 
    foo(); 
} 
"नग्न" एएसएम फ़ाइल में

, x86 के लिए:

# modified from http://asm.sourceforge.net/howto/hello.html 

.text     # section declaration 
    .global foo 

foo: 

# write our string to stdout 

    movl $len,%edx # third argument: message length 
    movl $msg,%ecx # second argument: pointer to message to write 
    movl $1,%ebx  # first argument: file handle (stdout) 
    movl $4,%eax  # system call number (sys_write) 
    int $0x80  # call kernel 

# and exit 

    movl $0,%ebx  # first argument: exit code 
    movl $1,%eax  # system call number (sys_exit) 
    int $0x80  # call kernel 

.data     # section declaration 

msg: 
    .ascii "Hello, world!\n" # our dear string 
    len = . - msg   # length of our dear string 

संकलित, इकट्ठा और लिंक (छ साथ ++ बल्कि ld की तुलना में यह ज्यादा यह करने के लिए आसान है क्योंकि सी ++ के लिए इस तरह) और रन:

[email protected]:/tmp > g++ -Wall -Wextra test.cc -c -o test.o 
[email protected]:/tmp > as -o asm.o asm.S 
[email protected]:/tmp > g++ test.o asm.o 
[email protected]:/tmp > ./a.out 
Hello, world! 

स्पष्ट रूप से यदि आप अपने फ़ंक्शन में तर्क पारित करना चाहते हैं या कुछ भी वापस करना चाहते हैं कहां कॉलिंग सम्मेलनों का सम्मान करने की जरूरत है।

1

मैं सिर्फ पिछली पोस्ट में एक चीज़ जोड़ना चाहता हूं। कल्पना कीजिए कि आप एक समारोह, कि तर्क को स्वीकार करना चाहते हैं: (कुछ

तरह

int add(int,int);

प्रोटोटाइप)

segment .text 
global add 

    add: 
    enter 0,0 
    mov eax,[ebp+8] ; first argument 
    mov ebx,[ebp+12] ; second argument 
    add eax,ebx 
    leave 
    ret 
+1

हाँ के अलावा नहीं धीमे 'एंटर' निर्देश का उपयोग न करें। http://agner.org/optimize/।यहां एक स्टैक फ्रेम बनाने का कोई कारण नहीं है। बस 'mov eax, [esp + 4] '/' eax जोड़ें, [esp + 8] '/' ret'। इसके अलावा, 'ebx' clobber मत करो; यह सभी सामान्य कॉलिंग सम्मेलनों में एक कॉल-संरक्षित रजिस्टर है। एक खतरनाक (और अक्षम) उदाहरण के लिए डाउनवॉटिंग, और आपने यह नहीं दिखाया कि कैसे बनाया जाए + NASM के साथ इसे लिंक करें। –

5

यहाँ एक चाल "नग्न समारोह" प्रभाव को प्राप्त करने का एक उदाहरण है।

#include <stdio.h> 

extern "C" int naked_func(); 

static void 
dummy() 
{ 
    __asm__ __volatile__ 
    (
    " .global naked_func\n" 
    "naked_func:\n" 
    " movq $3141569, %rax\n" 
    " ret\n" 
    ); 
} 

int 
main() 
{ 
    printf ("%d\n", naked_func()); 
    return 0; 
} 
+2

आपको डमी फ़ंक्शन को एक रैपर के रूप में भी आवश्यकता नहीं है क्योंकि मूल इनलाइन असेंबली को वैश्विक दायरे में रखा जा सकता है। –

0

इस विधानसभा में एक समारोह को परिभाषित करने के लिए अपने रास्ते है, यह एक अलग कोडांतरक-फ़ाइल है की जरूरत नहीं है और न ही आप हर न्यू लाइन से बचने के लिए की जरूरत है। आप असेंबली फ़ाइलों की सामग्री स्ट्रिंग-शाब्दिक में कॉपी कर सकते हैं। नोट:raw multiline string literal एक सी ++ 11 सुविधा है (आपने सी ++ भी टैग की है)। यह उपयोगी है, अगर आप एक ही .c -/.cpp -file में सबकुछ संकलित करना चाहते हैं।

extern"C" int rand_byte(void); 
asm (R"(
    .globl rand_byte 
rand_byte: 
    call rand 
    and eax, 255 
    ret 
)"); 

आप वैश्विक दायरे में अतिरिक्त पैरामीटर के बिना केवल मूल असेंबली-स्टेटमेंट का उपयोग कर सकते हैं। जीसीसी या क्लैंग और एक आर्म प्रोसेसर का उपयोग करते समय, आप [[gnu::naked]]/__attribute__((naked)) का उपयोग करने में सक्षम हैं।

[[gnu::naked]] 
int rand_byte(void) { 
    asm volatile (R"(
     push {lr} 
     bl rand 
     and r0, #255 
     pop {pc} 
    )"); 
}; 

पहला तरीका हमेशा नग्न कार्यों को परिभाषित करने की अनुमति देता है। यह और अधिक पोर्टेबल कोड बनाने में भी मदद करता है।

extern"C" int _cdecl rand_byte(void); 
    #if defined __x86__ 
     // NOTE: the names are decorated with a '_' on windows 32-bit 
     // You can use extern"C" int _cdecl rand_byte() asm("rand_byte"); 
     // to make the asm symbol name always be rand_byte, without an _ 
     asm volatile (R"(
      .globl _rand_byte 
     _rand_byte: 
      call rand 
      and eax, 255 
      ret 
     )"); 
    #elif defined __x86_64__ 
     asm volatile (R"(
      .globl rand_byte 
     rand_byte: 
      call rand 
      and rax, 255 # eax works here, too. x86-32 and -64 could share the same source. 
      ret 
     )"); 
    #elif defined __arm__ 
     asm (R"(
      .global rand_byte 
     rand_byte: 
      push {lr} 
      bl rand 
      and r0, #255 
      pop {pc} 
     )"); 
    #else 
     #error There is no code for your platform yet... 
    #endif 
+0

आप जीसीसी/जी ++ में वैश्विक दायरे में एक बुनियादी एएसएम स्टेटमेंट का उपयोग कर सकते हैं। आप वैश्विक दायरे में विस्तारित इनलाइन असेंबली का उपयोग नहीं कर सकते हैं। एक बुनियादी असेंबली कथन हमेशा दस्तावेज़ीकरण के प्रति अस्थिर रूप से अस्थिर है। –

+0

आपका x86 बनाम x86-64 उदाहरण थोड़ा मूर्ख है। 'और eax, 255' जो आप x86-32 और x86-64 दोनों पर चाहते हैं, और' और रैक्स, 255' से छोटा बाइट है। इसके अलावा, 'movzx eax, al' दोनों पर थोड़ा बेहतर है, क्योंकि यह छोटा है। क्या आप वाकई इसे इकट्ठा करते हैं? गैस निर्देश '.globl' या 'global' है, न कि 'वैश्विक'। 'Gcc -masm = intel' का उपयोग करना अभी भी जीएएस निर्देशों का उपयोग करता है, न कि NASM। (यह ठीक संकलित करेगा, लेकिन इकट्ठा नहीं होगा। गॉडबॉल्ट पर, यह सुनिश्चित करने के लिए "द्विआधारी" मोड का उपयोग करें, यह सुनिश्चित करने के लिए कि यह संकलित और संकलन भी है।) इसके अलावा, एआरएम में 'eax' नहीं है, इसमें' r0' है। –

+0

बेशक, 'rand_byte' के लिए asm मूर्खतापूर्ण है। 'रैंड' के लिए केवल एक कमजोर उपनाम 'uint8_t rand_byte' बनाने के लिए बेहतर होगा जब कॉलिंग सम्मेलन संकीर्ण रिटर्न मानों को उच्च कचरा (x86 पर नहीं बल्कि एआरएम पर) की अनुमति देता है, और कॉलर को शून्य-एक्सटेंशन को इनलाइन करने की आवश्यकता होने पर अनुमति दें । इनलाइन एएसएम के उदाहरणों के साथ आना लगभग असंभव है, जहां यह केवल https://gcc.gnu.org/wiki/DontUseInlineAsm के लिए बेहतर नहीं होगा, लेकिन आप कम से कम इसका उल्लेख करना चाहेंगे। (शायद विशेषाधिकार प्राप्त निर्देशों को छोड़कर जिनके पास अंतर्निहित/आंतरिक रैपर नहीं हैं)। –

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