本文不考虑静态链接方式,很多库在静态链接的时候会有问题,比如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这个命令检查一下。对于自己有源代码的程序,可以重新编译,加上–dynamic-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  –library-path ../lib:/home/changming/apps/lib64  ./uconv  –list”
All Things Works Fine!
原文链接: http://www.udpwork.com/redirect/6855
 

转载于:https://blog.51cto.com/mickelfeng/938881

让C/C++程序一次编译,到处运行 (仅限Linux)相关推荐

  1. 【openwrt】如何编译和运行一个arm linux 内核

    如何编译和运行一个arm linux 内核 1. 准备工具 linux4.0 内核 busybox工具包 2. busybox手工编译一个最小的文件系统 cd busybox export ARCH= ...

  2. Ubuntu14.04下C++程序编辑、编译、运行入门篇

    初次接触Ubuntu,一脑子的糊涂,更别提如何在Ubuntu下编译运行C++程序了,经过查资料,下面是自己在Ubuntu下写的第一个C++程序,仅供初学者参考,也为自己的入门学习梳理下思路. 一.编译 ...

  3. Ubuntu14.04下C++程序编辑、编译、运行

    1.输入组合键"Ctrl+Alt+t"调出终端: 安装vim:输入 sudo apt-get install vim: 安装gcc:输入 sudo apt-get install ...

  4. [转]移动应用统一化的谎言:一次编译,到处运行不可能

    Wholesale Applications Community (大规模应用程序联盟) (WAC) 上星期说明年二月会发布一个平台,能够允许开发者去写一个程序并且运行在多个操作系统上以及在多个销售平 ...

  5. Java一次编译,到处运行是如何实现的

    Java一次编译,到处运行是如何实现的 转自:https://cloud.tencent.com/developer/article/1415194 (排版微调) JAVA编译运行总览 Java是一种 ...

  6. 如何编译和运行C++程序

    如何编译和运行C++程序 C++ 和C语言类似,也要经过编译和链接后才能运行.我们在C语言课程的时候,讲了如何使用 VS.VC 6.0.VC++2010等常见开发工具,它们除了可以运行C语言程序,也可 ...

  7. c语言程序既可以编译执行也可以解释执行,2016年山东农业大学信息科学与工程学院C语言程序设计(同等学力加试)复试笔试仿真模拟题...

    一.选择题 1. 计算机高级语言程序的运行方法有编译执行和解释执行两种,以下叙述中正确的是 ( ). A.C 语言程序仅可以编译执行 B.C 语言程序仅可以解释执行 C.C 语言程序既可以编译执行,又 ...

  8. 如何在Windows下使用Linux系统来编译和运行程序?

    很多开发人员都有这样的疑问:自己平时是在Windows下面办公的,而自己编写的程序的运行环境又是Linux的,如何从Windows切换到Linux呢?是不是要专门到Linux机器上去编写代码呢? 实际 ...

  9. java 程序编译和运行的过程

    Java整个编译以及运行的过程相当繁琐,本文通过一个简单的程序来简单的说明整个流程. 如下图,Java程序从源文件创建到程序运行要经过两大步骤:1.源文件由编译器编译成字节码(ByteCode)  2 ...

最新文章

  1. 学习OpenCV(一)从Mat讲起
  2. c语言 amp 位与 什么意思,C语言中amp;是什么意思?--龙方网络
  3. 云OS:Linux在桌面打翻身仗的机会?
  4. .1 matlab,1 MATLAB集成环境
  5. hdu 1300(dp)
  6. AOP的底层实现-CGLIB动态代理和JDK动态代理
  7. springcloud中config和bus的使用
  8. 先出报表还是先计提所得税_合并报表投资时点的评估增值和内部交易到底该如何理解????...
  9. 必要时进行保护性拷贝
  10. 命令模式(3)-宏命令
  11. 什么是管理大数据技术
  12. 32位单片机应用场合_全球首款基于 RISC-V 的 32 位通用单片机出现
  13. Linux之Samba部署
  14. 用mysql搭建蚂蚁笔记_利用蚂蚁笔记搭建个人云笔记/博客
  15. 手机浏览器打开百度网页
  16. 【学习笔记】移动无线信道理论
  17. 51单片机八段数码c语言程序,51单片机做的音乐盒,带八段数码管显示程序+Proteus仿真...
  18. 找不到移动硬盘解决办法
  19. table-responsive响应式表格,手机端表格自适应
  20. 关于UI测试的相关及技巧

热门文章

  1. linux无锁化编程--__sync_fetch_and_add系列原子操作函数
  2. React 2019年路线图发布!Hooks明年一季度上线
  3. 图解 wp WordPress 文章 链接 在新窗口打开
  4. 理解并取证:DHCP的工作原理、怎么检测IP地址冲突
  5. [转] GMT、UTC与24时区 等时间概念
  6. Oracle 11g下加密表空间的使用
  7. Ios中checkBox
  8. Android 获取系统或SDCARD剩余空间信息
  9. 基于单个xml的数据库
  10. Saas 平台,多域名,泛域名.如何做分站点的统计之解决方案