busybox静态编译及动态编译实践
2015-08-28 18:41
344 查看
1. 简介
BusyBoxBusyBox 是一个集成了一百多个最常用linux命令和工具的软件。BusyBox 包含了一些简单的工具,例如ls、cat和echo等等,还包含了一些更大、更复杂的工具,例grep、find、mount以及telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。简单的说BusyBox就好像是个大工具箱,它集成压缩了Linux的许多工具和命令。除此之外,提供了良好的编程框架,用户能够将自己的命令集成到busybox当中。在实际的使用过程中,busybox常常被用于***linux的根文件系统。
2. 静态编译
下载busybox源码,进行配置编译[code] curl http://busybox.net/downloads/busybox-1.23.2.tar.bz2 | tar xjf - mkdir -p obj/busybox cd busybox-1.23.2 make O=../obj/busybox defconfig #独立在新文件中进行相关配置 cd ../obj/busybox make menuconfig
修改配置,使用静态编译,如果不使用静态编译,程序运行期间需要进行动态加载,则需在根文件系统中提供其所需的共享库。
[code]Location: -> Busybox Settings -> Build Options [*] Build BusyBox as a static binary (no shared libs)
使用
make进行编译,对于一些机器,可能会报如下的错误:
[code]networking/lib.a(inetd.o): In function `unregister_rpc': inetd.c:(.text.unregister_rpc+0x17): undefined reference to `pmap_unset' networking/lib.a(inetd.o): In function `register_rpc': inetd.c:(.text.register_rpc+0x56): undefined reference to `pmap_unset' inetd.c:(.text.register_rpc+0x72): undefined reference to `pmap_set' networking/lib.a(inetd.o): In function `prepare_socket_fd': inetd.c:(.text.prepare_socket_fd+0x7f): undefined reference to `bindresvport' collect2: ld returned 1 exit status make[2]: *** [busybox_unstripped] Error 1 make[1]: *** [_all] Error 2 make: *** [all] Error 2
观察上面的错误,可以发现问题出在
inetd.c中有未定义的引用,在网上搜索一下答案,关闭配置当中的
inet选项即可忽略该问题
[code] Location: -> Networking Utilities [ ] inetd
这时再执行
make,就能生成
busybox,执行
make install生成
_install目录,该目录中生成了常用的linux命令,这些命令均是符号链接到busybox上的。
3. 动态编译
网上大部分人都讲述的如何静态编译,而少部分人的讲述并未考虑到不同平台带来的问题,而我使用的平台为x86_64架构上,作为第一次探索动态编译,在这个过程当中遇到不少困难,希望下面的过程,能够对你有用。接下来,我们会使用到以下几个命令:
readelfreadelf:用来读ELF文件相关信息的命令
lddldd :用来打印共享链接库信息的命令
先来看看这两条命令有什么神奇之处:
[code]#include <stdio.h> #include <stdlib.h> int main(){ printf("Hello World\n"); return 0; }
gcc hello.c gcc\ \ \ hello.c\ \ \ -o helloo\ \ \ hello
readelf readelf\ \ -d hellod\ \ \ hello
Dynamic section at offset 0xe50 contains 20 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x4003c8
0x000000000000000d (FINI) 0x4005e8
… … …
相信,你已经发现
Shared library,共享库
libc.so.6正是该程序需要的动态链接库,那我们再接下来看下
ldd命令:
ldd helloldd \ \ \ hello
linux-vdso.so.1 => (0x00007ffc895e8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4a7e155000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4a7e526000)
这里的结果,更令人兴奋,因为它不仅告诉了所需的链接库,同时也交待它们的具体位置。(想当初,不晓得有这个命令,自己在
/lib目录下各种尝试,那才辛酸)
但这里的结果,想必也让你迷惑,为何这里出现了三个共享的链接库呢?对于
/lib64/ld-linux-x86-64.so.2比较好理解,这是程序动态链接所需要的链接器,那这个
linux-vdso.so.1是什么呢?
vdso: Virtual Dynamic Shared Object
虚拟动态共享库,是不是体会到什么了?来看看这段
在linux中,glibc是程序与内核之间的桥梁,如果内核增添的新的特性,带来了API的改变,这个时候如果glibc想要支持该新的特性,就需要对glibc进行升级。然而,glibc和linux不是一块开发的,同时glibc还要去兼容不同版本的linux内核,而linux内核也需要去兼容不同版本的glibc,因此这个虚拟共享库诞生,我感觉这个有点像一个虚拟框架,这个框架不会改变,glibc和linux内核彼此在这个框架下进行修改。
ldd命令的
-u参数可以用来查看未使用的动态链接库,来看看有什么样的效果呢:
ldd ldd \ \ \ -u hellou\ \ \ hello
Unused direct dependencies:
linux-vdso.so.1
使用strace ./hellostrace\ \ ./hello 来跟踪下hello的执行:
[code]execve("./hello", ["./hello"], [/* 18 vars */]) = 0 brk(0) = 0x2373000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3200d55000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=62944, ...}) = 0 mmap(NULL, 62944, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3200d45000 close(3) = 0 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
其实只发现它打开了
libc.so.6。
到了现在我们开始对busybox进行动态编译,动态编译的方法很简单,去掉之前静态编译的选项,即可。
然后根据ldd显示的动态链接库地址,当运行在不同机器上时,在相关路径下,需存有所需的链接库。
[code]/lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2
这一步,主要用于在***根文件系统时,当运行在嵌入式设备上时,需要提供所需要的链接库。
参考资料
静态库和动态库Linux内核特性之VDSO
linux下so动态库一些不为人知的秘密
相关文章推荐
- 东北地区ACM竞赛总结-2013.6.11
- 【JavaScript】js数组操作,由push到那么多
- Java网络编程(新IO概述)
- 用tomcat+apacheServer+spring搭建一个集群,实现简单的负载均衡
- CentOS用yum安装配置svn服务器步骤
- Linux中的延时函数
- 有损和无损转换分区格式
- css选择器的优先级
- [转]Web.xml配置详解之context-param
- 将ojdbc6安装到本地仓库从而打进可运行jar包
- Matlab中如何将(自定义)函数作为参数传递给另一个函数
- MySQL的 Grant命令权限分配
- 阿里云oss post上传文件 JavaScript代码示例 $.ajax()
- Git on the way
- 中断底半部&顶半部tasklet 与 workqueue
- android ListView 左滑和IOS一样的效果
- jquery 失去焦点事件 (text文本框有焦点事件)
- 去除DataTable重复数据的三种方法
- poj2983 差分约束 超级源点
- 【NOIP 2012提高】国王游戏