如何将C对象文件与汇编语言对象文件链接?

时间:2011-12-31 23:57:51

标签: c linux assembly ld gas

我无法链接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

我遇到了分段错误。是什么造成的?我没有100%正确地遵循C调用约定吗?

2 个答案:

答案 0 :(得分:11)

  

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

不要那样做。这样做:

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

(你可能不应该调用你的测试exectuable test,因为它可能与大多数UNIX系统上的/bin/test标准冲突。)

说明:UNIX二进制文件 not 通常在main开始执行。它们开始在名为_start的函数中执行,该函数来自crt1.o或类似(“C运行时启动”)。 文件是libc的一部分,它安排了各种初始化,这是正确启动应用程序所必需的。

您的程序实际上不需要libc中的任何,这就是您可以将其与ld相关联的原因。

但是,请考虑在main返回后会发生什么。 通常crt1.o中的代码将执行(相当于)exit(main(argc, argv));。由于您在没有crt1.o的情况下进行了链接,因此无法为您执行最终exit,因此代码将返回到...未定义的位置并立即崩溃。

答案 1 :(得分:4)

您还需要链接crt1.o(可能有不同的名称,包含必要的代码,直到可以调用main)和必要的库。 GCC通常还需要链接到libgcc.so,其中包含必要的辅助函数(例如,在32位系统上进行64位计算时)以及其他系统库。例如,在我的Mac上,它还需要链接到libSystem,其中还包含printf等常用的C函数。在Linux上,通常是libc

请注意,您的程序无法直接以main开头(正如您尝试使用ld .. -e main),入口点需要在调用C函数之前设置一些内容{ {1}}。这就是前面提到的main正在做的事情。我想分段错误是这种缺失设置的结果。

要了解GCC在您的系统上正在做什么,请致电:

crt1.o