2011-12-31 73 views
9

我無法鏈接2個對象文件,其中一個是從彙編語言源文件生成的,另一個是從C源文件生成的。如何鏈接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調用約定嗎?

回答

11

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

不要那樣做。做到這一點,而不是:

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

(你可能不應該打電話給你測試exectuable test,因爲它可能與/bin/test衝突,在大多數UNIX系統的標準。)

說明:UNIX二進制文件做一般開始執行main。他們開始執行一個名爲_start的函數,該函數來自crt1.o或類似的函數(「C運行時啓動」)。 文件是libc的一部分,它安排了各種初始化,這是適當啓動應用程序所必需的。

你的程序實際上不需要任何libc,這就是爲什麼你可以把它與ld鏈接。

但是,請考慮您的main返回後會發生什麼情況。 通常crt1.o中的代碼將執行(相當於)exit(main(argc, argv));。既然你鏈接沒有crt1.o,沒有人爲你做最後的exit,所以代碼返回...未定義的位置,並迅速崩潰。

4

您還需要鏈接crt1.o(可能有不同的名稱,包含必要的代碼,直到main可以調用)和必要的庫。 GCC通常還需要鏈接到libgcc.so,其中包含必要的幫助函數(例如,在32位系統上執行64位計算時)以及其他系統庫。例如,在我的Mac上,它也需要鏈接到libSystem,其中還包含通常的C函數,如printf。在Linux上,通常是libc

請注意,你的程序不能直接與main開始(因爲你正在試圖做的與ld .. -e main),入口點需要幾件事情成立調用C函數main之前。這就是前面提到的crt1.o正在做的事情。我猜想分段錯誤是由於這種缺失設置造成的。

要了解GCC正好做系統,請致電:

gcc main2.c strlength.s -m32 -o test -v