赞
踩
MemoryManager
MemoryManager
的功能是为模拟器提供一个简单易使用的内存访问接口,必须支持任意内存大小、内存地址的访存,还要能检测到非法内存地址访问。事实上,这非常类似于操作系统中虚拟内存的机制。因此,MemoryManager
的内部实现采用了类似x86体系结构中使用的二级页表的机制。具体地说,将32位内存空间在逻辑上划分为大小为4KB(2^12)的页,并且采用内存地址的前10位作为一级页表的索引,紧接着10位作为二级页表的索引,最后12位作为一个内存页里的下标。
页表结构可以如下声明
uint8_t **memory[1024];
其中,memory
指向一个长度为1024的一级页表数组,memory[i]
指向长度为1024的二级页表数组,memory[i][j]
指向具体的内存页,memory[i][j][k]
可以取出内存地址为(i<<22)|(j<<12)|k
的一个字节。可以在需要的时候对memory
进行动态内存分配和释放。模拟器对memory
的一个访存过程的示例如下
uint8_t MemoryManager::getByte(uint32_t addr) {
if (!this->isAddrExist(addr)) {
dbgprintf("Byte read to invalid addr 0x%x!\n", addr);
return false;
}
uint32_t i = this->getFirstEntryId(addr);
uint32_t j = this->getSecondEntryId(addr);
uint32_t k = this->getPageOffset(addr);
return this->memory[i][j][k];
}
本模拟器的可执行文件加载部分采用了GitHub上的开源库ELFIO(https://github.com/serge1/ELFIO),由于这个库只有头文件,所以导入工程相当容易,相关头文件在include/
文件夹下。
使用这个库进行ELF文件加载相当容易
// Read ELF file
ELFIO::elfio reader;
if (!reader.load(elfFile)) {
fprintf(stderr, "Fail to load ELF file %s!\n", elfFile);
return -1;
}
加载ELF文件进内存的代码如下,直接按照ELF文件头的信息将每个数据段拷贝到指定的内存位置即可,唯一需要注意的是文件内数据长度可能小于指定的内存长度,需要用0填充。值得一提的是本模拟器在设计时并未考虑支持32位以上的内存,因为内存占用如此之大的用户程序是比较罕见的,在我们用的测试程序中不会出现这种情况。
void loadElfToMemory(ELFIO::elfio *reader, MemoryManager *memory) { ELFIO::Elf_Half seg_num = reader->segments.size(); for (int i = 0; i < seg_num; ++i) { const ELFIO::segment *pseg = reader->segments[i]; uint64_t fullmemsz = pseg->get_memory_size(); uint64_t fulladdr = pseg->get_virtual_address(); // Our 32bit simulator cannot handle this if (fulladdr + fullmemsz > 0xFFFFFFFF) { dbgprintf( "ELF address space larger than 32bit! Seg %d has max addr of 0x%lx\n", i, fulladdr + fullmemsz); exit(-1); } uint32_t filesz = pseg->get_file_size(); uint32_t memsz = pseg->get_memory_size(); uint32_t addr = (uint32_t)pseg->get_virtual_address(); for (uint32_t p = addr; p < addr + memsz; ++p) { if (!memory->isPageExist(p)) { memory->addPage(p); } if (p < addr + filesz) { memory->setByte(p, pseg->get_data()[p - addr]); } else { memory->setByte(p, 0); } } } }
最后,需要在模拟器初始化时手动设置PC的值。
simulator.pc = reader.get_entry();
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。