大概可以按照以下步驟進行:
1. 分析那些函數用的是10.04下沒有的glibc的版本
通常12.04下編譯的程序在10.04下運行報glibc2.14沒找到的錯誤,這裏就要找出那個函數用了2.14版本。以應用程序guard爲例
objdump -T guard | grep 2.14
得知時memcpy(),通過網絡查詢得知,memcpy()史上曾經有個較大變動,很不幸,就發生在libc2.14和libc2.2.5(10.04的glibc缺省版本)之間
2. 想辦法讓memcpy靜態鏈接
首先從/usr/lib/x86_64-linux-gnu/libc.a將libc.a拷貝出來,放到一個目錄dir下,
然後抽取出memcpy.o/cacheinfo.o/init-arch.o
ar x memcpy.o libc.a
需要cacheinfo.o是由於memcpy.o對其有依賴,同樣cacheinfo.o對init-arch.o有依賴
3. 迫使編譯工具靜態鏈接上述挑選的obj文件
在需要鏈接的目錄的YBUILD裏頭加入如下鏈接控制項
link_flags = ['-Wl,--start-group /private/svn/memcpy.o /private/svn/cacheinfo.o \
/private/svn/init-arch.o --end-group',
],
注意:這裏得用start-group和end-group的原因見後面的說明#3
這個是對要編譯的單個程序起作用,如果希望所有的程序都這樣,那就需要修改scons下面的devel/ymake/site_scons/Cpp.py
在任何一個有link_flags的地方,加入上述選項
link_flags +=('-Wl, -start-group /private/svn/memcpy.o /private/svn/cacheinfo.o \
/private/svn/init-arch.o --end-group')
重新編譯就可以了
4. 如何驗證memcpy確實時靜態鏈接的,我們拿memcpy和memmove做一個對比
objdump -R guard | grep memcpy
00000000009d7bf8 R_X86_64_JUMP_SLOT __memcpy_chk
objdump -R guard | grep memmove
00000000009d7588 R_X86_64_JUMP_SLOT __memmove_chk
00000000009d7b88 R_X86_64_JUMP_SLOT memmove
objdump -t guard | grep memcpy
000000000069afc4 g F .text 0000000000000031 _ZN4base9c16memcpyEPtPKtm
0000000000441950 g F .text 0000000000000465 memcpy
0000000000000000 F *UND* 0000000000000000 __memcpy_chk@@GLIBC_2.3.4
objdump -t guard | grep memmove
0000000000000000 F *UND* 0000000000000000 __memmove_chk@@GLIBC_2.3.4
000000000069af93 g F .text 0000000000000031 _ZN4base10c16memmoveEPtPKtm
0000000000000000 F *UND* 0000000000000000 memmove@@GLIBC_2.2.5 ===============>未定義
說明:
1. 還有另外一種辦法是把memcpy wrap起來,然後自己實現memcpy(),在鏈接的時候也需要--wrap memcpy選項,加選項的辦法同上面的一樣
2. 如果還有其他版本不匹配的函數,則可以簡單地把gcc降級爲4.4(12.04缺省是4.6),先安裝gcc4.4,然後修改符號鏈接文件gcc指向gcc4.4
ls -al /usr/bin/gcc
lrwxrwxrwx 1 root root 7 Dec 28 13:18 /usr/bin/gcc -> gcc-4.4
3. 鏈接選項使用start-group和end-group的原因
-(
archives -)
or --start-group
archives --end-group
The archives should be a list of archive files. They may be either explicit file names, or -l options.
The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched only once in the order that it is specified on the command line. If a symbol in that archive is needed to resolve an undefined symbol referred to by an object in an archive that appears later on the command line, the linker would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all possible references are resolved.
Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular references between two or more archives.
4. 如果你用的32bit的ubuntu12.04,恭喜你,你可能沒這個煩惱
/lib32$ readelf -s libc.so.6 | grep 2.14 =============》32bit的libc.so裏頭memcpy的版本不是2.14,而是2.0的
80: 000ef480 61 FUNC GLOBAL DEFAULT 12 clock_adjtime@@GLIBC_2.14
469: 0002f140 91 FUNC GLOBAL DEFAULT 12 sigorset@@GLIBC_2.0
551: 000efe50 75 FUNC GLOBAL DEFAULT 12 name_to_handle_at@@GLIBC_2.14
1042: 000eff20 61 FUNC GLOBAL DEFAULT 12 setns@@GLIBC_2.14
1056: 000efea0 122 FUNC GLOBAL DEFAULT 12 open_by_handle_at@@GLIBC_2.14
1177: 000f0bc0 192 FUNC GLOBAL DEFAULT 12 sendmmsg@@GLIBC_2.14
1184: 00000000 0 OBJECT GLOBAL DEFAULT ABS GLIBC_2.14
1415: 000e8170 57 FUNC GLOBAL DEFAULT 12 syncfs@@GLIBC_2.14
2014: 0014ae80 128 FUNC GLOBAL DEFAULT 13 __libc_freeres@@GLIBC_2.1
2114: 000f2710 19 FUNC WEAK DEFAULT 12 mcount@@GLIBC_2.0
2214: 00034400 69 FUNC GLOBAL DEFAULT 12 __strtoull_internal@@GLIBC_2.0
2314: 0007d110 120 FUNC GLOBAL DEFAULT 12 _obstack_free@@GLIBC_2.0
readelf -s libc.so.6 | grep memcpy
352: 00098290 51 FUNC WEAK DEFAULT 12 wmemcpy@@GLIBC_2.0
357: 00082da0 70 FUNC GLOBAL DEFAULT 12 __memcpy_by2@@GLIBC_2.1.1
363: 00082d60 51 FUNC GLOBAL DEFAULT 12 __memcpy_by4@@GLIBC_2.1.1
851: 00083da0 48 FUNC GLOBAL DEFAULT 12 __memcpy_c@@GLIBC_2.1.1
868: 00082df0 59 FUNC GLOBAL DEFAULT 12 __memcpy_g@@GLIBC_2.1.1
1069: 00104760 62 FUNC GLOBAL DEFAULT 12 __wmemcpy_chk@@GLIBC_2.4
1193: 0007f530 70 IFUNC GLOBAL DEFAULT 12 memcpy@@GLIBC_2.0
1722: 00101560 70 IFUNC GLOBAL DEFAULT 12 __memcpy_chk@@GLIBC_2.3.4
而64bit就不一樣,用的時2.14的
/lib/x86_64-linux-gnu$ readelf -s libc.so.6 | grep 2.14
70: 0000000000182b14 4 OBJECT GLOBAL DEFAULT 15 _sys_nerr@@GLIBC_2.12
74: 00000000000f4200 37 FUNC GLOBAL DEFAULT 12 clock_adjtime@@GLIBC_2.14
515: 00000000000f4900 40 FUNC GLOBAL DEFAULT 12 name_to_handle_at@@GLIBC_2.14
967: 00000000000f4990 37 FUNC GLOBAL DEFAULT 12 setns@@GLIBC_2.14
981: 00000000000f4930 94 FUNC GLOBAL DEFAULT 12 open_by_handle_at@@GLIBC_2.14
1094: 00000000000f5b10 157 FUNC GLOBAL DEFAULT 12 sendmmsg@@GLIBC_2.14
1100: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS GLIBC_2.14
1107: 00000000000917e0 60 IFUNC GLOBAL DEFAULT 12 memcpy@@GLIBC_2.14
1310: 00000000000ed290 37 FUNC GLOBAL DEFAULT 12 syncfs@@GLIBC_2.14
1944: 0000000000182b14 4 OBJECT GLOBAL DEFAULT 15 sys_nerr@@GLIBC_2.12
2014: 00000000000bb3f0 70 FUNC GLOBAL DEFAULT 12 ntp_gettime@@GLIBC_2.2.5
2114: 00000000000e70a0 37 FUNC GLOBAL DEFAULT 12 __pipe@@GLIBC_2.2.5
/lib/x86_64-linux-gnu$ readelf -s libc.so.6 | grep memcpy
329: 00000000000a1530 9 FUNC WEAK DEFAULT 12 wmemcpy@@GLIBC_2.2.5
993: 000000000010ba20 27 FUNC GLOBAL DEFAULT 12 __wmemcpy_chk@@GLIBC_2.4
1107: 00000000000917e0 60 IFUNC GLOBAL DEFAULT 12 memcpy@@GLIBC_2.14
1109: 000000000008bbc0 71 IFUNC GLOBAL DEFAULT 12 memcpy@GLIBC_2.2.5
1599: 0000000000108190 60 IFUNC GLOBAL DEFAULT 12 __memcpy_chk@@GLIBC_2.3.4
5. 嘗試過其他方法,但都繞不過memcpy使用2.14版本的問題
比如鏈接選項加入“-static-libstd++“或者”-static-libgcc','-static'是想所有的都靜態鏈接,但最終鏈接報錯。