我读了一些帖子,得出的结论是extern告诉编译器“这个函数存在,但是它的代码在别的地方。不要惊慌。”但是链接器怎么知道这个函数在哪里定义呢?
我的案例:-我正在Keil uvision 4上工作。有一个头文件grlib. h,主函数在grlib_demo.c中(它包括grlib. h)。现在,有一个函数GrCircleDraw(),它在Circle. c中定义,并在grlib_demo. c中调用,还有一个语句
外部空GrCircleDraw(所有参数);
我的问题是链接器如何知道GrCircleDraw()的定义在哪里,因为Circle.c不包含在grlib. h和grlib_demo. c中
注意:-文件grlib. h和Circle. c在同一个文件夹中。代码运行成功。
4条答案
按热度按时间sczxawaw1#
简单的答案是“编译器不需要知道,但是链接器必须能够找到它”,通过多个
.o
文件,或者通过库,链接器必须能够找到GrCircleDraw
函数的单个定义。n6lpvg4x2#
当您在ELF format中编译.o文件时,
.o
文件上有许多内容,例如:.text
段;.data
、.rodata
、.rss
段;.symtab
,包含.o
中的符号(函数、全局变量等)列表(以及它们在文件中的位置)以及.o
文件所使用的符号;.rela.text
这样的部分是重定位列表--这些是链接编辑器(和/或动态链接器)为了将程序的不同部分链接在一起而必须进行的修改。在呼叫方
让我们编译一个简单的C文件:
与:
(我使用的是我系统的本机编译器,但交叉编译到ARM时,它的工作原理完全相同)。
您可以使用以下命令查看.o文件的内容:
在符号表中,您会发现:
我们的
foo
函数和bla
函数各有一个符号,值字段给予了它们在.text
部分中的位置。对于所使用的符号
GrCircleDraw
,存在一个符号:它是未定义的,因为该函数未在该.o
文件中定义,而是仍在别处找到。在
.text
部分(.rela.text
)的重新定位表中,您可以找到:此地址位于
foo
:链接编辑器将用X1 M17 N1 X函数的地址修补该地址处的指令。在被叫方
现在让我们自己编译一个
GrCircleDraw
的实现:让我们看看它的符号表:
它有一个
GrCircleDraw
条目,用于定义其在.text
节中的位置。∮把他们联系在一起∮
因此,当链接编辑器将两个文件组合在一起时,它知道:
.o
文件中定义了哪些函数及其位置;dldeef673#
编译器只将
extern
函数的名称放入.obj
文件。编译器不需要了解更多信息。当你开始链接时,作为一个开发者,你有责任给链接器给予所有必要的目标文件和库文件。链接器会把所有这些函数安排成一个二进制文件。如果你没有指定正确的库或
.obj
文件,链接就会失败,并返回unresolved blah-blah
。默认库通常是隐式包含的。这会使事情复杂化并产生错觉。你总是可以指定你不想要任何隐式库并显式包含所有的库。不幸的是每个系统都以自己的方式这样做。
wgmfuz8q4#
链接通常是这样进行的:命令行被迭代,每个给定参数都是
1.如果它是目标文件则直接使用,
1.在所需范围内使用(=满足迄今为止未解决的所有引用)。
最后,为了成功链接,必须完成每个引用。链接器命令行中给出的行的顺序很重要。