2011-01-13 33 views
27

Cプロジェクトから呼び出されたアセンブリで関数を使用しようとしています。この関数はlibc関数を呼び出して、printf()としましょうが、セグメンテーション・フォルトが発生し続けます。私は、関数の宣言がのが.ASMファイルでCアセンブリからの呼び出し関数

int do_shit_in_asm() 

を言わせてい.cファイルで

は私が

.extern printf 
.section .data 
     printtext: 
       .ascii "test" 
.section .text 
.global do_shit_in_asm 
.type do_shit_in_asm, @function 

do_shit_in_asm: 
    pushl %ebp 
    movl %esp, %ebp 
    push printtext 
    call printf 
    movl %ebp, %esp 
    pop %ebp 
ret 

コメントをいただければ幸いですどれ ポインタを持っています。アセンブリ言語関数を使い始めるための最良の方法の

as func.asm -o func.o 

gcc prog.c func.o -o prog 
+23

+1ファンクション名 –

+33

"すべてのポインタがわかります":int * ptr; – Sapph

+0

@Sapph +1しかしそれは助けません:)) –

答えて

16

変更push printtext

9

一つはCで同様の機能を記述し、その後、アセンブリリスト(gccの上-S)を生成するコンパイラスイッチでそれを構築することです。その後、コンパイラの出力を調べ、必要に応じて変更することができます。

printfなどさまざまな呼び出し規約(引数の数が異なるため)を使用する関数を呼び出す場合に特に便利です。これらの関数を呼び出すことは、非varargs関数を呼び出すこととはかなり異なる場合があります。この後

+1

非常に教育的ですが、一般的には非常に誤解を招くこともあります。本当の問題は、ABI固有の詳細、つまりレジスタを保存しなければならないこと、その意味、C ABIとのやりとりの仕方です。最初にこのパスをたどって、私のアセンブリは、コンパイラが生成しようとしていたものとまったく逆のものだったことに気付きました! – bbum

2

push printtext 
call printf 

あなたが欲しい:

addl $4, %esp 

さらなる説明:

あなたは、x86のLinuxを使っているので、私は、呼び出し規約がクリーンアップに呼び出し先を必要と仮定パラメータ。 printfを呼び出す前にポインタを押したので、その関数のret命令が実行された後、スタックは4でオフになります。

更新:

うん、OK、私はので、私は後方に私の頭の中で引数の順序を得ていたインテルの構文に使用されました。実際にはespに戻るaddlの不足は問題ありません。の近くでespを正しく復元しているためです。

OK、gasヌルの文字列を終了します。私の次の推測では

アップデート2 ...私はgasが何をするか見てみましょう...あなたがprintfに渡している文字列がnullターミネータを欠いていることですあなた、私は2番目の勘違いが間違っていたと思います。あなたが問題を発見したように見えるので、その点は疑問です。push $printtextにP

+0

まだセグメンテーションフォルト –

+0

私はインテルの構文に慣れていたので混乱しましたあなたは実際に 'addl $ 4、%esp'を望んでいます。もう一度見てみましょう... – asveikau

+0

@void - おそらく16進エディタをチェックすることができます。 printfに渡す文字列はnullで終了しますか? – asveikau

6

問題は、私は

pushl printtext 

むしろ

pushl $printtext 

そのおかげであなたの助けとあなたの時間を無駄にして申し訳ありませんのために皆を使用していたということでした。

これはそのままですが、アドレスprinttextから値をロードして、アドレスを押すのではなく、それを押しています。したがって、あなたはポインタではなく32ビットの数値として'test'を渡しており、printfはそれをアドレスとして解釈してクラッシュするように試みています。

+1

投稿する前にそれを手に入れました。あなたの問題を解決することにおめでとう。 :-) –

関連する問題