0

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が行うのは本当にばかげているようです。:( 提案がある場合は、回答を残してください。

4

2 に答える 2

4

この問題の解決策を見つけることができて非常に幸運でしたが、最終的にはやりたいことが実現しました。バージョン 4.7.2 の GCC マニュアルの状態は次のとおりです。

-mpush-args
-mno-push-args
Use PUSH operations to store outgoing parameters. This method is shorter
and usually equally fast as method using SUB/MOV operations and is enabled
by default. In some cases disabling it may improve performance because of
improved scheduling and reduced dependencies.

-maccumulate-outgoing-args
If enabled, the maximum amount of space required for outgoing arguments will
be computed in the function prologue. This is faster on most modern CPUs
because of reduced dependencies, improved scheduling and reduced stack usage
when preferred stack boundary is not equal to 2. The drawback is a notable
increase in code size. This switch implies ‘-mno-push-args’.

-mpush-args が機能しないため、私は幸運だと言っています。代わりに機能するのは、文書化されていない「-mno-accumulate-outgoing-args」です!

于 2012-11-29T03:49:16.293 に答える
3

私は最近同様の質問をしましたが、人々はそれが重要だとは思わなかったと思います.少なくともGCC 4.8.1の文書化されていないオプションを見つけました.最新の4.9バージョンについては知りません.

誰かが、「警告: スタック プローブには正確さのために -maccumulate-outgoing-args が必要です [デフォルトで有効]」というエラー メッセージが表示されると言いました。

スタック プローブを無効にするには、-mno-stack-arg-probe を使用します。そのため、次のオプションを確実に渡してください。

-mpush-args -mno-accumulate-outgoing-args -mno-stack-arg-probe

私にとっては、これでうまくいきます。PUSH を使用し、はるかに小さくて優れたコードを使用し、OllyDbg でデバッグするのがはるかに簡単です。

于 2014-07-27T15:22:38.013 に答える