本文不考虑静态链接方式,很多库在静态链接的时候会有问题,比如
libunwind
,它的异常处理
API
会和
gcc
原有的冲突。还有一个显著的问题就是
nss
。它根据配置文件
/etc/nsswitch.conf
来动态决定加载哪个
so
,然后用这个
so
执行名称解析服务等等。(
nss
是
glibc
的一部分,是系统很基本的东西)。还有,
jni
的
so
,想要静态链接很难。意思就是说,我要编译一个
so
,但是这个
so
所依赖的其它库又都必须是静态链接的,很难,而且也许会引入很多
BUG
。出于种种原因,我完全放弃了静态链接。(程序采用静态链接完美世界的传统)
即便你的程序简单到只是一个
hello world,
那么也需要链接到
libc.so
。很明显,不同的
glibc
版本之间,差别很大,经常不兼容。那么我能不能在低版本的
Linux
上使用高版本的
Linux
的
libc.so
呢?
于是我做了一个测试,我这边主要有两种
Linux
系统:
CentOS 5
和
CentOS 6
。
CentOS 5
下
ld-linux-x86-64.so.2
指向的是
ld-2.5.so
CentOS 6
下
ld-linux-x86-64.so.2
指向的是
ld-2.12.so
如果强行把
CentOS 5
的这个
so
替换成
CentOS6
的那个,那么会发现任何
elf
都执行不了,
relocation error: /lib64/libc.so.6: symbol _dl_tls_get_addr_soft, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2
系统基本是僵死状态。(还好我今天用
/lib64/ld-2.5.so ln -s -f ld-2.5.so ld-linux-x86-64.so.2
的方式救回来了)
如果我们不替换
ld.so,
而只是替换
libc.so
,例如
:
LD_LIBRARY_PATH=/home/changming/apps/lib64 ls (/home/changming/apps/lib64
放的是
CentOS6
的
libc.so
)
那么会报告:
error while loading shared libraries: /home/changming/apps/lib64/libc.so.6: ELF file OS ABI invalid
用
file
查看一下:
CentOS 6
的
libc.so.6: ELF 64-bit LSB shared object, AMD x86-64, version 1 (GNU/Linux), for GNU/Linux 2.6.18, not stripped
CentOS 6
的
libc.so.6: ELF 64-bit LSB shared object, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, not stripped
CentOS 6
的
libstdc++.so.6: ELF 64-bit LSB shared object, AMD x86-64, version 1 (SYSV), stripped
这个差别在于
elftype
。
于是我从
FreeBSD 9
下面,把
brandelf.c
复制到
Linux
,稍作修改后编译。然后用它更改
elftype
。
./brandelf -t SVR4 /home/changming/apps/lib64/libc.so.6 apps/lib64/libm.so.6
然后在
CentOS 5
下面用
CentOS 6
的
ld.so
执行
CentOS 6
的
bash
LD_LIBRARY_PATH=/home/changming/apps/lib64 /home/changming/apps/lib64/ld-linux-x86-64.so.2 ./bash
error while loading shared libraries: /home/changming/apps/lib64/libc.so.6: unexpected reloc type 0×25
这个问题在于,
bash
会
fork
新进程,而新进程采用哪个
ld.so
,是我无法控制的。
综上所述:用老的
ld.so
配合新的
libc.so
,只有两种结果:
"ELF file OS ABI invalid”
或
“unexpected reloc type 0×25”
。
结论:
ld.so
的版本必须和
glibc
的版本匹配。
但是,大多数情况下,这不是一个问题。因为大部分程序(我写的)是不会
fork
的。
我想说一个什么事情呢?
我想说,
Linux
的这套动态链接库命名机制(
soname
、
linker name
、
realname
)并未能解决
DLL hell
的问题。参见:
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
我现在写好一个程序,当把它扔到别的系统上运行时,它对
OS
的依赖应当越小越好,否则难道我为每个发行版的每个主版本都编译一次?虽然大部分开源项目都是这么做的,但是我实在是不想。我希望只编译一次,并且编译时所采用的
so
和运行时采用的
so
是完全一样的!综上所述,如果不
fork
,那么
you can
!
如果我就是非要
fork
,那么怎么办呢?
答:对于无源代码的程序,改
ELF
文件的
Program Headers
。将
PT_INTERP
的值设置为我自己的
ld.so
。(原来的默认值是
/lib64/ld-linux-x86-64.so.2
)。改完之后可以用
readelf
这个命令检查一下。对于自己有源代码的程序,可以重新编译,加上
�Cdynamic-linker ./ld-linux-x86-64.so.2
这样的参数。注意,对于
setuid
程序,这里一定要写绝对路径,否则就是一个安全漏洞哇。
在解决这些问题之后,只要我的程序没有用到
Linux Kernel
的新特性,那么就可以在相当大范围内的
Linux
上,自由执行了。
show
几个脚本:
打包
so
,并扔到
http server
上:
#!/bin/bash
rm -rf /tmp/lib64tar
mkdir /tmp/lib64tar
cp /lib64/ld-linux-x86-64.so.2 /tmp/lib64tar
cp /lib64/libc.so.6 /tmp/lib64tar
cp /lib64/libdl.so.2 /tmp/lib64tar
cp /lib64/libgcc_s.so.1 /tmp/lib64tar
cp /lib64/libm.so.6 /tmp/lib64tar
cp /lib64/libpthread.so.0 /tmp/lib64tar
cp /usr/lib64/libstdc++.so.6 /tmp/lib64tar
tar -zcvf /tmp/lib64tar.tar.gz -C /tmp/ lib64tar
scp /tmp/lib64tar.tar.gz 10.4.1.27:/home/changming/public_html/glu/
自动安装脚本
(
glu script
):
class LinuxLib64{
def install = {
log.info "Installing…"
def skeleton = shell.fetch(params.linuxlib64url)
def distribution = shell.untar(skeleton)
shell.rmdirs(mountPoint)
shell.mv(shell.ls(distribution)[0], mountPoint)
shell.toResource(mountPoint.path).list().each{ f ->
log.info f.path
shell.chmodPlusX(f)
}
log.info "Install complete."
}
def createChild = { args ->
return args.script
}
}
glu static model:
{
"agent": "10.4.1.14",
"mountPoint": "/lib64",
"initParameters": {
"linuxlib64url": "http://10.4.1.27/~changming/glu/lib64tar.tar.gz",
},
"entryState": "installed",
"parent": "/",
"metadata": {},
"tags": [],
"script": "http://10.4.1.27/~changming/glu/linuxlib64.groovy"
}
今天试了一下,从
icu
的网站下载为
RHEL6
编译的二进制包(一个
tar
包),然后在
CentOS 5
上解压到任意目录,这么执行:
“ /home/changming/apps/lib64/ld-linux-x86-64.so.2 �Clibrary-path ../lib:/home/changming/apps/lib64 ./uconv �Clist”
All Things Works Fine
!
原文链接
: http://www.udpwork.com/redirect/6855