2025-10-14
ELF文件的结构网上有很多教程,这里先只记录如何从ELF文件构建地址-函数名。
首先从ELF Header获取section header表的偏移,section header
Elf32_Ehdr header;
...
fread(&header,sizeof(ELF32_Ehdr),1,fp);
ret=fseek(fp,header.e_shoff,SEEK_SET);
接下来需要获取两个section header:.sym_tab和.str_tab。.sym_tab中类型为FUNC的表项就是我们想要的函数,对于32位的ELF而言,.sym_tab是Elf32_Sym数组,如果表项的st_info低4比特的值是2则说明该项类型为FUNC,表项的st_name就是该项的名字,st_name实际是表项名字的字符串首字符在.str_tab的索引。
首先把.str_tab保存下来,先扫描section header找到sh_type为3的项,该项的sh_offset即strtab在ELF文件中的偏移
for(int i=0;i<header.e_shnum;i++){read_cnt = fread(&sh,sizeof(Elf32_Shdr),1,fp);if(sh.sh_type==3)str = sh;
}
实际上我发现ELF中会存在多个sh_type等于3的项,现在暂时用sh_name等于9做进一步筛选。后续研究一下这些字符串表的区别。
找到strtab的位置之后先把里面的字符串复制出来
char* str_tab;
str_tab=(char*)malloc(str.sh_size);
ret=fseek(fp,str.sh_offset,SEEK_SET);
read_cnt=fread(str_tab,sizeof(char),str_sh_size,fp);
这样后面直接从这个数组获取函数名即可。
这里先理一下在am-kernels/tests/cpu_tests
中运行测试用例时发生了什么:首先am-kernels/tests/cpu_tests/
下的Makefile会调用abstract-machine
目录下的Makefile,这个Makefile会将测试用例编译成目标文件(使用riscv工具链),这个Makefile会调用abstract-machine/scripts/
目录下对应结构和平台的mk文件,在我做的这个选择中就是riscv32-nemu.mk。riscv32-nemu.mk会调用abstract-machine/scripts/platform/nemu.mk
,nemu.mk会调用nemu
目录下的Makefile,nemu
目录下的Makefile会调用nemu/scripts/native.mk
来构建nemu运行前面编译出的测试程序的目标文件。
讲义中提到如果实现的是riscv32,还需要从jal或者jalr中解析出跳转的目标地址,我的想法是直接检测pc的值不就可以了吗?
不好区分call和ret
ret是伪指令,实际是用jalr实现的。
【确认下c语言中位操作和逻辑操作的优先级】