快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
bfinutils-2.19
vs2008
欢迎转载,但请保留作者信息
1.1 文件格式
在使用bfd分析文件时,通常会先用bfd_check_format或者bfd_check_format_matches函数判断文件的类型,使用它们可以将文件分为4类:
/* File formats. */
typedef enum bfd_format
{
bfd_unknown = 0, /* File format is unknown. */
bfd_object, /* Linker/assembler/compiler output. */
bfd_archive, /* Object archive file. */
bfd_core, /* Core dump. */
bfd_type_end /* Marks the end; don't use it! */
}
bfd_format;
object为单个的目标文件,如.o,.obj之类的,archive则是目标文件的集合,如.a或者.lib文件,core则是dump生成的文件。
1.2 格式检查
先看bfd_check_format函数:
/*
FUNCTION
bfd_check_format
SYNOPSIS
bfd_boolean bfd_check_format (bfd *abfd, bfd_format format);
DESCRIPTION
Verify if the file attached to the BFD @var{abfd} is compatible
with the format @var{format} (i.e., one of <<bfd_object>>,
<<bfd_archive>> or <<bfd_core>>).
If the BFD has been set to a specific target before the
call, only the named target and format combination is
checked. If the target has not been set, or has been set to
<<default>>, then all the known target backends is
interrogated to determine a match. If the default target
matches, it is used. If not, exactly one target must recognize
the file, or an error results.
The function returns <<TRUE>> on success, otherwise <<FALSE>>
with one of the following error codes:
o <<bfd_error_invalid_operation>> -
if <<format>> is not one of <<bfd_object>>, <<bfd_archive>> or
<<bfd_core>>.
o <<bfd_error_system_call>> -
if an error occured during a read - even some file mismatches
can cause bfd_error_system_calls.
o <<file_not_recognised>> -
none of the backends recognised the file format.
o <<bfd_error_file_ambiguously_recognized>> -
more than one backend recognised the file format.
*/
bfd_boolean
bfd_check_format (bfd *abfd, bfd_format format)
{
return bfd_check_format_matches (abfd, format, NULL);
}
注释里面已经把函数功能讲得很清楚了,只是没涉及具体实现而已,再看bfd_check_format_matches函数:
bfd_boolean
bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
{
extern const bfd_target binary_vec;
const bfd_target * const *target;
const bfd_target **matching_vector = NULL;
const bfd_target *save_targ, *right_targ, *ar_right_targ;
int match_count;
int ar_match_index;
// 判断传入的参数和当前bfd的状态有没有问题
………………….
/* If the target type was explicitly specified, just check that target. */
if (!abfd->target_defaulted)
{
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) /* rewind! */
goto err_ret;
right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
if (right_targ)
goto ok_ret;
………………….
// 错误处理
}
// 遍历bfd库支持的所有目标格式
for (target = bfd_target_vector; *target != NULL; target++)
{
const bfd_target *temp;
bfd_error_type err;
// 进行简单初始化工作
………………………………
temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
// 判断结果
…………………………
}
// 错误处理
………………………….
}
它的逻辑其实也挺简单的,如果在openr函数中指定的要使用的target名称,那么这个函数将只检验这个指定的target,否则将遍历bfd支持的所有格式。在这里用到了一个叫BFD_SEND_FMT的宏,它的定义为:
#define BFD_SEND_FMT(bfd, message, arglist) /
(((bfd)->xvec->message[(int) ((bfd)->format)]) arglist)
展开后可以发现,具体的检查工作将由bfd_target:: _bfd_check_format这个回调函数完成,不同的target它们的回调函数也是不同的。看看这个函数指针的定义:
/* Check the format of a file being read. Return a <<bfd_target *>> or zero. */
const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *);
对应于需要检查的4种格式,定义4个不同的回调函数。
对于bfd_elf32_bfin_vec这个目标来说,它将这四个函数分别指向:
/* bfd_check_format: check the format of a file being read */
{ _bfd_dummy_target, /* unknown format */
bfd_elf32_object_p, /* assembler/linker output (object file) */
bfd_elf32_archive_p, /* an archive */
bfd_elf32_core_file_p /* a core file */
},
1.3 bfd_elf32_bfin_vec对archive格式的检查
bfd_elf32_bfin_vec将对archive格式进行检查的函数指针设置为bfd_elf32_archive_p,但在此定义之前还有一个宏定义:
#ifndef bfd_elf32_archive_p
#define bfd_elf32_archive_p bfd_generic_archive_p
#endif
因此,实际将由bfd_generic_archive_p这个函数来进行格式检查:
const bfd_target *
bfd_generic_archive_p (bfd *abfd)
{
struct artdata *tdata_hold;
char armag[SARMAG + 1];
bfd_size_type amt;
if (bfd_bread (armag, SARMAG, abfd) != SARMAG)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
bfd_is_thin_archive (abfd) = (strncmp (armag, ARMAGT, SARMAG) == 0);
if (strncmp (armag, ARMAG, SARMAG) != 0
&& strncmp (armag, ARMAGB, SARMAG) != 0
&& ! bfd_is_thin_archive (abfd))
return 0;
…………………
return abfd->xvec;
}
在这个函数里,首先就是读取SARMAG个字节的文件头标志,在elf/ar.h中定义了可能出现的文件头标志:
/* Note that the usual '/n' in magic strings may translate to different
characters, as allowed by ANSI. '/012' has a fixed value, and remains
compatible with existing BSDish archives. */
#define ARMAG "!<arch>/012" /* For COFF and a.out archives. */
#define ARMAGB "!<bout>/012" /* For b.out archives. */
#define ARMAGT "!<thin>/012" /* For thin archives. */
#define SARMAG 8
#define ARFMAG "`/012"
很显然,如果想要让bfd支持vdsp的dlb文件,这是必须重新定义的第一个函数。
1.4 bfd_elf32_bfin_vec对object格式的检查
bfd_elf32_bfin_vec将这个检查函数设置为bfd_elf32_object_p,但是在bfd的代码中并没有直接给出这个函数的定义,而是在elfcode.h中定义了一个宏:
#define elf_object_p NAME(bfd_elf,object_p)
而NAME则定义为:
#define NAME(x, y) x ## 32 ## _ ## y
于是乎elf_object_p这个名称就变成了bfd_elf32_object_p。在elfcode.h中还定义了这样的函数:
/* Check to see if the file associated with ABFD matches the target vector
that ABFD points to.
Note that we may be called several times with the same ABFD, but different
target vectors, most of which will not match. We have to avoid leaving
any side effects in ABFD, or any data it points to (like tdata), if the
file does not match the target vector. */
const bfd_target *
elf_object_p (bfd *abfd)
{
……………..
}
这也是实际使用的函数。
参考资料
bfd对多目标的支持( 2008-9-25 )
bfd对elf32格式的支持( 2008-11-7 )
objdump与readelf的区别( 2008-11-10 )
objdump代码分析( 2008-11-10 )