无处不在我寻找链接器实际上做了什么(除了重定位,有些人似乎置于“加载”之下)人们给出了两个(比方说)C模块的例子,它们互相调用函数。
据我了解,这应该通过预处理(#include等)来处理。我可以理解,如果我想在不同的时间组装两个模块,我需要稍后链接它们。但是当我使用说gcc时,它会直接输出可执行文件,所以在这个上下文中我并没有真正看到链接点,除非预处理(我将猜测它将是递归的)最终命中对象代码。
注意:我在这里指的是静态链接。我可以看到动态链接的重点。
答案 0 :(得分:1)
gcc正在使用大量工具来创建可执行文件,编译器就是其中之一,链接器,预处理器等也是如此,以查看它实际上正在做什么将-v
选项传递给它。如果你想看到中间文件使用-save-temps
,即一旦你创建了下面的文件,试试这个......
gcc-5 -save-temps -v -std=c11 -Wall -pedantic-errors main.c foo.c
如果查看目录,您会看到几个额外的文件......
a.out // Executable when no name is specified
foo.c // original foo.c
foo.h // original foo.h
foo.i // Preprocessed ouput of foo.c and foo.h
foo.o // foo Object file
foo.s // foo assembler
main.c // original main.c
main.i // main preprocessed
main.o // main object file
main.s // main assembler
如果您查看main.i
,您会发现它包含此内容
# 1 "foo.h" 1
int foo(int i);
但它不知道函数foo实际上做了什么。这都在foo.i
。这也意味着在创建目标文件时main.o
知道它需要foo
函数。将main.o中的符号foo
与foo.o中的foo
连接是链接器正在进行的操作。
这是一个例子,创建以下三个文件
foo.h中
#ifndef FOO_H
#define FOO_H
int foo(int i);
#endif
foo.c的的
#include "foo.h"
int foo(int i) {
return i - 1729;
}
的main.c
#include "foo.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("%d\n", foo(1));
return 0;
}
创建他们的Object文件,即不是可执行文件,如下所示,注意我已经为此添加了详细的标志..
gcc-5 -v -std=c11 -Wall -pedantic-errors main.c foo.c -c
如果您使用了-o
标志,您将看到gcc调用的实际链接器命令将对象链接到可执行文件中,即
gcc-5 -v -std=c11 -Wall -pedantic-errors main.c foo.c -o fooer
此时,您将在目录中找到两个目标文件。您可以使用ld创建可执行文件,如下所示(注意这是特定于mac的,使用gcc -v的输出为您的机器找到正确的命令)。
ld -dynamic -arch x86_64 -macosx_version_min 10.11.3 -lSystem main.o foo.o -o fooer