如何找到带有标题信息的ELF文件/图像的大小?

时间:2010-06-08 07:05:32

标签: linux filesize elf

我需要找到一个精灵图像的大小进行一些计算。我已经尝试使用linux上的readelf实用程序,它提供了有关标题和部分的信息。我需要拥有精灵的确切文件大小(总体而言)。

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

6 个答案:

答案 0 :(得分:2)

对于ELF文件,具体问题的答案有点棘手。

以下内容将使用标题计算ELF文件中“描述性”信息的大小: e_ehsize +(e_phnum * e_phentsize)+(e_shnum * e_shentsize)

以上内容基于ELF文档。

要添加到上述总和的下一个部分是部分条目文件中的大小。直观地,我们希望使用 sh_size 为文件中的每个部分 - e_shnum 计算它们。但是,由于对齐问题,此无法产生正确的答案。如果您使用有序的sh_offset值列表,您可以计算该条目占用的确切字节数(我发现了一些奇怪的对齐,其中使用sh_addralign并不像您希望的那样有用);对于最后一个条目,使用文件头的 e_shoff ,因为节头表是最后一个。这适用于我检查过的那对夫妇。

lib.c中的update.c 包含更新elf文件时使用的详细信息。

答案 1 :(得分: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;
}

答案 2 :(得分:0)

也许gelf可能有用。

  

GElf是一种通用的,与ELF类无关的API,用于处理ELF目标文件。 GElf提供了一个用于处理32位和64位ELF格式目标文件的通用接口。

具体是这些功能:

  

elf32_fsize,elf64_fsize - 返回目标文件类型的大小

答案 3 :(得分:0)

您是否尝试过使用gnu“readelf”实用程序?

http://sourceware.org/binutils/docs/binutils/readelf.html

答案 4 :(得分: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

答案 5 :(得分:-1)

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


如果您真的想使用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位文件,将64替换为64)。 e_ehsize是文件的大小(以字节为单位)。


我将逐字复制作为编辑建议发布的评论:

  

这个答案是不正确的。 e_ehsize只是elf头的大小,而不是elf文件的大小。