so编译 链接和加载


出处:http://duanple.blog.163.com/blog/static/7097176720111141085197/
链接器和加载器原理>>,不过此次会更细致深入地了解下整个编译链接和加载过程,并结合经常碰到的问题,提出一些解决方案。

链接过程中库的顺序

Q: 有几个库文件A.a、B.a、common.a,前两者用到了定义在后者中的例程,如果把   common.a放在前面,链接器报告存在无法解析的符号名,放在最后则无问题。
A: Floyd Davidson 
链接器按照命令行上指定顺序搜索库文件和目标文件(.a .o),二者之间的区别在   于.o文件被全部链接进来,而只从库文件中析取所需模块,仅当某个模块可以解析当前尚未成功解析的符号时,该模块被析取后链接进来。如果库文件无法解析任何当前尚未成功解析的符号,不从中析取也不发生链接。

Unix编程新手的常见问题是数学函数并不在标准C库中,而是在libm.a中   

cc -lm foo.c

这里foo.c用到了数学库中的符号,但是链接器无法正确解析。当搜索到libm.a时,   来自foo.c的数学函数符号尚未出现,因此不需要析取libm.a的任何模块。接下来 foo.o链接进来,增加了一批尚未成功解析的符号,但已经没有libm.a可供使用了, 因此数学库必须在foo.o之后被搜索到。

 cc foo.c –lm

在你的问题中,如果common.a首先被搜索到,因为不匹配尚未成功解析的符号,而被丢弃。结果A.a和B.a真正链接进来的时候,已经没有库可以解析符号了。

http://prefetch.net/articles/linkers.badldlibrary.html
* Why LD_LIBRARY_PATH is bad – http://xahlee.org/UnixResource_dir/_/ldpath.html
* LD_LIBRARY_PATH – just say no – http://blogs.sun.com/rie/date/20040710

综上,动态链接器会按照如下顺序加载或查找共享库:

l  链接时由-rpath选项指定的目录(已被硬编码到可执行文件中)

l  LD_LIBRARY_PATH指定的目录

l  路径缓存文件/etc/ld.so.cache指定的路径

l  默认共享库目录,先/usr/lib,后/lib

LD_PRELOAD,可以预先装载一些共享库。由LD_PRELOAD指定的文件,会在动态链接库按指定规则搜索共享库之前加载。比LD_LIBRARY_PATH指定的还要优先,同时无论程序是否依赖于它,LD_PRELOAD指定的共享库都会被装载。由于全局符号介入这一机制,LD_PRELOAD指定的库的符号会覆盖后面加载的库的同名符号。这就使得我们可以修改标准c库的某些或某几个函数,而不影响其他使用。比如我们可以在实验程序执行时通过设置LD_PRELOAD,来让系统优先加载我们修改后的库。

库冲突 技巧:多共享动态库中同名对象重复析构问题的解决方法。

GCC编译的背后( 预处理和编译 汇编和链接 )

An Introduction to GCC 学习笔记

LINUX下如何用GCC编译动态库

gcc生成静态库和动态库

GCC编译优化指南

深入理解软件包的配置、编译与安装

http://www.gentoo.org/proj/en/base/amd64/howtos/fpic.xml

Wikipedia article about position-independent code:

"In computing, position-independent code (PIC) or position-independent executable (PIE) is object code that can execute at different locations in memory. PIC is commonly used for shared libraries, so that the same library code can be mapped to a location in each application (using the virtual memory system) where it won’t overlap the application or other shared libraries. PIC was also used on older computer systems lacking an MMU, so that the operating system could keep applications away from each other.
Position-independent code can be copied to any memory location without modification and executed, unlike relocatable code, which requires special processing by a link editor or program loader to make it suitable for execution at a given location. Code must generally be written or compiled in a special fashion in order to be position independent. Instructions that refer to specific memory addresses, such as absolute branches, must be replaced with equivalent program counter relative instructions. The extra indirection may cause PIC code to be less efficient, although modern processors are designed to ameliorate this."
—Wikipedia Encyclopaedia

On certain architectures (AMD64 amongst them), shared libraries must be "PIC-enabled".

1.  What are "relocations"?

Again, from Wikipedia:

"In computer science, relocation refers to the process of replacing symbolic references or names of libraries with actual usable addresses in memory before running a program. It is typically done by the linker during compilation, although it can be done at run-time by a loader. Compilers or assemblers typically generate the executable with zero as the lower-most, starting address. Before the execution of object code, these addresses should be adjusted so that they denote the correct runtime addresses."
—Wikipedia Encyclopaedia

With these terms defined, we can finally have a look at the different scenarios where breakage occurs:

1.  Case 1: Broken compiler

At least GCC 3.4 is known to have a broken implementation of the -fvisibility-inlines-hidden flag. The use of this flag is therefore highly discouraged, reported bugs are usually marked as RESOLVED INVALID. See bug 108872 for an example of a typical error message caused by this flag.

1.  Case 2: Broken `-fPIC’ support checks in configure

Many configure tools check whether the compiler supports the -fPIC flag or not. They do so by compiling a minimalistic program with the -fPIC flag and checking stderr. If the compiler prints *any* warnings, it is assumed that the -fPIC flag is not supported by the compiler and is therefore abandoned. Unfortunately, if the user specifies a non-existing flag (i.e. C++-only flags in CFLAGS or flags introduced by newer versions of GCC but unknown to older ones), GCC prints a warning too, resulting in borkage.

To prevent this kind of breakage, the AMD64 profiles use a bashrc that filters out invalid flags in C[XX]FLAGS.

See bug bug 122208 for an example.

1.  Case 3: Lack of `-fPIC’ flag in the software to be built

This is the most common case. It is a real bug in the build system and should be fixed in the ebuild, preferably with a patch that is sent upstream. Assuming the error message looks like this:

Code Listing 1.1: A sample error message

.libs/assert.o: relocation R_X86_64_32 against `a local symbol’ can not be usedwhen making a shared object; recompile with -fPIC .libs/assert.o: could notread symbols: Bad value

This means that the file assert.o was not compiled with the -fPIC flag, which it should. When you fix this kind of error, make sure only objects that are used in shared libraries are compiled with -fPIC.

In this case, globally adding -fPIC to C[XX]FLAGS resolves the issue, although this practice is discouraged because the executables end up being PIC-enabled, too.

Note: Adding the -fPIC flag to the linking command or LDFLAGS won’t help.

1.  Case 4: Linking dynamically against static archives

Sometimes a package tries to build shared libraries using statically built archives which are not PIC-enabled. There are two main reasons why this happens:

Often it is the result of mixing USE=static and USE=-static. If a library package can be built statically by setting USE=static, it usually doesn’t create a .so file but only a .a archive. However, when GCC is given the -l flag to link to said (dynamic or static) library, it falls back to the static archive when it can’t find a shared lib. In this case, the preferred solution is to build the static library using the -fPIC flag too.

Warning: Only build the static archive with -fPIC on AMD64. On other architectures this is unneeded and will have a performance impact at execution time.

See bug 88360 and mysql bug 8796 for an example.

Sometimes it is also the case that a library isn’t intended to be a shared library at all, e.g. because it makes heavy usage of global variables. In this case the solution is to turn the to-be-built shared library into a static one.

See bug 131460 for an example.

Code Listing 1.1: A sample error message

gcc   -fPIC -DSHARED_OBJECT -c lex.yy.cgcc  -shared -o html2txt.so lex.yy.o -lflusr/lib/gcc/x86_64-pc-linux-gnu/4.1.1/../../../../x86_64-pc-linux-gnu/bin/ld:/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.1/../../../../lib64/libfl.a(libyywrap.o):relocation R_X86_64_32 against `a local symbol’ can not be used when making ashared object; recompile with -fPIC/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.1/../../../../lib64/libfl.a: could notread symbols: Bad value

相关