对于我正在编写的一个程序,我需要提取为risc-v arch编译的ELF二进制代码的指令。我尝试提取指令的方法如下:
void dumpCode(FILE *file, Elf32_Phdr *segm, Elf32_Ehdr *header)
{
char *fileptr;
struct stat statbuf;
int *opcode_ptr;
unsigned int i, vaddr, offset;
int fd = fileno(file);
if (fstat(fd, &statbuf)) {
fprintf(stderr, "[-] Error while stating the file!\n");
goto fail;
}
fileptr = (char *)mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (MAP_FAILED == fileptr) {
fprintf(stderr, "[-] Error mapping the file!\n");
goto fail;
}
offset = (0 == segm->p_offset ? header->e_ehsize + header->e_phnum * header->e_phentsize : segm->p_offset); // Mark 1
opcode_ptr = (int *)(fileptr + offset);
vaddr = (0 == segm->p_offset ? segm->p_vaddr + header->e_ehsize + header->e_phnum * header->e_phentsize : segm->p_vaddr); // Mark 2
for (i = 0; i < segm->p_filesz / 4; i++, vaddr += 4) { // Mark 3
unsigned char *opcode = getOpcode(*opcode_ptr++);
if (1 == disas(opcode, vaddr)) {
free(opcode);
break;
}
free(opcode);
}
munmap(fileptr, statbuf.st_size);
fail:
close(fd);
}
为了测试我的函数,我首先编写了一个简单的汇编程序:
.global _start
_start:
addi a0, x0, 1
la a1, str
addi a2, x0, 6
addi a7, x0, 64
ecall
addi a0, x0, 0
addi a7, x0, 93
ecall
.data
str: .ascii "Hello\n"
作为第二个测试文件,我写了一个不同的代码,这次是用C
#include <stdio.h>
#include <math.h>
int main(void)
{
printf("%.5f", sqrt(2.0));
return 0;
}
第一个测试文件已使用以下内容进行编译和汇编:riscv32-linux-gnu-as -o test1.o test1.s; riscv32-linux-gnu-ld -o test1 test1.o
第二个测试文件已经直接用gcc riscv32-linux-gnu-gcc -o test2 test2.c -lm
编译了。返回到 dumpCode 函数,我标记了三行。
1.第一行是文件中放置段的偏移量,如果它是0,如果我没有错,我需要添加(header-〉e_ehsize + header-〉e_phnum * header-〉e_phentsize)字节,以便在正确的位置开始转储。但是当我使用第二个测试文件时,它不起作用。第二个标记遵循与此相同的方法,提取正确的虚拟地址。
1.第三个标记放在for循环中,我用来迭代指令,但是使用(segm-〉p_filesz / 4)来计算二进制中存在的指令的确切数量,它给了我更多的指令。据我所知,额外的数据属于填充,但是我想知道当到达填充部分时,我是否可以停止处理数据。
如何计算需要从elf文件处理的正确字节数?如果该字节数包括填充,我可以忽略它吗?
1条答案
按热度按时间f0ofjuux1#
Source
这是错误的。文件非常具体:
数据从segm-〉p_offset开始。没有if或but。
如果您看到0,我怀疑这是因为段没有
PT_LOAD
标志,这意味着它根本不在文件中(文件中的偏移量没有意义)或因为段应该包含ELF头(因此偏移量0没有错误)。在CPU中,指令和非指令是没有区别的。每4个字节都可能是一条指令。甚至00000000也是一条指令。指令就是程序计数器指向的任何东西。你可以试着找出程序计数器可以指向哪里,但这等同于停机问题,因此是不可能的。