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

时间:2022-10-07 15:04:50

I need to find the size of an elf image for some computation. I have tried with the readelf utility on linux which gives the informations about the headers and section. I need to have the exact file size of the elf(on the whole).

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

How do I find the size of the ELF from the header information or Is there any other means to find the size of an elf without reading the full image.

我如何从头信息中找到精灵的大小,或者在没有读取完整图像的情况下找到一个精灵的大小。

6 个解决方案

#1


-1  

You can use the stat functions family (stat(), lstat(), fstat()) to get the size of any file (using the st_size member of the stat member). Do you need something more specific?

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


If you really want to use the ELF structure, use the elf.h header which contains that structure:

如果你真的想使用精灵的结构,请使用精灵。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;

It's the header of an ELF32 file (replace 32 with 64 for a 64-bit file). e_ehsize is the size of the file in bytes.

它是一个ELF32文件的头部(64位文件替换32,64位)。e_ehsize是文件的字节大小。


I'll copy verbatim the comment that was posted as an edit suggestion:

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

This answer is incorrect. e_ehsize is merely the size of the elf header, not the elf file.

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

#2


2  

The answer to the specific question is a little tricky for ELF files.

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

The following will compute the size of the "descriptive" information in an ELF file using the header: e_ehsize + (e_phnum * e_phentsize) + (e_shnum * e_shentsize)

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

The above is based on the ELF documentation.

以上是基于ELF文档。

The next piece to add to the above sum is the size in the file of the section entries. Intuitively we would like to compute this using sh_size for each of the sections in the file -- e_shnum of them. HOWEVER, this doesn't yield the correct answer due to alignment issues. If you use an ordered list of sh_offset values you can compute the exact number of bytes that the section entry occupies (I found some strange alignments where using sh_addralign isn't as useful as you would like); for the last section entry use the file header's e_shoff since the section header table is last. This worked for the couple I checked.

下一个要添加到上述和的部分是条目的文件中的大小。直观上,我们希望用sh_size来计算文件中的每个部分——e_shnum。然而,由于对齐问题,这并没有给出正确的答案。如果您使用一个有序的sh_offset值列表,您可以计算出section条目占用的确切字节数(我发现一些奇怪的对齐方式,使用sh_addralign并没有您想要的那么有用);对于最后一节,使用文件头的e_shoff,因为section header表是最后一个。这对我检查过的夫妇很有效。

update.c in libelf has the details it uses when updating an elf file.

更新。c在libelf中有更新elf文件时使用的详细信息。

#3


2  

Example:

例子:

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

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, but is not in this example.

这假设section header表(SHT)是ELF的最后一部分。通常情况是这样的,但也可能是最后一部分是ELF的最后一部分。这应该被检查,但不是在这个例子中。

Here is a working implementation in C, compile with gcc elfsize.c -o elfsize:

这里是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;
}

#4


0  

Perhaps gelf could be useful.

也许gelf是有用的。

GElf is a generic, ELF class-independent API for manipulat- ing ELF object files. GElf provides a single, common inter- face for handling 32-bit and 64-bit ELF format object files.

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

specifically these functions:

特别是这些函数:

elf32_fsize, elf64_fsize - return the size of an object file type

elf32_fsize, elf64_fsize -返回对象文件类型的大小。

#5


0  

Have you tried using the gnu "readelf" utility?

你试过使用gnu“readelf”工具吗?

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

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

#6


0  

All you have to do is to sum the last section's file offset and its size.

您所要做的就是将最后一节的文件偏移量和它的大小相加。

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 used values:

elfHeader使用价值:

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

sectionHeader used values:

sectionHeader使用价值:

sh_offset = Section file offset
sh_size = Section size in bytes

#1


-1  

You can use the stat functions family (stat(), lstat(), fstat()) to get the size of any file (using the st_size member of the stat member). Do you need something more specific?

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


If you really want to use the ELF structure, use the elf.h header which contains that structure:

如果你真的想使用精灵的结构,请使用精灵。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;

It's the header of an ELF32 file (replace 32 with 64 for a 64-bit file). e_ehsize is the size of the file in bytes.

它是一个ELF32文件的头部(64位文件替换32,64位)。e_ehsize是文件的字节大小。


I'll copy verbatim the comment that was posted as an edit suggestion:

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

This answer is incorrect. e_ehsize is merely the size of the elf header, not the elf file.

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

#2


2  

The answer to the specific question is a little tricky for ELF files.

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

The following will compute the size of the "descriptive" information in an ELF file using the header: e_ehsize + (e_phnum * e_phentsize) + (e_shnum * e_shentsize)

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

The above is based on the ELF documentation.

以上是基于ELF文档。

The next piece to add to the above sum is the size in the file of the section entries. Intuitively we would like to compute this using sh_size for each of the sections in the file -- e_shnum of them. HOWEVER, this doesn't yield the correct answer due to alignment issues. If you use an ordered list of sh_offset values you can compute the exact number of bytes that the section entry occupies (I found some strange alignments where using sh_addralign isn't as useful as you would like); for the last section entry use the file header's e_shoff since the section header table is last. This worked for the couple I checked.

下一个要添加到上述和的部分是条目的文件中的大小。直观上,我们希望用sh_size来计算文件中的每个部分——e_shnum。然而,由于对齐问题,这并没有给出正确的答案。如果您使用一个有序的sh_offset值列表,您可以计算出section条目占用的确切字节数(我发现一些奇怪的对齐方式,使用sh_addralign并没有您想要的那么有用);对于最后一节,使用文件头的e_shoff,因为section header表是最后一个。这对我检查过的夫妇很有效。

update.c in libelf has the details it uses when updating an elf file.

更新。c在libelf中有更新elf文件时使用的详细信息。

#3


2  

Example:

例子:

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

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, but is not in this example.

这假设section header表(SHT)是ELF的最后一部分。通常情况是这样的,但也可能是最后一部分是ELF的最后一部分。这应该被检查,但不是在这个例子中。

Here is a working implementation in C, compile with gcc elfsize.c -o elfsize:

这里是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;
}

#4


0  

Perhaps gelf could be useful.

也许gelf是有用的。

GElf is a generic, ELF class-independent API for manipulat- ing ELF object files. GElf provides a single, common inter- face for handling 32-bit and 64-bit ELF format object files.

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

specifically these functions:

特别是这些函数:

elf32_fsize, elf64_fsize - return the size of an object file type

elf32_fsize, elf64_fsize -返回对象文件类型的大小。

#5


0  

Have you tried using the gnu "readelf" utility?

你试过使用gnu“readelf”工具吗?

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

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

#6


0  

All you have to do is to sum the last section's file offset and its size.

您所要做的就是将最后一节的文件偏移量和它的大小相加。

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 used values:

elfHeader使用价值:

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

sectionHeader used values:

sectionHeader使用价值:

sh_offset = Section file offset
sh_size = Section size in bytes