码迷,mamicode.com
首页 > 其他好文 > 详细

busybox静态编译及动态编译实践

时间:2015-08-28 19:48:40      阅读:1163      评论:0      收藏:0      [点我收藏+]

标签:linux工具   busybox   动态编译   静态编译   

1. 简介

  BusyBox 是一个集成了一百多个最常用linux命令和工具的软件。BusyBox 包含了一些简单的工具,例如ls、cat和echo等等,还包含了一些更大、更复杂的工具,例grep、find、mount以及telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。

  简单的说BusyBox就好像是个大工具箱,它集成压缩了Linux的许多工具和命令。除此之外,提供了良好的编程框架,用户能够将自己的命令集成到busybox当中。在实际的使用过程中,busybox常常被用于制作linux的根文件系统。


2. 静态编译

下载busybox源码,进行配置编译

    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

  修改配置,使用静态编译,如果不使用静态编译,程序运行期间需要进行动态加载,则需在根文件系统中提供其所需的共享库。

Location:                                                           
-> Busybox Settings                                        
   -> Build Options     
      [*] Build BusyBox as a static binary (no shared libs)         

使用make进行编译,对于一些机器,可能会报如下的错误:

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选项即可忽略该问题

    Location:                 
    -> Networking Utilities 
       [ ] inetd  

  这时再执行make,就能生成busybox,执行make install生成_install目录,该目录中生成了常用的linux命令,这些命令均是符号链接到busybox上的。


3. 动态编译

  网上大部分人都讲述的如何静态编译,而少部分人的讲述并未考虑到不同平台带来的问题,而我使用的平台为x86_64架构上,作为第一次探索动态编译,在这个过程当中遇到不少困难,希望下面的过程,能够对你有用。

接下来,我们会使用到以下几个命令:

  • readelf:用来读ELF文件相关信息的命令
  • ldd :用来打印共享链接库信息的命令

先来看看这两条命令有什么神奇之处:

#include <stdio.h>
#include <stdlib.h>
int main(){
        printf("Hello World\n");
        return 0;
}

gcc   hello.c   -o   hello

readelf  -d   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   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   -u   hello

 Unused direct dependencies:
    linux-vdso.so.1

使用strace  ./hello 来跟踪下hello的执行:

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显示的动态链接库地址,当运行在不同机器上时,在相关路径下,需存有所需的链接库。

/lib/x86_64-linux-gnu/libc.so.6 
/lib64/ld-linux-x86-64.so.2 

这一步,主要用于在制作根文件系统时,当运行在嵌入式设备上时,需要提供所需要的链接库。


参考资料

版权声明:本文为博主原创文章,未经博主允许不得转载。

busybox静态编译及动态编译实践

标签:linux工具   busybox   动态编译   静态编译   

原文地址:http://blog.csdn.net/sunliymonkey/article/details/48056273

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!