playing around with some stuff today I happened upon a very weird thing. I'm linking my kernel as 64-bit ELF with a code segment and a data segment. But if the kernel contains absolutely no initialized data, the linker will generate a data segment with p_filesz == 0 (OK, that would be expected), and p_offset == 0 (and that was really not expected). I have BSS for days, but so far had no need of initialized data (I solved the problem for now by adding an initialized int, but that is a bit hacky) But with p_offset being zero, my memory zeroing code would actually zero out the ELF header, which leads to the entry point being overwritten with 0, leading to a fault shortly after the jump. Also, of course, a lot of the initial code of the kernel would be overwritten with 0, also likely leading to faults.
Anyone else see that? How can I prevent that? Here's the linker script:
Code: Select all
ENTRY(_kstart)
OUTPUT_FORMAT("elf64-x86-64")
PHDRS {
headers PT_PHDR PHDRS;
text PT_LOAD FILEHDR PHDRS;
data PT_LOAD;
}
SECTIONS {
. = 0xffffffff80000000 + SIZEOF_HEADERS;
.text : {
*(.text)
*(.text.*)
} :text
.rodata : {
*(.rodata)
*(.rodata.*)
}
/* Normally, the overlap between text and data section is handled by having
* two different pages for the last bits of text and the first bits of data.
* That way, if the last bits of text are overwritten, it won't affect the
* text that is actually used. Unfortunately, for the kernel this is not
* possible. The whole file is loaded into memory en bloc, so the same page
* would be mapped twice. Therefore, a write access to the writable page
* would end up being visible in the non-writable side of things. Therefore,
* we must actually page-align here.
*/
. = ALIGN(2M);
.data : {
*(.data)
*(.data.*)
} :data
.bss : {
*(.bss)
*(COMMON)
*(.bss.*)
}
}