読者です 読者をやめる 読者になる 読者になる

ELF のセクション名一覧を表示

ELF形式のファイルには先頭にELFヘッダーがある。
ELFヘッダーは以下の構造体になっている。

typedef struct
{
  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
  Elf64_Half    e_type;                 /* Object file type */
  Elf64_Half    e_machine;              /* Architecture */
  Elf64_Word    e_version;              /* Object file version */
  Elf64_Addr    e_entry;                /* Entry point virtual address */
  Elf64_Off     e_phoff;                /* Program header table file offset */
  Elf64_Off     e_shoff;                /* Section header table file offset */
  Elf64_Word    e_flags;                /* Processor-specific flags */
  Elf64_Half    e_ehsize;               /* ELF header size in bytes */
  Elf64_Half    e_phentsize;            /* Program header table entry size */
  Elf64_Half    e_phnum;                /* Program header table entry count */
  Elf64_Half    e_shentsize;            /* Section header table entry size */
  Elf64_Half    e_shnum;                /* Section header table entry count */
  Elf64_Half    e_shstrndx;             /* Section header string table index */
} Elf64_Ehdr;

先頭からe_shoff行った所からセクションヘッダーが並んでいる。
セクションの名前はセクションヘッダーではなく.shstrtabセクションに含まれている。 .shstrtabセクションのセクションヘッダーはELFヘッダーのe_shstrndxが示す位置に並んでいる。 セクションヘッダーのサイズはELFヘッダーのe_shentsizeから得られる。
なので、.shstrtabセクションの開始オフセットは
e_shoff + e_shentsize * e_shstrndx のように計算できる。

セクションヘッダーは以下の構造体になっている。

typedef struct
{
  Elf64_Word    sh_name;                /* Section name (string tbl index) */
  Elf64_Word    sh_type;                /* Section type */
  Elf64_Xword   sh_flags;               /* Section flags */
  Elf64_Addr    sh_addr;                /* Section virtual addr at execution */
  Elf64_Off     sh_offset;              /* Section file offset */
  Elf64_Xword   sh_size;                /* Section size in bytes */
  Elf64_Word    sh_link;                /* Link to another section */
  Elf64_Word    sh_info;                /* Additional section information */
  Elf64_Xword   sh_addralign;           /* Section alignment */
  Elf64_Xword   sh_entsize;             /* Entry size if section holds table */
} Elf64_Shdr;

.shstrtabはNULL文字終端の文字列からなっており、sh_nameがそのセクションの名前が.shstrtab中の何番目にあるのかを示している。

なので以下のようなプログラム(read_section.c)でセクション名一覧を表示できる。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <elf.h>
#include <sys/stat.h>
#include <sys/mman.h>

int is_elf(Elf64_Ehdr *ehdr)
{
  return
    ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
    ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
    ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
    ehdr->e_ident[EI_MAG3] == ELFMAG3;
}



int main(int argc, char **argv)
{
  int fd, i;
  struct stat sb;
  char *head;
  Elf64_Ehdr *ehdr;
  Elf64_Shdr *shdr, *shstr;

  fd = open(argv[1], O_RDONLY);
  fstat(fd, &sb);
  head = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);

  ehdr = (Elf64_Ehdr *)head;

  if (!is_elf(ehdr)) {
    fprintf(stderr, "%s is not elf\n", argv[1]);
    exit(1);
  }
  shstr = (Elf64_Shdr *)(head + ehdr->e_shoff
                              + ehdr->e_shentsize * ehdr->e_shstrndx);
  for (i = 0; i < ehdr->e_shnum; i++) {
    shdr = (Elf64_Shdr *)(head + ehdr->e_shoff + ehdr->e_shentsize * i);
    printf("%s\n", (char *)(head + shstr->sh_offset + shdr->sh_name));
  }

  return 0;
}

コンパイルして実行。

$ gcc read_section.c
$ ./a.out a.out

.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.ctors
.dtors
.jcr
.dynamic
.got
.got.plt
.data
.bss
.comment
.shstrtab
.symtab
.strtab