アセンブリ言語プログラムから呼び出すことができるように、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
私はここでメモリから移動するので、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ファイルとアセンブリファイルの両方をオブジェクトファイルにコンパイルし、オブジェクトファイルをリンクして実行する必要があります。
これがお役に立てば幸いです。
X86_64の場合、次のことに注意してください。
スタックは、C呼び出しを行う前に16ビットにアラインする必要があります。
Assemblyで関数を定義する場合、関数を呼び出した関数は戻り値をスタックに配置し、それを調整しません。そのため、通常はPush %rbp
。
これは私にここに例を示します: なぜx86_64アセンブリ関数からCのabort()関数を呼び出すと、アボート信号の代わりにセグメンテーション違反(SIGSEGV)が発生するのですか?
何らかの理由でアセンブリからcall
を実行している場合(TODOなぜそれを実行する必要があるのか?)、次のことを心配する必要があります。
次に例を示します。 拡張インラインASMでprintfを呼び出す