コード
read_elf.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 main(int argc, char *argv[]) {
int fd, i;
struct stat sb;
char *head;
Elf64_Ehdr *ehdr; // elf header
Elf64_Shdr *shdr; // section header
Elf64_Shdr *shstr; // section string
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;
// head is address
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));
}
munmap(head, sb.st_size);
close(fd);
exit (0);
}
$ clang read_elf.c ./a.out a.out
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.got
.got.plt
.data
.bss
.comment
.symtab
.strtab
.shstrtab
メモ
shdr->sh_name
shdr->sh_name
はsection nameのアドレス値が入ってるのではなく、Section header string table
からsection nameまでのoffsetである.
なので、head + shstr->sh_offset + shdr->sh_name
は、
mmapされたfileの先頭アドレス + fileの先頭アドレスからSection header string table
までのoffset + Section header string table
からsection nameまでのoffsetである.
なお、mmapがどういう仕組み・アルゴリズムでfileをメモリ上にマッピングしているのかはここでは触れない.
ehdr = (Elf64_Ehdr *)head;
最近リトルエンディアンについて触れたので、これについても改めてメモをする.
ehdr = (Elf64_Ehdr *)head;
ehdrはこの右側に書いたElf64_Ehdr領域に対する直接的な操作になるだけである.
Shared Private Board@2x (2).png
その他参考資料
ELFのSection header string table indexセクションの中を表示する
リンカ・ローダ実践開発テクニック―実行ファイルを作成するために必須の技術