最近、WindowsでGCCを使用してx86アセンブリを練習しています。現在、テスト目的でアセンブリと C コードを混在させています。現在の知識では説明できない奇妙なことに遭遇したので、SOに助けを求めました。
最小限の例を見てみましょう。C コードにtest_func()関数があり、これをアセンブリに変換してから、後で C コードから呼び出します。ただし、この関数はプロジェクトから他の関数を呼び出しており、そこに問題があります。アセンブリ内から他の C コード関数を呼び出すと、セグメンテーション エラーが発生します。
アセンブリで見たい関数:
#include "rf_string.h"
void test_func()
{//nonsense function, just calling another C function of the project
RF_String s;
rfString_Init(&s,"anything");
}
このためのアセンブリ コードを吐き出すように gcc に要求すると、次のようになります。
.file "to_asm.c"
.section .rdata,"dr"
.align 4
LC0:
.ascii "anything\0"
.text
.globl _test_func
.def _test_func; .scl 2; .type 32; .endef
_test_func:
LFB6:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $40, %esp
movl $LC0, 4(%esp)
leal -16(%ebp), %eax
movl %eax, (%esp)
movl _rfString_Init, %eax
call *%eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE6:
次に、これを「asm_test.S」というファイルに保存し、それをプロジェクトのビルド プロセスに含めることで、正常にビルドおよびリンクされます。そのため、関数を呼び出す簡単なプログラムを作成してみます。
int main()
{
test_func();
return 0;
}
問題はデバッグ時に発生します。アセンブリ コード内から他の C 関数を呼び出すと、セグメンテーション エラーが発生します。これは、アセンブリ コードから呼び出そうとする他の関数で発生します。使用した関数とは特に関係ありません。
ここでの関数呼び出しに関係していると思います:
movl %eax, (%esp)
movl _rfString_Init, %eax
call *%eax
なぜこれを行うのか、これはどういう意味ですか? 具体的には、単に関数を呼び出さないのはなぜですか? また、%eax レジスタの前の * は何ですか? また、最後の 2 行を以下のような関数への単純な呼び出しに置き換えると、すべてが完全に正常に機能しているように見えて、本当に困惑することを追加する必要があります。
call _rfString_Init
もう 1 つの小さな質問は、これらすべての cfi_directives に関するものです。SOで尋ねられた質問への回答で判断する場合、それらは例外処理の目的で生成されているようです。問題は、コードの機能に関する限り、それらを安全に無視できるかどうかです。