У меня есть общий вопрос c о GDT и G CC. Начали писать ядро ОС с целью изучения. В настоящее время я использую G CC для компиляции кода. В нескольких руководствах по настройке GDT одни и те же базовые адреса (0) и пределы (0xFFFFF) используются для сегмента кода и данных. Моя первая мысль о x86 newb ie была такова: если я использую разные базовые адреса и ограничения, это может быть дополнительной защитой.
Вот что я пробовал (сокращенно):
Сценарий компоновщика:
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 = .;
}
Я добавил символы для каждого раздела, затем написал простые функции Assembler , чтобы получить начальный адрес и размер для каждого раздела, который я вызывал в C:
Функции ассемблера (как пример):
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
Я использовал различные разделы для настройки кода и данных ( не показан в следующем фрагменте кода) в сегменте 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);
Загрузка с помощью инструкции ассемблера lgdt
работает. Но когда я делаю sh сегментный регистр с длинным прыжком, я получаю ошибку общей защиты ( # GP ). Итак, я изучил сгенерированный машинный код. Проблема заключается в том, что, когда я компилирую его с G CC с опциями по умолчанию, адрес перехода команды прыжка в длину не является правильным. Для перехода в нужное место требуется какой-то перевод адреса. Также сегменты данных используют неправильные адреса. Хорошо, я могу вместо этого использовать пейджинг, но даже если вопрос звучит глупо:
Возможно ли использовать разные сегменты для кода и данных с G CC или другими словами, может G CC обрабатывать разные сегменты? Я знаю, что в G CC есть аргумент PIC
, но еще не пробовал.