看到这个问题的大家好。我有个问题。首先,我目前正在内核中编写 ELF 阅读器,现在遇到一个问题。这个问题出在字符串上。我的意思是,如果我们有两个如下所示的代码片段:
printf("HELLO\n");
还有
char msg[10] = "HELLO\n";
printf(msg);
只有第二个可以在可执行程序中工作。这不是printf的问题,我已经充分测试了这个功能。区别在于行:在第一个示例中,“HELLO “将位于 ELF 文件的末尾,在第二个中 - 更接近开头。但我还检查了第一种情况下将哪些数据加载到 ELF_exe_buffer 中 - 并且加载了行。我不知道为什么我得到这个错误,请帮忙。我在下面附上了ELF阅读器代码(该功能基于来自业余操作系统的elf阅读器代码)
ELF 阅读器(业余操作系统)- https://github.com/queso-fuego/amateuros/blob/master/include/elf/elf.h
void* ELF_exe_buffer;
void* ELF_read(const char* path) {
struct FATContent* content = FAT_get_content(path);
if (content->file == NULL) {
kprintf("File not found\n");
return NULL;
}
char* file_content = FAT_read_content(content);
char* header_content = file_content;
Elf32_Ehdr *ehdr = (Elf32_Ehdr*)header_content;
if (ehdr->e_ident[0] != '\x7f' || ehdr->e_ident[1] != 'E') {
kprintf("\r\nError: Not ELF.\r\n");
free(file_content);
return NULL;
}
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
kprintf("\r\nError: Program is not an executable or dynamic executable.\r\n");
free(file_content);
return NULL;
}
Elf32_Phdr* phdr = (Elf32_Phdr*)(header_content + ehdr->e_phoff);
uint32_t mem_min = 0xFFFFFFFF, mem_max = 0;
uint32_t alignment = PAGE_SIZE;
uint32_t align = alignment;
for (uint32_t i = 0; i < ehdr->e_phnum; i++) {
if (phdr[i].p_type != PT_LOAD) continue;
if (align < phdr[i].p_align) align = phdr[i].p_align;
uint32_t mem_begin = phdr[i].p_vaddr;
uint32_t mem_end = phdr[i].p_vaddr + phdr[i].p_memsz + align - 1;
mem_begin &= ~(align - 1);
mem_end &= ~(align - 1);
if (mem_begin < mem_min) mem_min = mem_begin;
if (mem_end > mem_max) mem_max = mem_end;
}
uint32_t buffer_size = mem_max - mem_min;
uint32_t buffer_alignment = align - 1;
ELF_exe_buffer = calloc(1, buffer_size);
if (ELF_exe_buffer == NULL) {
kprintf("\r\nError: Could not malloc() enough memory for program\r\n");
free(file_content);
return NULL;
}
memset(ELF_exe_buffer, 0, buffer_size);
for (uint32_t i = 0; i < ehdr->e_phnum; i++) {
if (phdr[i].p_type != PT_LOAD) continue;
uint32_t relative_offset = phdr[i].p_vaddr - mem_min;
uint8_t* dst = (uint8_t*)ELF_exe_buffer + relative_offset;
uint8_t* src = file_content + phdr[i].p_offset;
uint32_t len = phdr[i].p_memsz;
memcpy(dst, src, len);
}
free(file_content);
FAT_unload_content_system(content);
return (void*)((uint8_t*)ELF_exe_buffer + (ehdr->e_entry - mem_min));
}
通过添加到 CCFLAGS“-fpic”标志来修复
这个问题出在弦上。
代码显然是错误的。
如果在链接地址(第一个
EX_EXEC
段的.p_vaddr
中的地址)加载,则LOAD
二进制文件将仅正确运行,但是您的代码将其加载到任意内存位置(从
calloc
)。
对于
ET_DYN
,代码更加错误(除非二进制文件是完全静态的ET_DYN
)。一般来说,ET_DYN
(以及ET_EXEC
)二进制文件要求您注意其中的PT_INTERP
。
通过添加到 CCFLAGS“-fpic”标志来修复
如果您的意思是使用
ET_EXEC
构建 -fpic
允许您的代码成功运行此类二进制文件,则可能会解决在与其链接的地址不同的地址运行 ET_EXEC
的一些问题,但我怀疑这一点解决所有此类问题。