Как я могу найти размер файла / изображения ELF с информацией заголовка? - PullRequest
3 голосов
/ 08 июня 2010

Мне нужно найти размер изображения эльфа для некоторых вычислений. Я пробовал с утилитой readelf на linux, которая дает информацию о заголовках и разделе. Мне нужен точный размер файла эльфа (в целом).

Как узнать размер эльфа из информации заголовка или есть ли другие способы найти размер эльфа без чтения полного изображения.

Ответы [ 6 ]

2 голосов
/ 18 сентября 2016

Пример:

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 голосов
/ 23 февраля 2012

Ответ на конкретный вопрос немного сложен для файлов ELF.

Ниже вычисляется размер «описательной» информации в файле ELF с использованием заголовка: e_ehsize + (e_phnum* e_phentsize) + (e_shnum * e_shentsize)

Вышеуказанное основано на документации ELF.

Следующий фрагмент, добавляемый к вышеуказанной сумме, - это размер в файлераздел записи.Интуитивно мы хотели бы вычислить это, используя sh_size для каждого из разделов в файле - e_shnum из них.ОДНАКО, этот не дает правильного ответа из-за проблем с выравниванием.Если вы используете упорядоченный список значений sh_offset , вы можете вычислить точное количество байтов, занимаемое записью раздела (я обнаружил некоторые странные выравнивания, где использование sh_addralign не так полезно, как хотелось бы);для последней записи раздела используйте заголовок файла e_shoff , поскольку таблица заголовка раздела является последней.Это сработало для пары, которую я проверял.

update.c в libelf содержит детали, которые он использует при обновлении файла elf.

0 голосов
/ 09 августа 2016

Все, что вам нужно сделать, это сложить смещение файла последнего раздела и его размер.

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
0 голосов
/ 08 июня 2010

Вы пытались использовать утилиту gnu "readelf"?

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

0 голосов
/ 08 июня 2010

Возможно gelf может быть полезным.

GElf - это общий, независимый от класса API-интерфейс для манипулирования объектными файлами ELF. GElf предоставляет единый общий интерфейс для обработки 32-битных и 64-битных объектных файлов в формате ELF.

конкретно эти функции:

elf32_fsize, elf64_fsize - вернуть размер типа объектного файла

0 голосов
/ 08 июня 2010

Вы можете использовать семейство функций 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 (замените 32 на 64 для 64-битного файла). e_ehsize - размер файла в байтах.


Я скопирую дословно комментарий, который был опубликован в качестве предложения по редактированию:

Этот ответ неверный. e_ehsize - это просто размер заголовка эльфа, а не файла эльфа.

...