如何find带有Header信息的ELF文件/图像的大小?

我需要为一些计算find一个精灵图像的大小。 我已经试过在Linux上的readelf实用程序,它提供了有关标题和部分的信息。 我需要精确的文件大小(总体来说)。

如何从标题信息中findELF的大小?还有没有其他方法可以在不阅读完整图像的情况下查找精灵的大小。

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


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

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

对于特定问题的答案是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文件时使用的细节。

例:

 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编译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; } 

也许gelf可能是有用的。

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

具体这些功能:

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

你有没有尝试过使用GNU“readelf”工具?

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

所有你需要做的是总结最后一节的文件偏移量和大小。

 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