利用libbfd获取elf可执行文件的section(节)及symbol(符号)信息

本文介绍了如何安装libbfd库,并详细阐述了在使用libbfd库时需要注意的头文件包含和链接步骤,特别是解决缺少config.h文件的问题。通过一个简单的应用实例,展示了libbfd在解析ELF可执行文件section和symbol信息方面的应用。

一. 安装bfd库

libbfd(Binary File Descriptor library是binutils中附带的一个C库。
从 http://ftp.gnu.org/gnu/binutils 下载binutils。
我们这里下载binutils-2.23.2.tar.gz
下载后,解压安装libbfd。方法如下:
tar -xzf binutils-2.23.2.tar.gz
cd binutils-2.23.2/bfd
./configure
make
make install


安装完成后,可以看到有如下文件生成。
/usr/local/include/bfd.h
/usr/local/lib/libbfd.a


二. 使用bfd库需要注意的地方

1. 头文件包含

程序使用bfd,需要包含bfd.h头文件。

但是,在包含bfd.h之前,还需要包含config.h。

即代码中需要有如下形式的文件包含:


#include "config.h"
#include <bfd.h>

那么这个config.h是什么东东呢?他不是系统的头文件,也不是bfd库的头文件,而是应用程序自己的头文件。

然而用户可能会感到奇怪,我的应用程序源码中并不存在这个config.h文件。那是因为你开发应用时,没有采用GNU autotools。

采用GNU autotools的项目,在编译前一般都会执行一下configure脚本,生成Makefile及config.h文件。

那么,对于没有使用GNU autotools的应用,怎么解决呢?本文这里提供一个简单的config.h文件。

这个文件的内容,相当于是使用GNU autotools开发一个hello world项目而得到的config.h。

/* config.h.  Generated from config.h.in by configure.  */
/* config.h.in.  Generated from configure.ac by autoheader.  */

/* Name of package */
#define PACKAGE "hello"

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "bug-report@address"

/* Define to the full name of this package. */
#define PACKAGE_NAME "hello"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "hello 1.0"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "hello"

/* Define to the home page for this package. */
#define PACKAGE_URL ""

/* Define to the version of this package. */
#define PACKAGE_VERSION "1.0"

/* Version number of package */
#define VERSION "1.0"


2. 链接

需要带上这几个库:bfd iberty  dl z

例如,假设hello.c是一个完整的使用bfd库的程序,则他的编译方法如下。

gcc hello.c -lbfd -liberty  -ldl -lz


三. 应用实例

#include <stdio.h>
#include <stdint.h>
#include "config.h"
#include <bfd.h>
#include <strings.h>
#include <linux/elf.h>

/* 
   这里定义3个static变量,并把他们放到一个单独的section中。
   后面,我们通过bfd找出这个section,并得到这3个变量的内容。
   同时,我们还通过符号查找操作,找到a_haha这个static变量的信息。
*/
static uint64_t  a_haha   __attribute__((section ("my_test_sec"))) =3;
static uint64_t  b        __attribute__((section ("my_test_sec"))) =7;
static uint64_t  c        __attribute__((section ("my_test_sec"))) =8;

/* 获取当前进程自己的elf文件路径 */
int get_self_path(char *buf, int buf_len)
{
    int ret = readlink("/proc/self/exe", buf, buf_len);
    buf[ret]='\0';
    return ret; 
}

void section_proc(bfd *abfd,  asection *sect, PTR obj)
{
    if (strcmp(sect->name, "my_test_sec")==0)
        printf("section %s exists\n", sect->name);
}



void search_a_given_symbol(bfd *ibfd, const char *name)
{
         long storage_needed;
         asymbol **symbol_table;
         long number_of_symbols;
         long i;
         symbol_info symbolinfo ;

         storage_needed = bfd_get_symtab_upper_bound(ibfd);


         symbol_table =  (void *)(unsigned long)xmalloc(storage_needed);
         number_of_symbols =  bfd_canonicalize_symtab (ibfd, symbol_table);


        printf("Scanning %i symbols\n", number_of_symbols);
        for(i=0;i<number_of_symbols;i++)
        {
                if (symbol_table[i]->section==NULL) continue;
                
                bfd_symbol_info(symbol_table[i],&symbolinfo);
                if (strcmp(name, symbolinfo.name))  continue;

                printf("Section %s  ",symbol_table[i]->section->name);
                printf("Symbol \"%s\"  value 0x%x\n",
                         symbolinfo.name, symbolinfo.value);
        }


}

int main()
{
    char our_self_path[1024];
    bfd *ibfd;
    char **matching;

    asection *psection;

    bfd_init();

    get_self_path(our_self_path, sizeof(our_self_path));
    printf("our elf file path:%s\n", our_self_path);

    ibfd = bfd_openr(our_self_path, NULL);
    bfd_check_format_matches(ibfd, bfd_object, &matching);

    printf("number of sections = %d\n", bfd_count_sections(ibfd));

    /* 遍历所有section,让section_proc对每一个section进行处理 */
    bfd_map_over_sections(ibfd,  section_proc,  NULL);

    /* 查找特定名称的section,打印出其信息 */
    psection = bfd_get_section_by_name(ibfd, "my_test_sec");
    printf("section name=%s; start_address=0x%llx; size=%d\n"
         , psection->name
         , psection->vma
         , psection->size);

    /* 打印出my_test_sec section中的3个uint64_t变量的值 */
    {
        uint64_t *pu64 = (void *) psection->vma;
        printf("%lu %lu %lu \n", pu64[0], pu64[1], pu64[2]);
    }

    printf("address of a_haha=%p\n", &a_haha);

    /* 遍历所有符号,以找出名称为a_haha的符号 */
    search_a_given_symbol(ibfd, "a_haha");
    return 0;
}


最后,程序运行效果如下:


[root@smb test]# gcc hello.c -lbfd -liberty  -ldl -lz
[root@smb test]# ./a.out 
our elf file path:/home/shared/sunmingbao/test/a.out
number of sections = 34
section my_test_sec exists
section name=my_test_sec; start_address=0x6c9a28; size=24
3 7 8 
address of a_haha=0x6c9a28
Scanning 1905 symbols
Section my_test_sec  Symbol "a_haha"  value 0x6c9a28
[root@smb test]# 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值