29

アセンブリ言語プログラムから呼び出すことができるように、GCC を使用して C 関数からアセンブリ言語関数を生成することは可能ですか? gcc が C をマシン コード (アセンブリ言語に簡単に逆アセンブルできる) にコンパイルすることは知っています。また、 C でアセンブリ言語関数をインライン化できることは既に知っていますが、アセンブリから C 関数を呼び出す方法はまだ見つかっていません。これは基本的にこれの逆です。

ここでは、x86 アセンブリ プログラムで C 関数をインライン化しようとしています。インライン化ができない場合、アセンブリ言語プログラムから C 関数を呼び出す他の方法はありますか?

.686p
.model flat,stdcall
.stack 2048

.data

.code
start:

invoke  ExitProcess, 0

printSomething PROC ;now I'm attempting to inline a C function here
    void printSomething(thingToPrint){
        printf("This is a C function that I want to invoke from an assembly language program.");
        printf("There must be some way to do this - is it possible somehow?");
    }
printSomething ENDP

end start
4

2 に答える 2

35

私はここで記憶から行っているので、1つか2つの詳細でわずかにずれている可能性があります. しかし、あなたが正しい方向に進むにはそれで十分であることを願っています.

ルーチンprintSomething()がアセンブリ ファイルで定義されていないことを GCC アセンブラに伝える必要があります。「C」ではexternキーワードを使用します。アセンブリには.globlを使用する必要があります。

.globl printSomething

GCC 以外のアセンブラを使用している場合は、キーワードが異なる場合があります。

次の大きな問題は、「引数を渡す方法」です。これは、プロセッサと OS に大きく依存します。質問のタイトルはx86を示しているため、16ビットまたは32ビットモードと標準のx86 ABIを使用していると仮定します(WindowsとLinuxでも異なるx86-64とは対照的です)。C パラメータは、スタックにプッシュすることによって、呼び出されたルーチンに渡されます。それらは右から左にスタックにプッシュされます。

したがって、

printSomething (arg1, arg2, arg3, arg4);

に変換します...

pushl arg4
pushl arg3
pushl arg2
pushl arg1
call  printSomething
addl  $0x10, %esp

あなたは自問するかもしれません、これは何ですか

addl $0x10, %esp

? 4 つの 32 ビット引数をルーチンに (スタックに) 渡しました (別名プッシュ)。ルーチンはこれらの引数を予期することを認識していますが、それらをスタックからポップする責任はありません。その責任は呼び出し元にあります。そのため、ルーチンから戻った後、スタック ポインターを調整して、以前にスタックにプッシュした 4 つの 32 ビット引数を破棄します。

上記の例では、32 ビット モードで動作していると想定しています。16bitモードだったら…

pushw arg4
pushw arg3
pushw arg2
pushw arg1
call  printSomething
addw  $0x8, %sp

あなたの例では、printSomething()は1つの引数しかとらず、私の例では4つ使用したことに気づきました。必要に応じて私の例を調整してください。

最後の手順として、C ファイルとアセンブリ ファイルの両方をオブジェクト ファイルにコンパイルし、オブジェクト ファイルをリンクしてから実行する必要があります。

これが役立つことを願っています。

于 2013-04-28T13:43:21.923 に答える