GCC/G++ で小さな 16 ビット OS の開発を開始しました。私はCygwinでコンパイルしたGCCクロスコンパイラを使用しています.asm( ".code16gcc\n")を各.CPPファイルの最初の行として配置しています。 .CPP ファイルは次のようになります。
G++: i586-elf-g++ -c $(CPP_FILE) -o $(OBJECT_OUTPUT) -nostdinc -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fpermissive -masm=intel
LD: i586-elf-ld -T $(LD_SCRIPT) $(OBJECT_OUTPUT) -o $(BINARY_OUTPUT)
私が現在直面している問題は、GCC が関数呼び出しコードをアセンブリに変換する方法です。
より具体的には、PUSH 命令を使用して引数を渡す代わりに、GCC は引数が配置されるべき ESP に対するオフセットを「計算」し、MOV 命令を使用してスタックを手動で書き込みます。
アセンブリ コードの PUSH 命令に依存しているため、これは私にとって有益ではありません。私の問題をより明確に説明するために、次の 2 つの関数を使用します。
void f2(int x);
void f1(){
int arg = 8;
asm("mov eax, 5");
asm("push eax");
f2(arg);
asm("pop eax");
}
void f2(int x){
}
関数 f1 では、PUSH 命令を使用して EAX を保存しています。f2 を呼び出して「POP EAX」命令を実行した後、5 に復元されることを期待しています。ただし、EAX は 5 ではなく 8 になることが判明しました。これは、GCC が生成する ASSEMBLY CODE が次のようになっているためです (わかりやすくするためにソースも含めました)。
void f1()
C++: {
push ebp
mov ebp,esp
sub esp,byte +0x14
C++: int arg = 8;
mov dword [ebp-0x4],0x8
C++: asm("mov eax, 5");
mov eax,0x5
C++: asm("push eax");
push eax
C++: f2(arg);
mov eax,[ebp-0x4]
mov [dword esp],eax =======>>>>>> HERE'S THE PROBLEM, WHY NOT 'PUSH EAX' ?!!
call f2
C++: asm("pop eax");
pop eax
C++: }
o32 leave
o32 ret
void f2(int x)
C++: {
push ebp
mov ebp,esp
C++: }
pop ebp
o32 ret
-mpush-args や -mno-push-args などのいくつかの G++ コンパイル フラグを使用してみましたが、覚えていない別のフラグもあり、GCC はまだ PUSH を使用したくありません。私が使用しているバージョンはi586-elf-g++ (GCC) 4.7.2
(Cygwin で再コンパイルされたクロスコンパイラ) です。
前もって感謝します!
更新:ここに私が見つけたウェブページがあります: http://fixunix.com/linux/6799-gcc-function-call-pass-arguments-via-push.html
複雑なものに対するインラインアセンブリの使いやすさを制限することを考えると、GCCが行うのは本当にばかげているようです。:( 提案がある場合は、回答を残してください。