現在自作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
のサンプルを見ながら、いくつか自分で組み上げてみる。
各関数の機能については、完全に把握しきっているわけではない。
#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のローダに接続している。
一応これで移行は完了できた。シミュレーション動作的にも問題ない。