KIVСпасибо большое! Хорошее описание. Как я понял если использовать релоки, то в ядре должен быть, так скажем свой ассемблер, чтобы потом всё это дело скомпилировать?! Хотя может не так понял. Мне всё равно больше нравится позиционно-независимый код.
А какое смещение может быть для всех инструкций (то есть там сколько в обратном направлении, сколько в прямом)? Я тут эксперимент провёл, а разве обязательно mov на lea менять?
Вот например такую ситуацию описывал:
Я собираюсь писать драйвера для 64-битного режима работы процессора, то есть для L-Mode. буду использовать страничную адресацию (собственно иначе никак), где каждая страничка будет занимать 4096 байт (4 КБ). Вот и получается, что в системе может быть таких страничек 4503599627370496 штук (это 2 в 64 степени и затем разделённое на 4096). Вообще, правильнее было бы указать 68719476736 штук (это 2 в 48 степени и затем разделённое на 4096), так как для адресации используются только 48 младших бит. Вот и получается, что странички с абсолютным индексом ближе к 68719476735 будут отведены под ядро операционной системы. Ниже страничку будут с драйверами. А страничку с нулевого индекса будут заполняться кодом программ пользователя. Странички программ будут переключаться (CR3 регистр меняться), а вот странички с драйверами и ядром всегда будут статические.
Так вот, получается что фактически я могу драйвер запихать в любую из страничек в диапазоне от 0 до 68719476735 (пока забудем про программы и про ядро операционной системы). Ну а если драйвер занимает больше 4 КБ, то его уже в несколько подряд идущих страничек пихать. В общем драйвер никогда не знает где он будет сидеть. А при его загрузке в страничку, операционная система в своей служебной таблице будет помечать какой драйвер куда грузила. Предположим что мы поместили драйвер клавиатуры в страничку с индексом 10000. Ну а в самом драйвере будет такой вот код:
Код:
use64
org 0x0000000000000000
address_FunA dq FunA ; Смещение от начала драйвера до функции FunA
address_FunB dq FunB ; Смещение от начала драйвера до функции FunB
value dw 0x0000 ; Глобальная переменная драйвера
FunA:
mov AX,4
mov [value],AX
ret
FunB:
call FunA
ret
Ну и вот что произойдёт, когда, как я уже говорил, поместили драйвер в страничку с индексом 10000, и решили вызвать подряд обе функции?!
Ядро определяет куда оно загрузило драйвер, потом складывает это значение со значением смещения функции в драйвере и передаёт туда управление (ага, это будет 64-битный адрес). И что произойдёт в коде самого драйвера, когда будет вызвана функция FunA? Будет в страничке 10000 по смещению 16 записано число 4 или будет в страничку с индексом 0 по смещению 16 записано число 4?
Далее. Что произойдёт когда будет вызвана функция FunB? Потом она передаст управление на страницу 10000 по смещению 18 или на страницу 0 по смещению 18?
Вот что меня волнует. Я хочу чтобы все адреса в драйвере были относительными на все инструкции: mov, jmp, nz, ..., call. Но боюсь что будет не так.