Cプログラム(GNUアセンブラー)で使用するアセンブリルーチンをコンパイルするにはどうすればよいですか?
-
03-07-2019 - |
質問
ヘッダーファイルを作成して、Cプログラムで使用するアセンブリ関数のセットがあります。たとえば、実際のアセンブリルーチンを定義するasm_functions.sと、関数のプロトタイプと標準の#defineが必要なasm_functions.hがある場合です。私の目標は、Cプログラム、たとえばtest_asm.cを使用してアセンブリ関数を呼び出すことです。
asm__functions.h:
#define ASM_CONST_1 0x80
#define ASM_CONST_2 0xaf
uint8_t asm_foo( int, int, int );
asm__functions.s:
/* dont need this: #include "asm_functions.h" */
.section .text
.type asm_foo, @function
asm__foo:
/* asm code with proper stack manipulation for C calling conventions */
ret
test__asm.c:
#include "asm_foo.h"
int main() {
uint8_t res = asm_foo( 1, 2, 3);
return 0;
}
このような状況では、プログラムのリンクをコンパイルする適切な方法は何でしょうか?私はこのようなことを試みていました:
gas -o asm_foo.o asm_foo.s
gcc -o test_asm test_asm.c
しかし、アセンブリルーチンが未定義であるというGCCからのリンカーエラーがまだ発生しています。この不自然な例が状況を説明するのに十分であると思います。
ありがとう!
編集:
これは、1つのコマンドでコンパイルしたときの出力のスニペットです。
tja@tja-desktop:~/RIT/SP2/latest$ gcc -o test_pci pci_config.s test_pci.c
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0x8): undefined reference to
PCI_FUNCTION_ID'
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0xa): undefined reference to
READ_CONFIG_BYTE'
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0x18): undefined reference to
PCI_BIOS_FUNCTION_INT'
/tmp/ccY0SmMN.o: In function _pci_bios_read_byte':
(.text+0x1b): undefined reference to
BAD_REGISTER_NUMBER'
/tmp/ccY0SmMN.o: In function _pci_bios_read_word':
(.text+0x30): undefined reference to
PCI_FUNCTION_ID'
...
PCI_FUNCTION_IDなど、これらはすべてヘッダーファイルに定義されており、Cプログラムに含まれています。アセンブリコードを単独でコンパイルしてもエラーはありません。
解決
質問のファイルに基づいて、私はなんとかコンパイルしました。ファイル名とファイルの内容の両方を変更しました。
asm_const.h:
#define ASM_CONST_1 0x80
#define ASM_CONST_2 0xaf
asm_functions.h:
#include "asm_const.h"
unsigned char asm_foo( int, int, int );
asm_functions.S(末尾のSは大文字でなければなりません!#includeで必要です):
#include "asm_const.h"
.section .text
.globl asm_foo
.type asm_foo, @function
asm_foo:
mov $ASM_CONST_1, %eax
/* asm code with proper stack manipulation for C calling conventions */
ret
test_asm.c:
#include "asm_functions.h"
int main() {
return asm_foo( 1, 2, 3);
}
大文字のSを持つアセンブリファイル拡張子.Sが必要であることに注意してください。.sを使用すると、.sファイルはプリプロセッサを介して実行されないため、#includeは機能せず、 .sファイルでASM_CONST_1を使用できます。
単一のコマンドでコンパイル:
gcc -o test_asm asm_functions.S test_asm.c
または、代わりに、複数のコマンドを使用してコンパイルし、.oファイルを作成します:
gcc -c asm_functions.S
gcc -c test_asm.c
gcc -o test_asm asm_functions.o test_asm.o
単一コマンドgccは、gasを使用して.Sファイルをコンパイルし、GCCのCコンパイラを使用して.cファイルをコンパイルし、ldを使用して結果の一時.oファイルをリンクします。 gccは、これらすべてのコマンドをデフォルトで適切なフラグで実行します。
一部のシステム(ただし、デフォルトのGCCインストールのLinuxではない)では、.Sファイル(.cまたは.hファイルではない)でエクスポートされた関数の名前にアンダースコアを付加する必要があります。したがって、 asm_foo
のすべてのインスタンスは、.Sファイルでのみ _asm_foo
になります。
他のヒント
インラインアセンブリの使用を検討しましたか?アセンブラーファイルを使用するよりもはるかに簡単です。
編集:また、リンカーエラーが発生する理由は、おそらくCコンパイラが実際のシンボルの識別子に先頭の下線を追加するためです。アセンブリファイルにアンダースコアを追加してみてください。