FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

ELFファイルを取り扱うためのlibelfライブラリ調査

現在自作CPUのELFファイルロードにはlibbfdを使用しているが、このライブラリにはいくつか問題があるように思えている。 まず、環境によって必要な関数の引数が異なること。bfd_section_size()関数の引数が環境で異なるので困っている。

  uintptr_t sz = (uintptr_t)bfd_get_section_size(section);
  uintptr_t sz = (uintptr_t)bfd_get_section_size(bfd, section);

環境によっては上手く動作しないので困っていたので、さらにCygwin環境だと上手くビルドできないという問題に直面したので、いよいよlibbfdを諦めてlibelfに置き換えることにした。

手元にあるlibelfのサンプルを見ながら、いくつか自分で組み上げてみる。

packages.ubuntu.com

各関数の機能については、完全に把握しきっているわけではない。

#include <libelf.h>
...
Elf_Scn    *scn;
Elf_Data   *data;
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;

extern "C" int
load_binary(char const* path_exec,
            char const* filename,
            bool is_load_dump)
{

  if (((ehdr = elf64_getehdr(elf)) == NULL) ||
      ((scn  = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
      ((data = elf_getdata(scn, NULL)) == NULL) ||
      ((phdr = elf64_getphdr(elf)) == NULL))
    failure();

ELF情報のロードに成功すると、次は.textセクションをダンプしてみる。

  dump_segment (".text", fd);
void dump_segment (const char* segname, int fd)
{
  unsigned int cnt;
  Elf * elf;
  Elf64_Shdr * shdr;
  Elf_Data * datapoint;
  int count, count2;
  Byte_t * buffer;
...
  /* Traverse input filename, printing each section */
  for (cnt = 1, scn = NULL; (scn = elf_nextscn(elf, scn))!=NULL; cnt++) {
    if ((shdr = elf64_getshdr(scn)) == NULL)
      failure();
    if (!strncmp ((char *)data->d_buf + shdr->sh_name,
                   segname,strlen(segname)) &&
        strlen(segname) == strlen((char *)data->d_buf + shdr->sh_name)) {

      lseek (fd,shdr->sh_offset,SEEK_SET);
      buffer = (Byte_t *) malloc ((shdr->sh_size)*sizeof(unsigned char));
      valsRead=read(fd,buffer, shdr->sh_size);

      base = phdr->p_paddr;
...
      for(count=0; count < valsRead; count=count+4) {
        fprintf (stderr,"%08x: ", base);

        base = base + 4;
        switch (identity[EI_DATA]) {

          case 1:    /* Little endian */
            for (count2=3;count2>-1;count2--) {
              fprintf (stderr,"%.2x",static_cast<UByte_t>(buffer[count+count2]));
              g_memory->StoreMemory<Byte_t> (base - 4 + count + count2, static_cast<Byte_t *>(&buffer[count+count2]));
            }
            fprintf (stderr,"\n");
            break;
...

ELFの情報を受け取ってはStoreMemory()でメモリに書き込んでいく。そして自作RISC-V CPUのローダに接続している。

一応これで移行は完了できた。シミュレーション動作的にも問題ない。