Hello everyone who sees this question. I have a problem. First of all, I'm currently writing an ELF reader in my kernel and now I have one problem. This problem is in the strings. What I mean is that if we have two code snippets like the below one:
printf("HELLO\n");
And
char msg[10] = "HELLO\n";
printf(msg);
Only the second one will work in the executable program. This is not a problem with printf, I have fully tested this function. The difference is in the line: in the first example, "HELLO\n" will be located at the end of the ELF file, in the second - closer to the beginning. But I also checked what data is loaded into ELF_exe_buffer in first case - and the rows are loaded. I don't know why I am getting this error, please help. I attach the ELF reader code below (this function is based on elf reader code from amateur OS)
ELF reader (amateur OS) - 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));
}
Fixed by adding to CCFLAGS "-fpic" flag
The code is obviously wrong.
An
EX_EXECbinary will only run correctly if loaded at the linked-at address (the address in the.p_vaddrof the firstLOADsegment), but your code loads it into an arbitrary memory location (returned fromcalloc).For
ET_DYN, the code is even more wrong (unless the binary is a fully-staticET_DYN). In generalET_DYN(as well asET_EXEC) binaries require that you pay attention toPT_INTERPin them.If by that you mean that building
ET_EXECwith-fpicallows your code to run such binary successfully, that probably fixes some of the issues of runningET_EXECat a different address from where it was linked, but I doubt that fixes all such issues.