web-dev-qa-db-ja.com

x86アセンブリ言語からのC関数の呼び出し

アセンブリ言語プログラムから呼び出すことができるように、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
19
Anderson Green

私はここでメモリから移動するので、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ビットモードで動作していると想定しています。それが16ビットモードなら、それは...

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

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

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

これがお役に立てば幸いです。

22
Sparky

X86_64の場合、次のことに注意してください。