計算のためにエルフ画像のサイズを見つける必要があります。ヘッダーとセクションに関する情報を提供する Linux の readelf ユーティリティを試してみました。エルフの正確なファイルサイズ(全体)が必要です。
ヘッダー情報から ELF のサイズを確認するにはどうすればよいですか、またはイメージ全体を読み取らずに ELF のサイズを確認する方法はありますか。
特定の質問に対する答えは、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
ます:
#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 は、ELF オブジェクト ファイルを操作するための、ELF クラスに依存しない汎用 API です。GElf は、32 ビットおよび 64 ビットの ELF 形式のオブジェクト ファイルを処理するための単一の共通インターフェイスを提供します。
特にこれらの機能:
elf32_fsize、elf64_fsize - オブジェクト ファイル タイプのサイズを返す
gnu の「readelf」ユーティリティを試してみましたか?
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 ヘッダーのサイズです。