I have a generic question about the GDT and GCC. Have started to write an OS Kernel for the purpose of learning. Currently I use GCC for compiling the code. In several tutorials for setting up the GDT, the same base addresses (0) and limits (0xFFFFF) are used for code and data segment. My first thought as a x86 newbie was, if I use different base addresses and limits it's could be an additional protection.
Here is what I have tried (shortened):
Linker script:
ENTRY(_start)
SECTIONS {
. = 1M;
_kern_start = .;
.text ALIGN(4096) : {
_kern_text_start = .;
*(.multiboot)
*(.text)
_kern_text_end = .;
}
.rodata ALIGN(4096) : {
_kern_rodata_start = .;
*(.rodata)
_kern_rodata_end = .;
}
.data ALIGN(4096): {
_kern_data_start = .;
*(.data)
_kern_data_end = .;
}
.bss ALIGN(4096) : {
_kern_bss_start = .;
*(.bss)
_kern_bss_end = .;
}
.stack ALIGN(4096) : {
_kern_stack_start = .;
*(.stack)
_kern_stack_end = .;
}
.heap ALIGN(4096) : {
_kern_heap_start = .;
*(.heap)
_kern_heap_end = .;
}
_kern_end = .;
}
I added symbols for each section, then I wrote simple Assembler functions to get the start address and size for each section which I called within C:
Assembler functions (as example):
FUNCTION(_kern_text_get_addr)
pushl %ebp
movl %esp, %ebp
movl $_kern_text_start, %eax
leave
ret
FUNCTION(_kern_text_get_size)
pushl %ebp
movl %esp, %ebp
movl $_kern_text_start, %ebx
movl $_kern_text_end, %eax
sub %ebx, %eax
leave
ret
I used the different sections to setup the code and data (not shown in the following code snippet) segment in the GDT:
uint32_t base;
uint32_t limit;
base = _kern_text_get_addr();
limit = _kern_text_get_size() / 4096;
/* Kernel Code */
gdt_set_entry(&gdt[GDT_KERN_CODE], base, limit, GDT_ACCESS_EXEC |
GDT_ACCESS_SEGMENT |
GDT_ACCESS_RING0 |
GDT_ACCESS_PRESENT,
GDT_FLAG_SIZE |
GDT_FLAG_GRAN);
Loading with the Assembler instruction lgdt
works. But when I flush the segment registers with a long jump, I got a General Protection (#GP) fault. So I examined the generated machine code. The issue is when I compile it with GCC with default options the jump address of long jump instruction isn't correct. It needs some kind of address translation to jump to the correct location. Also the data segments use wrong addresses. Okay, I can use paging instead but even if the question sounds stupid:
Is it even possible to use different segments for code and data with GCC or in other words, can GCC handle different segments? I know there is the PIC
argument in GCC, but not tried it yet.