首页 > 代码库 > crti.o: could not read symbols: Bad value
crti.o: could not read symbols: Bad value
Sometimes it occurs that gcc bails out with an error message like the following:
.libs/assert.o: relocation R_X86_64_32 against `a local symbol‘ can not be used
when making a shared object; recompile with -fPIC .libs/assert.o: could not
read symbols: Bad value
There are several different types of causes for such an error. This HOWTO will explain all of them and show how to fix them.
1. What is PIC?
PIC is an abbreviation for Position-Independent Code. The following is an excerpt of the 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 withoutmodification and executed, unlike relocatable code, which requires specialprocessing by a link editor or program loader to make it suitable for executionat a given location. Code must generally be written or compiled in a specialfashion in order to be position independent. Instructions that refer tospecific memory addresses, such as absolute branches, must be replaced withequivalent program counter relative instructions. The extra indirection maycause PIC code to be less efficient, although modern processors are designed toameliorate this."
—Wikipedia Encyclopaedia
On certainarchitectures (AMD64 amongst them), shared libraries must be"PIC-enabled".
2. What are"relocations"?
Again, fromWikipedia:
"In computerscience, relocation refers to the process of replacing symbolic references ornames of libraries with actual usable addresses in memory before running aprogram. It is typically done by the linker during compilation, although it canbe done at run-time by a loader. Compilers or assemblers typically generate theexecutable with zero as the lower-most, starting address. Before the executionof object code, these addresses should be adjusted so that they denote thecorrect runtime addresses."
—Wikipedia Encyclopaedia
With these termsdefined, we can finally have a look at the different scenarios where breakageoccurs:
Case 1: Brokencompiler
At least GCC 3.4 isknown to have a broken implementation of the -fvisibility-inlines-hidden flag.The use of this flag is therefore highly discouraged, reported bugs are usuallymarked as RESOLVED INVALID. See bug 108872 foran example of a typical error message caused by this flag.
Case 2: Broken`-fPIC‘ support checks in configure
Many configure toolscheck whether the compiler supports the -fPIC flag or not. They do so by compilinga minimalistic program with the -fPIC flag and checking stderr. If the compilerprints *any* warnings, it is assumed that the -fPIC flag is not supported bythe compiler and is therefore abandoned. Unfortunately, if the user specifies anon-existing flag (i.e. C++-only flags in CFLAGS or flags introduced by newerversions of GCC but unknown to older ones), GCC prints a warning too, resultingin borkage.
To prevent this kindof breakage, the AMD64 profiles use a bashrc that filters out invalid flags inC[XX]FLAGS.
See bug bug 122208 for an example.
Case 3: Lack of`-fPIC‘ flag in the software to be built
This is the mostcommon case. It is a real bug in the build system and should be fixed in theebuild, preferably with a patch that is sent upstream. Assuming the errormessage looks like this:
.libs/assert.o: relocation R_X86_64_32 against `a localsymbol‘ can not be used
when making a shared object; recompile with -fPIC.libs/assert.o: could not
read symbols: Bad value
This means that thefile assert.o was not compiled with the -fPIC flag, which it should. When youfix this kind of error, make sure only objects that are used in sharedlibraries are compiled with -fPIC.
In this case,globally adding -fPIC to C[XX]FLAGS resolves the issue, although this practiceis discouraged because the executables end up being PIC-enabled, too.
Note: Adding the-fPIC flag to the linking command or LDFLAGS won‘t help.
Case 4: Linkingdynamically against static archives
Sometimes a packagetries to build shared libraries using statically built archives which are notPIC-enabled. There are two main reasons why this happens:
Often it is theresult of mixing USE=static and USE=-static. If a library package can be builtstatically by setting USE=static, it usually doesn‘t create a .so file but onlya .a archive. However, when GCC is given the -l flag to link to said (dynamicor static) library, it falls back to the static archive when it can‘t find ashared lib. In this case, the preferred solution is to build the static libraryusing the -fPIC flag too.
Warning: Only buildthe static archive with -fPIC on AMD64. On other architectures this is unneededand will have a performance impact at execution time.
See bug 88360 and mysql bug 8796 for anexample.
Sometimes it is alsothe 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 isto turn the to-be-built shared library into a static one.
See bug 131460 foran example.
gcc -fPIC -DSHARED_OBJECT -c lex.yy.c
gcc -shared -o html2txt.so lex.yy.o -lfl
usr/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 notbe used when making a
shared object; recompile with -fPIC
/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.1/../../../../lib64/libfl.a:could not
read symbols: Bad value
在公司搭建Dopra编译器环境时遇到上面错误,最后定位到编译器自带的crti.o没有使用-fPIC选项编译,而在编译共享库时,我的Makefile里面使用了-shared和-fPIC选项,导致ld链接crti.o时不识别并报bad value错误。
下面是关于glibc运行时库crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o的介绍,可以帮助我们理解ld错误发生的时刻:
crt1.o,crti.o, crtbegin.o, crtend.o, crtn.o是glibc的几个辅助运行时库,其与我们自己的.o文件一起链接成一个可执行文件。其中crt1.o中包含程序的入口函数_start以及两个未定义的符号__libc_start_main和main,由_start负责调用__libc_start_main初始化libc,然后调用我们源代码中定义的main函数;另外,由于类似于全局静态对象这样的代码需要在main函数之前执行,crti.o和crtn.o负责辅助启动这些代码。另外,gcc中同样也有crtbegin.o和crtend.o两个文件,这两个目标文件用于配合glibc来实现C++的全局构造和析构。
在标准linux平台下,link的顺序是:ld crt1.o crti.o [user_objects][system_libraries] crtn.o,其中user_objects时用户源码编译的.o文件,system_libraries是系统的库文件。上面错误即ld在链接crti.o时,解析符号报错。
crti.o: could not read symbols: Bad value