5

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

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

4

6 回答 6

6

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

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

以上内容基于 ELF 文档。

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

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

于 2012-02-22T23:54:01.973 回答
4

例子:

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;
}
于 2016-09-18T14:07:01.053 回答
0

也许gelf可能有用。

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

特别是这些功能:

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

于 2010-06-08T07:29:17.263 回答
0

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

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

于 2010-06-08T07:33:51.630 回答
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
于 2016-08-09T13:42:24.227 回答
-2

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


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

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

于 2010-06-08T07:08:11.323 回答