2011-12-11 10 views
5

से भी बुलाए बिना दो बार बुलाया जाता है, मैं उन कुछ subroutines को परिभाषित करने की कोशिश कर रहा हूं जिनके पास printf को कॉल किया गया है। एक बहुत ही तुच्छ उदाहरण इस प्रकार है:असेंबली सबराउटिन को मुख्य

extern printf 
LINUX  equ  80H 
EXIT   equ  60 

section .data 
    intfmt: db "%ld", 10, 0 

segment .text 
    global main 

main: 
    call os_return  ; return to operating system 

os_return: 
    mov rax, EXIT  ; Linux system call 60 i.e. exit() 
    mov rdi, 0  ; Error code 0 i.e. no errors 
    int LINUX  ; Interrupt Linux kernel 

test: 
    push rdi 
    push rsi 
    mov rsi, 10 
    mov rdi, intfmt 
    xor rax, rax 
    call printf 
    pop rdi 
    pop rsi 
    ret 

यहाँ परीक्षण सिर्फ printf कि स्क्रीन पर नंबर 10 आउटपुट के लिए एक कॉल है। मैं इसे कॉल करने की उम्मीद नहीं करता क्योंकि मुझे इसके लिए कोई फोन नहीं है।

हालांकि संकलन है और चल रहा है जब:

nasm -f elf64 test.asm 
gcc -m64 -o test test.o 

मैं आउटपुट प्राप्त:

10 
10 

मैं पूरी तरह विस्मित कर रहा हूँ और सोचा कि अगर किसी को समझा सकता है क्यों यह हो रहा है?

उत्तर

3

int 80H 32-बिट सिस्टम कॉल इंटरफ़ेस का आह्वान करता है, जो ए) 32-बिट सिस्टम कॉल नंबर का उपयोग करता है और बी) 32-बिट कोड का उपयोग करने के लिए है, 64-बिट कोड नहीं। आपका कोड वास्तव में यादृच्छिक पैरामीटर के साथ umask सिस्टम कॉल कर रहा है।

... 
os_return: 
    mov rax, EXIT  ; Linux system call 60 i.e. exit() 
    mov rdi, 0  ; Error code 0 i.e. no errors 
    syscall   ; Interrupt Linux kernel 
... 
+0

धन्यवाद:

64-बिट सिस्टम कॉल के लिए, बजाय syscall अनुदेश का उपयोग करें! क्या मैं मूल्य 60 (EXIT) आरडीआई में डालता हूं, फिर रैक्स के बजाय, printf को कॉल करने के समान? –

+0

नहीं, 'रैक्स' में syscall संख्या डालना और 'rdi' में पहला तर्क सही है। कर्नेल syscall एबीआई के कुछ दस्तावेज और उपयोगकर्ता स्तर के कॉलिंग सम्मेलनों के अंतर के लिए http://www.x86-64.org/documentation/abi.pdf (विशेष रूप से परिशिष्ट ए) देखें। –

+0

इस बारे में आपको बुरा रखने के लिए खेद है, लेकिन मैंने syscall को कॉल करने के लिए "int LINUX" पंक्ति को बदल दिया और शीर्ष पर बाहरी सिस्कोल जोड़ा और अभी भी दो दस प्राप्त करें। क्या कोई मौका है कि आप मुझे सिस्कोल को कॉल करने का एक छोटा सा उदाहरण दिखा सकते हैं? बहुत बहुत धन्यवाद :) –

2

मैं कहूँगा कि exit करने के लिए अपने कॉल विफल हो रहा है, इसलिए जब वह लौटता है, यह है कि पहली से 10

फिर प्रिंट test कार्य करने के लिए के माध्यम से गिर जाता है, जब आप ret के साथ वापसी आप अनुदेश के लिए वापस जाओ call os_return के ठीक बाद, यह os_return है। बाहर निकलने के लिए कॉल फिर से विफल हो जाता है और फिर से test फ़ंक्शन पर आता है। लेकिन इस बार retmain फ़ंक्शन से लौटाता है और प्रोग्राम समाप्त होता है।

exit कॉल विफल होने के कारण क्यों है, मैं यह नहीं बता सकता कि मेरे पास 64-बिट सिस्टम उपलब्ध नहीं है। लेकिन आप libc से exit फ़ंक्शन को अलग कर सकते हैं और देख सकते हैं कि यह कैसा किया जाता है। मेरा अनुमान है कि int LINUX इंटरफ़ेस केवल 32-बिट है, क्योंकि यह केवल ऐतिहासिक संगतता के लिए मौजूद है, और 64-बिट लिनक्स इतना पुराना नहीं है।