2010-06-08 50 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; 
} 
相關問題