4

_ExitGCC のインライン アセンブラ機能をいじりながら、C 標準ライブラリに似た、すぐにプロセスを終了する関数を作成しようとしました。

関連するソースコードは次のとおりです。

void immediate_exit(int code)
{
#if defined(__x86_64__)
    asm (
            //Load exit code into %rdi
            "mov %0, %%rdi\n\t"
            //Load system call number (group_exit)
            "mov $231, %%rax\n\t"
            //Linux syscall, 64-bit version.
            "syscall\n\t"
            //No output operands, single unrestricted input register, no clobbered registers because we're about to exit.
            :: "" (code) :
    );
//Skip other architectures here, I'll fix these later.
#else
#   error "Architecture not supported."
#endif
}

これはデバッグ ビルド (を使用-O0) では問題なく機能しますが、任意のレベルで最適化をオンにするとすぐに、次のエラーが発生します。

immediate_exit.c: Assembler messages:
immediate_exit.c:4: Error: unsupported for `mov'

そこで、両方のビルドのアセンブラー出力を調べました (.cfi*わかりやすくするために、ディレクティブやその他のものを削除しました。問題がある場合は、再度追加できます)。デバッグ ビルド:

immediate_exit:
.LFB0:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)

    mov -4(%rbp), %rdi
    mov $231, %rax
    syscall

    popq    %rbp
    ret

そして最適化されたバージョン:

immediate_exit:
.LFB0:
    mov %edi, %rdi
    mov $231, %rax
    syscall

    ret

そのため、最適化されたバージョンは、32 ビット レジスタをからロードするのではなくedi、64ビット レジスタに入れようとしています。これがエラーの原因であると推測されます。rdirbp

これで、 'm' を のレジスタ制約として指定することでこれを修正できます。これにより、最適化レベルに関係なくcodeGCC がロードされます。rbpただし、コンパイラとその作成者は、どこに何かを配置するかについて、私よりもはるかに優れた考えを持っていると思うので、私はそれをしたくありません。

だから(最後に!)私の質問は、GCCをアセンブリ出力でrdiはなく使用するように説得するにはどうすればよいですか?edi

4

2 に答える 2

9

全体として、明示的な移動ではなく、制約を使用して値を適切なレジスタに取得する方がはるかに優れています。

asm("syscall" :: "D" ((uint64_t)code), "a" ((uint64_t)231));

これにより、コンパイラは、有用な場合はコードの早い段階で移動を巻き上げたり、値がすでに正しいレジスタにあるように配置できる場合は移動を完全に回避したりできます...

于 2013-09-10T17:26:18.823 に答える