快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
bfinutils-2.18
欢迎转载,但请保留作者信息
bfd库是一个用于处理二进制文件的库,它可以读写ELF, COFF之类格式的文件,但不涉及CPU的反汇编操作(这个将由opcodes完成)。在binutils,gdb等程序中都使用了它。那么它是如何做到支持如此多的目标呢?
Bfd的主要信息由一个叫bfd的结构体进行描述:
/* Extracted from bfd.c. */
struct bfd
{
………………………………..
/* A pointer to the target jump table. */
const struct bfd_target *xvec;
………………………………..
/* Pointer to structure which contains architecture information. */
const struct bfd_arch_info *arch_info;
………………………………..
/* Used by the back end to hold private data. */
union
{
struct aout_data_struct *aout_data;
struct artdata *aout_ar_data;
struct _oasys_data *oasys_obj_data;
struct _oasys_ar_data *oasys_ar_data;
struct coff_tdata *coff_obj_data;
struct pe_tdata *pe_obj_data;
struct xcoff_tdata *xcoff_obj_data;
struct ecoff_tdata *ecoff_obj_data;
struct ieee_data_struct *ieee_data;
struct ieee_ar_data_struct *ieee_ar_data;
struct srec_data_struct *srec_data;
struct ihex_data_struct *ihex_data;
struct tekhex_data_struct *tekhex_data;
struct elf_obj_tdata *elf_obj_data;
struct nlm_obj_tdata *nlm_obj_data;
struct bout_data_struct *bout_data;
struct mmo_data_struct *mmo_data;
struct sun_core_struct *sun_core_data;
struct sco5_core_struct *sco5_core_data;
struct trad_core_struct *trad_core_data;
struct som_data_struct *som_data;
struct hpux_core_struct *hpux_core_data;
struct hppabsd_core_struct *hppabsd_core_data;
struct sgi_core_struct *sgi_core_data;
struct lynx_core_struct *lynx_core_data;
struct osf_core_struct *osf_core_data;
struct cisco_core_struct *cisco_core_data;
struct versados_data_struct *versados_data;
struct netbsd_core_struct *netbsd_core_data;
struct mach_o_data_struct *mach_o_data;
struct mach_o_fat_data_struct *mach_o_fat_data;
struct bfd_pef_data_struct *pef_data;
struct bfd_pef_xlib_data_struct *pef_xlib_data;
struct bfd_sym_data_struct *sym_data;
void *any;
}
tdata;
……………………………..
};
从这三个成员大致就可以猜出bfd支持多目标所使用的方法了。它用了一个叫xvec的成员来保存具体目标的信息,包括其操作函数和相关的一些参数。而arch_info这个成员则定义了一种目标体系结构的硬件参数,如位数,是否big-endian等等,这个值定义好了之后就不再改变,这也是将它定义为const的原因。最后读写的数据将由tdata这个union来表示,对于不同的目标需要进行不同的解释。
在这里,bfd_target无疑扮演了一个苦力的角色,它将完成具体文件格式的分析。这个结构体的定义为:
typedef struct bfd_target
{
/* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. */
char *name;
/* The "flavour" of a back end is a general indication about
the contents of a file. */
enum bfd_flavour flavour;
……………………………….
/* Entries for byte swapping for data. These are different from the
other entry points, since they don't take a BFD as the first argument.
Certain other handlers could do the same. */
bfd_uint64_t (*bfd_getx64) (const void *);
bfd_int64_t (*bfd_getx_signed_64) (const void *);
void (*bfd_putx64) (bfd_uint64_t, void *);
bfd_vma (*bfd_getx32) (const void *);
bfd_signed_vma (*bfd_getx_signed_32) (const void *);
void (*bfd_putx32) (bfd_vma, void *);
bfd_vma (*bfd_getx16) (const void *);
bfd_signed_vma (*bfd_getx_signed_16) (const void *);
void (*bfd_putx16) (bfd_vma, void *);
………………………………………
} bfd_target;
这个结构的信息分为两类,一类是基本信息描述,如名称等,另一类是在处理这个目标时的回调函数,这些函数将由bfd相关的主控函数进行调用。对于不同的目标都必须定义一个具体的结构体。如bfin-elf格式,它的target就定义为:
const bfd_target bfd_elf32_bfin_vec =
{
/* name: identify kind of target */
TARGET_LITTLE_NAME,
……………………………….
/* Routines to byte-swap various sized integers from the data sections */
bfd_getl64, bfd_getl_signed_64, bfd_putl64,
bfd_getl32, bfd_getl_signed_32, bfd_putl32,
bfd_getl16, bfd_getl_signed_16, bfd_putl16,
………………………………
};
在targets.c这个文件中,列出了bfd支持的所有目标,它将这些变量都放在一个称为_bfd_target_vector的数组中:
static const bfd_target * const _bfd_target_vector[] =
{
#ifdef SELECT_VECS
SELECT_VECS,
#else /* not SELECT_VECS */
……………………………
&arm_epoc_pe_big_vec,
&arm_epoc_pe_little_vec,
&arm_epoc_pei_big_vec,
………………………….
&bfd_elf32_avr_vec,
&bfd_elf32_bfin_vec,
&bfd_elf32_bfinfdpic_vec,
………………………….
#endif /* not SELECT_VECS */
/* Always support S-records, for convenience. */
&srec_vec,
&symbolsrec_vec,
/* And tekhex */
&tekhex_vec,
/* Likewise for binary output. */
&binary_vec,
/* Likewise for ihex. */
&ihex_vec,
………………………………..
NULL /* end of list marker */
};
通过SELECT_VECS这个宏的定义,可以控制让bfd只支持自己需要的目标。
在对一个文件进行读写之前,可以通过bfd_set_default_target函数来设置自己需要的目标。