2011-12-31 11 views
9

アセンブリ言語ソースファイルから生成された2つのオブジェクトファイルと、Cソースファイルから生成された2つのオブジェクトファイルのリンクに問題があります。Cオブジェクトファイルをアセンブリ言語オブジェクトファイルにリンクする方法は?

Cソースコード:

//main2.c 
extern int strlength(char *); 
int main(){ 
    char * test = "hello"; 
    int num = strlength(test); 
    return num; 
} 

アセンブリソースコード:

#strlength.s 
.include "Linux32.s" 

.section .text 
.globl strlength 
.type strlength, @function 
strlength: 
pushl %ebp 
movl %esp, %ebp 
movl $0, %ecx 
movl 8(%ebp), %edx 
read_next_byte: 
movb (%edx), %al 
cmpb $END_OF_FILE, %al 
jle end 
incl %edx 
incl %ecx 
jmp read_next_byte 
end: 
movl %ecx, %eax 
popl %ebp 
ret 

私はコンパイルして、このように 'GCC' を使用して実行すると:

gcc main2.c strlength.s -m32 -o test 
./test 
echo $? 

私は5を取得しています正しい。しかし、私はコンパイル時に/別途組み立てた後、このように「LD」 にリンク:私はセグメンテーションフォールトを取得

as strlength.s --32 -o strlength.o 
cc main2.c -m32 -o main2.o 
ld -melf_i386 -e main main2.o strlength.o -o test 
./test 

。これを引き起こしているのは何ですか? Cの呼び出し規約に100%正しく従っていませんか?

答えて

11

ld -melf_i386 -e main main2.o strlength.o -o test

はそれをしないでください。代わりに、次の操作を行います。

gcc -m32 main2.o strlength.o -o test 

(それは/bin/testと競合する可能性として、あなたは、おそらくほとんどのUNIXシステム上の標準、テストexectuable testを呼び出すべきではありません。)

説明:UNIXバイナリは、一般的にないを行いますmainで実行を開始してください。それらはという関数で実行されます。これはまたはそれに類するものです( "Cランタイムスタートアップ")。 そのファイルはlibcの一部であり、アプリケーションの適切な起動に必要なさまざまな初期化を手配します。

あなたのプログラムは、実際にあなたがldとリンクすることができた理由ですlibcからを必要としません。

ただし、mainが返品した後に何が起こるかを考えてください。 通常のコードはcrt1.oのコードはexit(main(argc, argv));を実行します。 crt1.oなしでリンクしているので、最後にexitを行う人は誰もいないので、コードは...未定義の場所に戻り、速やかにクラッシュします。

4

crt1.o(名前が異なる場合があり、mainが呼び出されるまで必要なコードを含む)と必要なライブラリをリンクする必要もあります。 GCCは通常、必要なヘルパー関数(例えば、32ビットシステムで64ビット計算を行う場合)と他のシステムライブラリを含むlibgcc.soにリンクする必要があります。たとえば、私のMacではprintfのような通常のC関数も含まれているlibSystemにリンクする必要があります。 Linuxでは、通常libcです。 (あなたがld .. -e mainとしてやろうとしているよう)あなたのプログラムが直接mainで始めることはできません。

注意、エントリポイントが前にC関数を呼び出すmainにいくつかのことをセットアップする必要があります。これは前述のcrt1.oのことです。私はセグメンテーションフォールトがこの欠けているセットアップの結果であると思います。 GCCは正確にあなたのシステム上をやっているかを見るために

、呼び出し:

gcc main2.c strlength.s -m32 -o test -v 
関連する問題