2011-12-11 7 views
5

printfを呼び出すサブルーチンをいくつか定義しようとしています。次のように 非常に簡単な例である:アセンブリサブルーチンは、メインから呼び出されなくても2回呼び出されます。

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 

ここで試験がちょうど画面に数10を出力printf関数への呼び出しを有します。私はそれが呼び出されないので、これが呼び出されるとは思わないでしょう。

はしかし、コンパイルし、実行している場合:

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

を私は出力を得る:

10 
10 

を私は完全に困惑だし、なぜこれが起こっている、誰かが説明できるのか疑問に思っ?

答えて

3

int 80Hは、a)32ビットシステムコール番号を使用し、b)64ビットコードではなく32ビットコードで使用することを意図しています。あなたのコードは実際にはランダムなパラメータでumaskシステムコールを実行しています。 64ビットのシステムコールについては

、代わりにsyscall命令を使用します。

... 
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

感謝を! printfを呼び出すのと同じように、値60(EXIT)をrdiの代わりにraxの代わりに入れますか? –

+0

いいえ、 'rax'のシステムコール番号と' rdi'の最初の引数は正しいです。カーネルのsyscall ABIに関するいくつかのドキュメントと、ユーザーレベルの呼び出し規約との相違点については、http://www.x86-64.org/documentation/abi.pdf(特に付録A)を参照してください。 –

+0

残念なことに残念に思っていますが、私は回線を "int LINUX"に変更してシステムコールを呼び出し、外部システムコールをトップに追加して2つの10を取得しました。あなたが私に電話をかけるためのミニ・サンプルを見せてもらえますか?どうもありがとうございます:) –

2

私はexitへの通話が失敗していると言うでしょう、それが戻ったとき、それはあなたがretに戻ったとき、あなたは戻って、命令に行く最初の10

を印刷しtest機能にフォールスルーcall os_returnの直後、つまり、まあos_returnです。終了への呼び出しは再び失敗し、test関数に再度渡されます。しかし今度はretmain関数から戻り、プログラムが終了します。

なぜexitコールが失敗したかについて、私は64ビットシステムを利用できないため、私にはわかりません。しかし、exit関数をlibcから逆アセンブルして、そこでどのように処理されているのか見ることができます。私の推測では、int LINUXのインターフェイスは32ビットのみであり、歴史的な互換性のために存在し、64ビットのLinuxはそれほど古いものではないためです。

関連する問題