Несколько вопросов начинающего

Тема в разделе "WASM.BEGINNERS", создана пользователем s3dworld, 6 окт 2010.

  1. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    По всей вероятности, $ -- это текущее значение счётчика размещения (аналог IP на время трансляции программы), а $$ -- базовый адрес текущей секции. Но я ФАСМом не пользуюсь, так что это лишь мои предположения.
     
  2. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    s3dworld
    Не забывайте, что вам понадобиться как минимум два сегмента кода и данных. Системный (ring0) и защищенный (ring3), а возможно еще и промежуточные уровни (ring1, ring2), хотя этими уровнями можно и не пользоваться.
    Еще не забудьте что в любом случае Вам ни куда не деться от заполнения таблицы векторов прерываний (если хотите использовать исключения и прерывания от железа, т.е. написать полноценную ОС)
    Только опять таки вы забываете про то, что страницы будут находиться в физическом адресном пространстве, а программы при этом будет исполняться в виртуальном адресном пространстве. Для каждой задачи проще формировать свое виртуальное пространство, которое может включать одни и теже страницы, но и уникальные страницы. Не стоит заморачиваться на работу с диском. Попробуйте вначала правильно написать менеджер страниц памяти (существующих).
    256 это программных прерываний (нулевое прерывание - прерывание деления на ноль), но также есть 16 аппаратных прерываний (по старой модели, PIC), или 24 аппаратных прерывания (в новой, IOAPIC) они проецируются на программные вектора прерываний. Исключения также проецируются на программные вектора прерываний, но в отличие от PIC или IOAPIC они жестко закреплены за номерами векторов (например за вектором 0 закреплено исключение деления на ноль, за вектором 1 закреплено трассировочное исключение)
    Исключения и аппаратные прерывания могут пересекаться, но это не желательно (т.к. кроме всего прочего за одним аппаратным прерыванием может быть закреплено более одного устройства)
    следующий вопрос
    $ - текущий адрес
    $$ - базовый адрес (задается в org, для бинарного файла)
    давайте посчитаем вместе
    пусть команда выполняется по смещению 0x00FF от начала файла
    и в начала файла стоит org 0x7C00, то получаем
    rb 510 - (($) - $$)
    подставляем значения
    rb 510 - ((0x00FF+0x7C00) - 0x7C00); не забывайте org добавляет базовый адрес ко всем смещениям
    считаем
    rb 510 - (0x00FF) => rb 255
     
  3. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    SII
    То есть если у меня дескриптор описывает сегмент кода с 0x00000000, длиной 11111111111111111111b, со включённой гранулярностью (G=1), то в CS я ложу селектор с индексом этого дескриптора в глобальной таблице дескрипторов (GDT). В реальном режиме я не мог ничего загрузить в регистр CS сам (MOV не работала), и как я тогда туда селектор затащу? Может получается, что мне просто нужно прыгнуть на 32-битный код и у меня в CS селектор сам загрузится? Но откуда ему знать какой селектор туда пихать (мало ли сколько я дескрипторов с кодом сделаю, ведь по идее я могу сделать чтобы они друг на друга накладывались, как он узнает-то). И описываю я дескриптор сегмента данных с 0x00000000, длиной 11111111111111111111b, со включённой гранулярностью (G=1), и в регистры DS и SS (да пока можно и в ES, FS и GS) загружаю селектор, где идёт индекс моего дескриптора из глобальной таблицы дескрипторов (GDT). Просто для выборки данных подключать какой-нибудь из регистров общего назначения (например EDX), для того чтобы сформировывать смещение [DS:EDX]. Так что ли? А для стека самому указать значение для регистров ESP и EBP. Так? Только не понимаю я немного разницы в их назначении. ESP - указатель стека, EBP - указатель базы для стека. Поясните что на что указывает и как изменяется при PUSH и POP.

    max7C4
    Спасибо! С $ и $$ стало понятно. Получается что с векторами прерываний такая же ситуация обстоит как с ОЗУ и устройствами компьютера - всё проецируется на одну адресную шину (размером 4 ГБ для x86). То есть из 256 прерываний мне нужно обработчик писать для всех, но именно прерываний для моей операционной системы останется 232 (256-24) прерывания (от 0x18 до 0xFF), которые я могу использовать как захочу? А первые 24 (от 0x00 до 0x17) мне нужно будет написать обработчики для обращения к устройствам? Или всё так-же, только немного сместить нужно диапазон (0 - деление на ноль, 1 - трассировка), то есть мне будет для операционной системы доступно только 230 прерываний (от 0x1A до 0xFF), и 24 прерывания для устройств (от 0x02 до 0x19)?
     
  4. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    1) через FAR JMP в статье Broken Sword - Процессор Intel в защищенном режиме #8 пример
    2) при помощи FAR CALL
    dw 1DFFh
    dd FarCall_Offset; call far [FarCall]
    ...
    FarCall_Offset dd 0
    FarCall_Selector dw ?
    3) при помощи FAR RETURN (RETF) предварительно поместив в стек содержимое для EIP и CS
    4) при помощи IRETD ("the IRET instruction pops the return instruction pointer, return code segment selector, and EFLAGS image from the stack to the EIP, CS, and EFLAGS registers")
    5) а также при помощи команд SYSENTER, SYSEXIT, INTn, INTO, INT3, BOUND (смотри здесь)
     
  5. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    s3dworld
    Исключений гораздо больше 2-х. Просто я для примера привел первые два, которые помню точно.
    Эту же таблицу с нормальным форматированием вы можете найти в 253665.pdf Intel® 64 and IA-32 Architectures
    Software Developer’s Manual vol. 1

    т.е. вектора с номерами:
    0-31 резервируются под исключения
    32-63 отводишь под аппаратные прерывания
    64-255 остаются системе
     
  6. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Mikl___
    Если честно, так особо и не понял на счёт перехода. Как то сложно.

    max7C4
    Спасибо! Про прерывания стало понятно.

    Я тут читаю книжку Микропроцессор i486 (Книга 1). Решил досконально всё изучить, то есть начал с самого начала и ничего не пропускаю. Дошёл до главы 1, пункта 3: 1.3. Форматы команд. В общем пока всё понятно. Табличка хорошая:

    [​IMG]

    Сразу понятно какой-регистр для чего используется. Но вот когда дошёл до формата команд, тут уже запутался.

    [​IMG]

    Судя по рисунку, минимальная инструкция для процессора может занимать 1 байт, а максимальная 16 байт (но мне кажется что-то я где-то слышал что максимум всего 15 байт). Так если сложить все префиксы, то получится 4 байта. Действительно ли такой префикс может быть?

    Далее в книге написано:

    [​IMG]

    А вот сама таблица:

    [​IMG]

    Я так и не понял описание чего это: первого байта инструкции, второго или же обоих. Но если сложить все поля вместе: 1+1+1+3+2+3+3+3+2+3+4 то получим 26 бит. 26 бит это больше 3 байт, но меньше 4 байт.

    Видимо оно не код команды, а несколько битов из кода команды (вроде бы 3 биты) и далее захватывает уже другие описания. Только вот после кода операции на рисунке показано что идёт байт mod r/m, который содержит в себе: mod, reg/ком и r/m. А в таблице показано отдельно reg и mod r/m (причём длина указана 2, запятая, 3). Я запутался. На рисунке показан байт sib, заканчивающийся описанием base и далее идёт смещение в команде. А в таблице после base идёт sreg2 и sreg3, для замены сегмента. Да и ещё какой-то tttn.

    Те кто разбираются в этом, помогите. Куда там что относится?
     
  7. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    s3dworld
    Я уже говорил выше: загрузить только регистр CS нельзя никакими средствами. Его загрузка выполняется только и исключительно вместе с загрузкой (E)IP, что выполняется любой командой дальнего перехода (JMP FAR, CALL FAR, RETF, IRET). Какие сложности?

    Префикс повторения используется только с командами строковых операций; поведение процессора при его появлении с другими командами непредсказуемо (на практике он игнорируется, однако этого может и не быть). Но у всех строковых команд никаких явных операндов нет, так что после кода операции никаких других байтов там нет. Ну а максимальная длина кода команды действительно ограничена 15-ю байтами -- даже в 64-разрядной системе команд, где ещё префикс REX добавился.
     
  8. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    Читайте внимательней. Часть кода операции может задаваться полями байта ModR/M, следующего за байтом (или байтами) кода операции.

    Да и, по большому, счёту, зачем Вам сейчас разбираться с точным кодированием команд? Навыки программирования от этого не улучшатся, а каши в голове прибавится (а её и так немало).
     
  9. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    SII
    Для создания своего ассемблера.

    Ну а биты w, d и s где находится? В коде операции или в байте mod r/m? Честно, совсем не понятно.

    Сказано точно, что если команда состоит из двух байт, то первый байт фиксированный, то есть если что-то и составлять, то во втором байте кода операции. А сам код операции, как я понимаю, может в себе хранить регистр для использования (в какой регистр предназначены данные). Ну и тут ещё есть байт mod r/m, где можно указать ещё два регистра. Вот я и не понимаю, это зачем вообще указывать аж три регистра процессору (один в коде операции, и два в байте mod r/m)?

    Да и sreg2 и sreg3, для замены сегмента и ещё какой-то tttn, они то где содержатся?
     
  10. Tronix

    Tronix Member

    Публикаций:
    0
    Регистрация:
    10 сен 2010
    Сообщения:
    122
    В младших 8086 можно было сделать тупо так: MOV CS,reg16/mem :) Фича была не документированная и в 286 уже вызывала invalid opcode.
     
  11. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    Tronix
    Там можно и pop cs сделать, а теперь (код команды 0x0F) это начало двухбайтных инструкций.
     
  12. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Нет. Даже наоборот лучше не делать. Чтобы не вносить путаницу в адресах. И лимит не 4 ^ 32, а в 2 ^ 32 - 1.

    После перехода в PM (mov cr0, eax) ты делаешь jmp CODE_SELECTOR:start32. А можешь сразу на 64-битный сегмент прыгать, но тогда уже должна быть включена страничная трансляция, настроен каталог страниц, включено 64-битное расширение и страничное расширение. Переход кодировать db надо только в старых ассемблерах. FASM их числу не относится.
    Все прерывания описывать не надо. Можно описать только те, что нужны - исключения и IRQ. А остальные заполнить 0. Тогда при обращении в ним произойдёт #GP. В ядре у вас вызовов неизвестных прерываний вообще быть не должно, а если это сделало приложение, то его надо прибить, потому что "программа выполнила недопустимую операцию". Поскольку сначала вы прерывания не обрабатываете надо сделать cli перед mov cr0, eax, а после настройки обработчиков - sti.
     
  13. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    Я пока хочу с защищённым разобраться. Ведь если в защищённом я разберусь, то в длинном ничего нового для меня не будет же?
     
  14. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Новым будет лишь отсутствие некоторых старых вещей и большее количество регистров.
    Переходят в PM так:
    Код (Text):
    1.     lgdt [gdtr] ; Загружаем адрес GDT
    2.     cli ; Изначально мы не можем обрабатывать прерывания - их надо запретить
    3.     mov eax, cr0
    4.     or al, 1 ; Установим бит 0
    5.     mov cr0, eax ; После этой команды мы уже фактически в PM. Только код 16-битный
    6.     jmp 8:start32 ; Дальний прыход. Им мы загружаем CS 32битным селектором
    7. use32 ; КОд уже 32 бита
    8. start32:
    9.     mov ax, 16 ; Селектор сегмента данных
    10.     mov ds, ax
    11.     mov es, ax
    12.     mov fs, ax
    13.     mov gs, ax
    14.     mov ss, ax
    15.     mov esp, XXX ; Если у нас SS не был 0, то ESP содержит неверный адрес и пока мы его не исправим пользоваться стеком нельзя
    16.     ; >> Ну вот мы и в PM <<
    17. ...
    18. ; Значение для GDTR
    19. gdtr:
    20.     dw 3 * 8 - 1 ; 3 дескриптора
    21.     dd gdt
    22. align 16 ; GDT полезно выравнивать на 16 байт - будет работать быстрее
    23. gdt:
    24.     dq 0 ; NULL
    25.     dq 0x00CF9A000000FFFF ; Сегмент кода с базой 0 и лимитом 4 ГБ
    26.     dq 0x00CF92000000FFFF ; Сегмент данных с базой 0 и лимитом 4 ГБ
    Чтобы разделить код ядра и пользователя надо будет описать ещё два сегмента - один кода, один данных - с DPL = 3.
    Выглядеть они будут так: 0x00CFF2000000FFFF (данные), 0x00CFFA000000FFFF (код).
     
  15. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    Вот строчка из кода:

    Код (Text):
    1. jmp 8:start32
    Не пойму что здесь означает цифра 8? Откуда она вообще берётся?
     
  16. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Это селектор сегмента кода.
    8 = 1 shl 3
    потому что сегмент кода имеет индекс 1. А индекс в селекторе начинается с 3-его бита
     
  17. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    Теперь понятно.

    Передо мной стоит главный вопрос, стоит ли писать свой ассемблер или нет. Формат команд мне полностью не понятен. А тупо копировать всё от FASM по командно (написал inc AX и получившийся код разбирать в HEX-редакторе) не соответствует моим планам. Я хочу разобраться как всё это строится, а не копировать готовое.

    Что самое главное - именно составление инструкций для процессора меня беспокоит. Всё остальное (препроцессор и прочее) это я на ура сделаю. Скажем так, для меня удобнее тогда было бы вести проект, когда всё своё.

    Есть ли у кого нормальная документация (подробная и желательно на русском языке) по поводу составления машинных инструкций для 16/32/64-битных команд? Или если кому не жалко времени, расскажи-те сами как всё это составляется.
     
  18. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    Слишком сложная и объёмная задача, так что особого смысла нет.
     
  19. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Прерывания в PM:
    Таблица прерываний является массивом дескрипторов прерываний. Каждый дескриптор описывает смещение обработчика, сегмент и атрибуты. Формат дескриптора таков:
    Код (Text):
    1. Слово - младшие 16 бит смещения
    2. Слово - сегмент
    3. Байт - зарезервировано. Должно быть ноль.
    4. Байт - Атрибуты.
    5. Слово - старшие 16 бит смещения.
    То есть можно описать дескриптор так:
    Код (Text):
    1. dw offset and 0xFFFF
    2. dw segment
    3. db 0
    4. db flags
    5. dw offset shr 16
    Флаги бывают разные. Для начала тебе пригодятся два - 0x8E и 0xFE. Первый обозначает прерывание, которое нельзя вызывать из кода на ring3, а второй - которое можно. 0x8E должны иметь прерывания IRQ, потому что приложения не должны иметь возможность сгенерировать ложные IRQ-прерывания, а 0xFE - системные вызовы - ведь их то приложения как раз должны мочь вызвать по команде int XX.
    Вот процедура, которая устанавливает обработчик с сегментом BX и смещением EAX на прерывание DL с атрибутами DH.
    Код (Text):
    1. set_int_handler:
    2.     push eax edi
    3.     movzx edi, dl
    4.     shl edi, 4
    5.     add edi, idt
    6.     stosw
    7.     mov ax, bx
    8.     stosw
    9.     xor al, al
    10.     mov ah, dh
    11.     stosw
    12.     shr eax, 16
    13.     stosw
    14.     pop edi eax
    15.     ret
    16. ...
    17.     mov eax, general_fault_handler
    18.     mov ebx, KERNEL_CODE32_SELECTOR
    19.     mov dh, 0x8E
    20.     mov dl, 13
    21.     call set_int_handler
     
  20. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    тут только терпение, словарь и маны интела или амд. самые первые и достоверные источники.