快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
bfinutils-2.19
vs2008
欢迎转载,但请保留作者信息
1.1 数值转换
在elf文件中,最开始的就是文件头,用结构体表示就是:
typedef struct {
unsigned char e_ident[16]; /* ELF "magic number" */
unsigned char e_type[2]; /* Identifies object file type */
unsigned char e_machine[2]; /* Specifies required architecture */
unsigned char e_version[4]; /* Identifies object file version */
unsigned char e_entry[4]; /* Entry point virtual address */
unsigned char e_phoff[4]; /* Program header table file offset */
unsigned char e_shoff[4]; /* Section header table file offset */
unsigned char e_flags[4]; /* Processor-specific flags */
unsigned char e_ehsize[2]; /* ELF header size in bytes */
unsigned char e_phentsize[2]; /* Program header table entry size */
unsigned char e_phnum[2]; /* Program header table entry count */
unsigned char e_shentsize[2]; /* Section header table entry size */
unsigned char e_shnum[2]; /* Section header table entry count */
unsigned char e_shstrndx[2]; /* Section header string table index */
} Elf32_External_Ehdr;
这个结构体表现了文件头中各个字段所占用的字节数,但是并没有考虑这些值是以bigendian还是littleendian方式存放的。为了方便使用,bfd另外定义了一个内部使用的结构体进行表示:
typedef struct elf_internal_ehdr {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
bfd_vma e_entry; /* Entry point virtual address */
bfd_size_type e_phoff; /* Program header table file offset */
bfd_size_type e_shoff; /* Section header table file offset */
unsigned long e_version; /* Identifies object file version */
unsigned long e_flags; /* Processor-specific flags */
unsigned short e_type; /* Identifies object file type */
unsigned short e_machine; /* Specifies required architecture */
unsigned int e_ehsize; /* ELF header size in bytes */
unsigned int e_phentsize; /* Program header table entry size */
unsigned int e_phnum; /* Program header table entry count */
unsigned int e_shentsize; /* Section header table entry size */
unsigned int e_shnum; /* Section header table entry count */
unsigned int e_shstrndx; /* Section header string table index */
} Elf_Internal_Ehdr;
此外还定义了elf_swap_ehdr_in和elf_swap_ehdr_out两个函数在这两种表示方式之间进行转换:
/* Translate an ELF file header in external format into an ELF file header in
internal format. */
static void
elf_swap_ehdr_in (bfd *abfd,
const Elf_External_Ehdr *src,
Elf_Internal_Ehdr *dst)
{
int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
memcpy (dst->e_ident, src->e_ident, EI_NIDENT);
dst->e_type = H_GET_16 (abfd, src->e_type);
dst->e_machine = H_GET_16 (abfd, src->e_machine);
dst->e_version = H_GET_32 (abfd, src->e_version);
if (signed_vma)
dst->e_entry = H_GET_SIGNED_WORD (abfd, src->e_entry);
else
dst->e_entry = H_GET_WORD (abfd, src->e_entry);
dst->e_phoff = H_GET_WORD (abfd, src->e_phoff);
dst->e_shoff = H_GET_WORD (abfd, src->e_shoff);
dst->e_flags = H_GET_32 (abfd, src->e_flags);
dst->e_ehsize = H_GET_16 (abfd, src->e_ehsize);
dst->e_phentsize = H_GET_16 (abfd, src->e_phentsize);
dst->e_phnum = H_GET_16 (abfd, src->e_phnum);
dst->e_shentsize = H_GET_16 (abfd, src->e_shentsize);
dst->e_shnum = H_GET_16 (abfd, src->e_shnum);
dst->e_shstrndx = H_GET_16 (abfd, src->e_shstrndx);
}
在这个函数中,使用了H_GET_16这样的宏来进行值的转换,看看它的定义:
#define H_GET_16 bfd_h_get_16
#define bfd_h_get_16(abfd, ptr) /
BFD_SEND (abfd, bfd_h_getx16, (ptr))
#define BFD_SEND(bfd, message, arglist) /
((*((bfd)->xvec->message)) arglist)
也就是说,它将调用不同的target提供的回调函数来完成数值的转换,比如对于elf32-bfin这个target,它的bfd_h_getx16这个回调函数指向bfd_getl16这个函数。
bfd_vma
bfd_getl16 (const void *p)
{
const bfd_byte *addr = p;
return (addr[1] << 8) | addr[0];
}
1.2 文件头存储
在elf的后端数据表示中,用
struct elf_obj_tdata *elf_obj_data;
来表示elf格式的所有数据,其中struct elf_obj_tdata就保存了elf文件头:
/* Some private data is stashed away for future use using the tdata pointer
in the bfd structure. */
struct elf_obj_tdata
{
Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */
………………….
};
要读写这个文件头的数据,可以用
#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header)
这个宏来取得此文件头。
1.3 e_machine
在文件头中,有个叫e_machine的字段,用以表示此elf文件数据适用的CPU类型,在elf/common.h中定义了一百多种的CPU类型,比如:
#define EM_386 3 /* Intel 80386 */
#define EM_BLACKFIN 106 /* ADI Blackfin */
不过在vdsp的doj文件中,并没有使用EM_BLACKFIN这个值,而是使用了不在定义中的值34。因而在elf32-bfin这个目标处理时,将不再进行后继处理。为了让bfd支持doj格式的文件,自定义一个值:
#define EM_VDSP_DOJ 34 /*vdsp doj file*/
修改elf_object_p函数:
/* Check that the ELF e_machine field matches what this particular
BFD format expects. */
if (ebd->elf_machine_code != i_ehdrp->e_machine
&& (ebd->elf_machine_alt1 == 0
|| i_ehdrp->e_machine != ebd->elf_machine_alt1)
&& (ebd->elf_machine_alt2 == 0
|| i_ehdrp->e_machine != ebd->elf_machine_alt2))
{
if (ebd->elf_machine_code != EM_NONE)
goto got_wrong_format_error;
………………………………..
}
这个判断条件可以改为:
/* Check that the ELF e_machine field matches what this particular
BFD format expects. */
if (ebd->elf_machine_code != i_ehdrp->e_machine
&& (ebd->elf_machine_alt1 == 0
|| i_ehdrp->e_machine != ebd->elf_machine_alt1)
&& (ebd->elf_machine_alt2 == 0
|| i_ehdrp->e_machine != ebd->elf_machine_alt2) &&
i_ehdrp->e_machine != EM_VDSP_DOJ)
{
………………..
参考资料
bfd对多目标的支持( 2008-9-25 )
bfd对elf32格式的支持( 2008-11-7 )
objdump与readelf的区别( 2008-11-10 )
objdump代码分析( 2008-11-10 )
bfd的文件格式识别( 2008-11-10 )
bfd的后端数据表示( 2008-11-10 )
Bfd中的内存泄漏( 2008-11-13 )