10

我在链接 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 调用约定吗?

4

2 回答 2

13

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人为您执行最终操作,因此代码返回到 ... undefined location 并立即崩溃。

于 2012-01-01T00:07:58.680 回答
4

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

请注意,您的程序不能直接以 with 开头main(就像您尝试使用 with 一样ld .. -e main),入口点需要在调用 C function 之前设置一些东西main。这就是前面提到crt1.o的正在做的事情。我猜分段错误是缺少设置的结果。

要查看 GCC在您的系统上究竟做了什么,请调用:

gcc main2.c strlength.s -m32 -o test -v
于 2012-01-01T00:07:01.350 回答