2010-06-08 51 views
3

我需要为某些计算找到一个精灵图像的大小。我已经尝试了linux上的readelf实用程序,它提供了有关标题和部分的信息。我需要精确的文件大小(总体来说)。如何查找包含Header信息的ELF文件/图像的大小?

如何从标题信息中找到ELF的大小或是否有其他方法可以在不阅读完整图像的情况下查找精灵的大小。

回答

-1

您可以使用stat系列函数(stat()lstat()fstat()),以获得任何文件(使用stat成员的st_size成员)的大小。 你需要更具体的东西吗?


如果你真的想使用的ELF结构,使用其中包含结构elf.h中标题:

typedef struct { 
     unsigned char e_ident[EI_NIDENT]; 
     uint16_t  e_type; 
     uint16_t  e_machine; 
     uint32_t  e_version; 
     ElfN_Addr  e_entry; 
     ElfN_Off  e_phoff; 
     ElfN_Off  e_shoff; 
     uint32_t  e_flags; 
     uint16_t  e_ehsize; 
     uint16_t  e_phentsize; 
     uint16_t  e_phnum; 
     uint16_t  e_shentsize; 
     uint16_t  e_shnum; 
     uint16_t  e_shstrndx; 
} Elf32_Ehdr; 

这是一个ELF32文件的头部(64更换32 64位文件)。 e_ehsize是以字节为单位的文件大小。


我会复制被张贴编辑建议逐字评论:

这个答案是不正确。 e_ehsize仅仅是elf标题的大小,而不是elf文件。

+0

我们如何使用这个结构来找到任何ELF文件的大小。我的意思是API样的东西.. – fasil 2010-06-09 10:26:58

+0

任何使用示例? – fasil 2010-06-09 11:01:25

+0

你的语言是什么?以C语言为例,使用'fread()'读取头文件应该很容易,然后打印'e_ehsize'成员。 – 2010-06-09 11:18:40

0

也许gelf可能是有用的。

GElf是一个通用的ELF类独立API,用于操作ELF对象文件。 GElf为处理32位和64位ELF格式目标文件提供了一个单一的通用接口。

具体如下功能:

elf32_fsize,elf64_fsize - 返回一个对象的文件类型

+0

使用GELF库的任何使用示例... – fasil 2010-06-09 10:57:41

+0

我不能与此,因为我需要安装库的东西在根文件系统,这将需要更多的空间.. – fasil 2010-06-09 10:59:59

+0

@fasil:你可以使用“[libelf by Example](http://sourceforge.net/projects/elftoolchain/files/Documentation/libelf-by-example/)”教程开始使用GELF(3)API。 – jkoshy 2012-02-26 03:07:38

2

答案的具体问题是ELF文件有点棘手。

下面将使用标头计算在ELF文件中的 “描述” 信息的大小:e_ehsize +(e_phnum * e_phentsize)+(e_shnum * e_shentsize)

上面是基于ELF文档。

添加到上述总和中的下一个部分是部分条目文件中的大小。直观地,我们希望使用sh_size来计算文件中的每个部分 - e_shnum。但是,由于对齐问题,不会产生正确答案。如果你使用了一个sh_offset值的有序列表,你可以计算出这个section entry占据的确切字节数(我发现了一些使用sh_addralign并不像你想的那样有用的奇怪对齐方式)。对于最后一部分条目,使用文件标头的e_shoff,因为部分标题表是最后一个。这对我检查的那对夫妇有效。

update.c in libelf有更新elf文件时使用的细节。

+0

建议'elf_getphdrnum()'和'elf_getshdrnum()'函数分别检索ELF对象中的PHDR和SHDR条目数。这些函数可以正确处理使用扩展编号的ELF对象,其中直接使用ELF标头的“e_phnum”或“e_shnum”字段可能不正确。 – jkoshy 2012-02-26 03:41:09

+0

但是由于节头表直接映射,并且sh_offsets的有序列表被扩展并映射到内存中,所以节头表不会最终位于内存映像的末尾。例如,在磁盘上,sh_offset将小于上一节的内存映像偏移量。小 - 大=负 – Captainlonate 2013-11-05 17:10:20

0

您所要做的就是对最后一部分的文件偏移量和大小进行求和。

fseek(fileHandle, elfHeader.e_shoff + (elfHeader.e_shnum-1) * elfHeader.e_shentsize, SEEK_SET); 
Elf64_Shdr sectionHeader; // or Elf32_Shdr 
fread(&sectionHeader, 1, elfHeader.e_shentsize, fileHandle); 

int fileSize = sectionHeader.sh_offset + sectionHeader.sh_size; 

elfHeader使用的值:

e_shoff = Section header table file offset 
e_shnum = Section header table entry count 
e_shentsize = Section header table entry size  

sectionHeader使用的值:

sh_offset = Section file offset 
sh_size = Section size in bytes 
2

实施例:

ls -l gives 126584 

Calculation using the values also reported by readelf -h: 

Start of section headers e_shoff  124728 
Size of section headers  e_shentsize 64 
Number of section headers e_shnum  29 

e_shoff + (e_shentsize * e_shnum) = 126584 

这假定节头表(SHT)是ELF的最后一部分。这通常是这种情况,但也可能是最后一部分是ELF的最后一部分。应该检查这个,但不在这个例子中。

这里是一个在C工作的实施,编译gcc elfsize.c -o elfsize

#include <elf.h> 
#include <byteswap.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <fcntl.h> 

typedef Elf32_Nhdr Elf_Nhdr; 

static char *fname; 
static Elf64_Ehdr ehdr; 
static Elf64_Phdr *phdr; 

#if __BYTE_ORDER == __LITTLE_ENDIAN 
#define ELFDATANATIVE ELFDATA2LSB 
#elif __BYTE_ORDER == __BIG_ENDIAN 
#define ELFDATANATIVE ELFDATA2MSB 
#else 
#error "Unknown machine endian" 
#endif 

static uint16_t file16_to_cpu(uint16_t val) 
{ 
    if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) 
     val = bswap_16(val); 
    return val; 
} 

static uint32_t file32_to_cpu(uint32_t val) 
{ 
    if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) 
     val = bswap_32(val); 
    return val; 
} 

static uint64_t file64_to_cpu(uint64_t val) 
{ 
    if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) 
     val = bswap_64(val); 
    return val; 
} 

static long unsigned int read_elf32(int fd) 
{ 
    Elf32_Ehdr ehdr32; 
    ssize_t ret, i; 

    ret = pread(fd, &ehdr32, sizeof(ehdr32), 0); 
    if (ret < 0 || (size_t)ret != sizeof(ehdr)) { 
     fprintf(stderr, "Read of ELF header from %s failed: %s\n", 
      fname, strerror(errno)); 
     exit(10); 
    } 

    ehdr.e_shoff  = file32_to_cpu(ehdr32.e_shoff); 
    ehdr.e_shentsize = file16_to_cpu(ehdr32.e_shentsize); 
    ehdr.e_shnum  = file16_to_cpu(ehdr32.e_shnum); 

    return(ehdr.e_shoff + (ehdr.e_shentsize * ehdr.e_shnum)); 
} 

static long unsigned int read_elf64(int fd) 
{ 
    Elf64_Ehdr ehdr64; 
    ssize_t ret, i; 

    ret = pread(fd, &ehdr64, sizeof(ehdr64), 0); 
    if (ret < 0 || (size_t)ret != sizeof(ehdr)) { 
     fprintf(stderr, "Read of ELF header from %s failed: %s\n", 
      fname, strerror(errno)); 
     exit(10); 
    } 

    ehdr.e_shoff  = file64_to_cpu(ehdr64.e_shoff); 
    ehdr.e_shentsize = file16_to_cpu(ehdr64.e_shentsize); 
    ehdr.e_shnum  = file16_to_cpu(ehdr64.e_shnum); 

    return(ehdr.e_shoff + (ehdr.e_shentsize * ehdr.e_shnum)); 
} 

long unsigned int get_elf_size(char *fname) 
/* TODO, FIXME: This assumes that the section header table (SHT) is 
the last part of the ELF. This is usually the case but 
it could also be that the last section is the last part 
of the ELF. This should be checked for. 
*/ 
{ 
    ssize_t ret; 
    int fd; 
    long unsigned int size = 0; 

    fd = open(fname, O_RDONLY); 
    if (fd < 0) { 
     fprintf(stderr, "Cannot open %s: %s\n", 
      fname, strerror(errno)); 
     return(1); 
    } 
    ret = pread(fd, ehdr.e_ident, EI_NIDENT, 0); 
    if (ret != EI_NIDENT) { 
     fprintf(stderr, "Read of e_ident from %s failed: %s\n", 
      fname, strerror(errno)); 
     return(1); 
    } 
    if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) && 
     (ehdr.e_ident[EI_DATA] != ELFDATA2MSB)) 
    { 
     fprintf(stderr, "Unkown ELF data order %u\n", 
      ehdr.e_ident[EI_DATA]); 
     return(1); 
    } 
    if(ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 
     size = read_elf32(fd); 
    } else if(ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 
     size = read_elf64(fd); 
    } else { 
     fprintf(stderr, "Unknown ELF class %u\n", ehdr.e_ident[EI_CLASS]); 
     return(1); 
    } 

    close(fd); 
    return size; 
} 

int main(int argc, char **argv) 
{ 
    ssize_t ret; 
    int fd; 

    if (argc != 2) { 
     fprintf(stderr, "Usage: %s <ELF>\n", argv[0]); 
     return 1; 
    } 
    fname = argv[1]; 

    long unsigned int size = get_elf_size(fname); 
    fprintf(stderr, "Estimated ELF size on disk: %lu bytes \n", size); 
    return 0; 
} 
相关问题