Skip to content

Commit

Permalink
ELFローダーを実装(とりあえず先頭のauipc, addi,sub,...は実行してた)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamiyaowl committed May 1, 2019
1 parent 38993e7 commit 6bfd7dd
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 13 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"functional": "cpp",
"tuple": "cpp",
"map": "cpp",
"ios": "cpp"
"ios": "cpp",
"iosfwd": "cpp",
"vector": "cpp"
}
}
6 changes: 4 additions & 2 deletions rv32i-sample-src/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ services:
volumes:
- ./:/work
command: >
riscv32-unknown-elf-readelf
-h
riscv32-unknown-elf-objdump
-x
-l
--prefix-addresses
/work/hello.o
depends_on:
- riscv-compile
8 changes: 5 additions & 3 deletions src/Cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ namespace sim {
alu.reset();
}
void load_program(const std::string& elf_path){
elf::load(elf_path, [&](uint32_t addr, uint32_t data){
mem.write(addr, data);
uint32_t entryAddr = elf::load32(elf_path, [&](uint32_t addr, uint8_t data){
mem.write_byte(addr, data);
});
printf("[CPU] entryAddr:%08x\n", entryAddr);
reg.write_pc(entryAddr);
}
void step() {
auto pc = reg.read_pc();
auto inst = mem.read(pc);
printf("[DEBUG] pc:%d\tinst:%08x\n", pc, inst);
printf("[CPU] pc:%d\tinst:%08x\n", pc, inst);
alu.run(reg, mem, inst);
}
void run(){
Expand Down
70 changes: 64 additions & 6 deletions src/ElfLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string>
#include <functional>
#include <fstream>
#include <stdio.h>

// elf.hから一部引用
typedef uint32_t Elf32_Addr;
Expand All @@ -26,14 +27,15 @@ typedef int64_t Elf64_Sxword;
using namespace std;
namespace sim {
namespace elf {
// https://codedocs.xyz/scarv/riscv-gnu-toolchain/linux_2elf_8h_source.html
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Expand All @@ -42,10 +44,32 @@ namespace sim {
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf32_phdr{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct elf32_shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;

// Thanks: http://blue-9.hatenadiary.com/entry/2017/03/14/212929
// Specs: https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
void load(const std::string& elf_path, std::function<void(uint32_t addr, uint32_t data)> write) {
uint32_t load32(const std::string& elf_path, std::function<void(uint32_t addr, uint32_t data)> write) {
std::ifstream ifs(elf_path, ifstream::in | ifstream::binary);
assert(ifs);

Expand Down Expand Up @@ -73,12 +97,46 @@ namespace sim {
assert(hdr.e_type == 2); // ET_EXEC
assert(hdr.e_machine == 243); // EM_RISCV (243) for RISC-V ELF files. We only support RISC-V v2 family ISAs, this support is implicit.
assert(hdr.e_entry > 0); // 実行可能な場合、エントリポイントの仮想アドレス。今回は実行ファイルのみサポート
assert(hdr.e_phnum > 0); // Program Headerは存在するはず

// TODO:ph Program Headerのp_type=1(LOAD)をメモリ上に展開


// Program Headerをみてメモリ上に展開
for(int i = 0 ; i < hdr.e_phnum ; ++i) {
Elf32_Phdr phdr = {};
ifs.read((char*)(&phdr.p_type), sizeof(phdr.p_type));
ifs.read((char*)(&phdr.p_offset), sizeof(phdr.p_offset));
ifs.read((char*)(&phdr.p_vaddr), sizeof(phdr.p_vaddr));
ifs.read((char*)(&phdr.p_paddr), sizeof(phdr.p_paddr));
ifs.read((char*)(&phdr.p_filesz), sizeof(phdr.p_filesz));
ifs.read((char*)(&phdr.p_memsz), sizeof(phdr.p_memsz));
ifs.read((char*)(&phdr.p_flags), sizeof(phdr.p_flags));
ifs.read((char*)(&phdr.p_align), sizeof(phdr.p_align));
// とりあえず PT_LOAD(1)だけ考えとく
if (phdr.p_type == 1) {
printf("[ElfLoader][LOAD] off:%08x vaddr:%08x paddr:%08x\n", phdr.p_offset, phdr.p_vaddr, phdr.p_paddr);
// p_offset : セグメント先頭へのファイル先頭からのオフセット
// p_vaddr : メモリ上の仮想アドレス
// p_paddr : 物理アドレスとして予約されている→使わない
// p_filesz : セグメントのファイルイメージのバイト数
// p_memsz : 仮想メモリイメージでのバイト数→filesz使うので不問
// p_flags : x/w/rフラグ→今回は無視
// p_align : セグメントのアライン
assert(phdr.p_align > 0);
// ifstreamの現在位置を保存しておく
auto current = ifs.tellg();
ifs.seekg(phdr.p_offset, std::ifstream::beg);
// Callbackの実装がしょぼいのでがんばって1byteずつ読むよ...
for(int i = 0 ; i < phdr.p_filesz ; ++i) {
char buf;
ifs.read(&buf, 1);
write(phdr.p_vaddr + i, static_cast<uint8_t>(buf));
}
ifs.seekg(current, std::ifstream::beg);
}
}
// おわり
ifs.close();
// EntryPointを返す
return hdr.e_entry;
}
}
}
2 changes: 1 addition & 1 deletion src/Reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ namespace sim {
this->pc = data;
}
void incr_pc() {
this->pc++;
this->pc += (XLEN / 8);
}
};
};

0 comments on commit 6bfd7dd

Please sign in to comment.