Статья ASM для х86. (1.0) Введение.

Всем привет!
Поскольку зарегистрировался на данном форуме, внесу и я свои 5-копеек в общую копилку статей. Занимаюсь по-большей частью ассемблером, то и статья на эту тему. Гуру в этой области прошу строго не судить, т.к. с изложением своих мыслей всегда имел проблемы. Поскольку пишу по-ходу дела и в свободное время, то между частями могут быть перерывы. Рассматривается работа процессоров x86 в двух режимах – реальном RM, и зашищённом РМ. Как и принято - начну издалека..

Часть 1. Общие сведения

1.1. Процессор и его регистры.


В компьютерной системе всё вращается вокруг центрального процессора CPU. Он работает под управлением какой-либо системы. Программист пишет инструкций, которые система помещает в память ОЗУ. В свою очередь процессор берёт инструкции из памяти в свои регистры, выполняет их, и помещает опять в память. Цикл повторяется до тех пор, пока пользователь не остановит программу.

CPU имеет огромное кол-во регистров, и только малая их часть предназначена непосредственно для выполнения кода – эти регистры назвали РОН, или регистры общего назначения: EAX, EBX, ECX, EDX и т.д. Гугл не напрягаясь выдаст кучу ссылок на их описание.

Но такая картина только снаружи процессора. Попав в контейнер процессорного ядра, все регистры переименовываются по типу R0, R1..RN, где N – нагрузка на процессор. Блок переименования ‘Rename’ ввели для параллельного исполнения инструкций на одном ядре процессора, и теперь не возникает путаницы, какому именно потоку принадлежит та или иная инструкция. На выходе из ядра, регистры опять приобретают свои имена EAX и прочие.

Кроме РОН, процессор имеет и следующие регистры:


  • Пять регистров-управления самим процессором CR0..CR4 (Control Registers);
  • Четыре регистра управления памятью GDTR, LDTR, IDTR, TR (Descriptor Table Registers);
  • Восемь регистров-отладки DR0..DR7 (Debug Registers);
  • Более 1000 специфических регистров MSR (Model-Specific Registers).

1.2. Формат и набор команд процессора х86.

Для начала, рассмотрим такой ассемблерный код в виндовом отладчике ‘DEBUG’..
Здесь командой а я ассемблировал некоторый код, который потом командой u дизассемблировал:

db_1.png


  1. Всё-что выделено голубым – это команды процессора. Общее их кол-во давно перевалило за 200, и в каждом процессоре появляются всё новые и новые. Забегая вперёд скажу, что львиная их доля никому не нужна, кроме самих AMD и INTEL - мы будем использовать из них всего штук 20-30.
  2. Выделенное красным – это операнды команд. Слева от запятой находится приёмник, а справа – источник, который может быть регистром, константой, или значением в памяти. Если операнд является значением в памяти, то он берётся в квадратные скобки (по крайней мере в fasm’e, самом ‘правильном’ ассемблере из всех). Здесь в ход идут регистры процессора.
  3. Выделенное зелёным – это инструкция ассемблера, т.е. команда с операндами. Именно её исполняет CPU.
  4. Ну и жёлтое это то, как видит инструкции процессор. Этот поток байт (каждая пара чисел) принято называть Operation-Code, или по нашему ‘Опкод’ инструкции.
Это в отладчике опкоды выстроены в более-менее приглядном виде, а в процессор они поступают непрерывным потоком. Тут возникает резонный вопрос: -“Как процессор в потоке байт отличает одну инструкцию от дугой?”. Оказывается очень просто. Внутренняя микроархитектура процессоров чётко регламентирована и придерживается определённых правил – иначе получим хаос. Процессор берёт первый байт из потока, и по нему вычисляет длину текущей инструкции. Например он знает, что опкод 0xb8 – это MOV AX. Поскольку в ассемблере операнды всегда должны быть равны по размеру (а АХ это 2-байта), значит после 0хb8 нужно взять ещё 2-байта – итого три. Красиво эту картину расписал К.Касперски в своей статье “Дизассемблирование в уме”.


1.3. Оперативная память ОЗУ.

Как упоминалось выше, для быстрого доступа к инструкциям кода, система считывает программу с жёсткого диска, в память ОЗУ. При этом, чтобы не забивать напрасно память, программа читается с диска не целиком, а кусками по 4 Кб – т.н. страницами. Когда процессор выполнит все инструкции этой страницы, процессор сгенерит исключение #PF (PageFault, ошибка страницы) и контроллёр-памяти сразу-же загрузит в память следующую страницу с диска, а отработанная отправится в утиль.

На такой подкачке страниц с диска, основана виртуальная память защищённого режима. Например, можно по-очереди отображать в одну 4-Кбайтную страницу физической памяти, хоть 1000 страниц с диска и создастся иллюзия, как-будто на машине установлено 8-16 Gb физ.памяти. Правда работать такая программа будет как черепаха, т.к. всё время будет уходить на замещение страниц.

Процессор соединяется с памятью 64-битной шиной, однако выбор ячейки на модуле памяти требует двумерного адреса, т.е. адреса-строки, и адреса-столбца. Такой адрес назвали DRAM-адресом. Преобразованием адресов занимается контроллёр-памяти. Он разбивает линейный адрес процессора на две составляющие, и засылает их логике DDR по очереди – сначала строку, потом столбец. Чтобы логика модуля поняла где-какой адрес, контроллёр подтверждает их стробами #RAS (row-address-strobe) и #CAS (column, столбец) соответственно. Время между этими стробами (задержка) входит в состав ‘таймингов памяти’ и известно под названием RAS-to-CAS Delay.

В плане расхода тактов, обмен с динамической памятью DDR для процессора операция слишком медленная. Поэтому, чтобы не обращаться к ней часто, проц за один раз загребает сразу по 64-байта данных, которые помещает в свой кэш. Такой обмен назвали пакетным, а длину пакета задаёт параметр BL контроллёра памяти. Он расшифровывается как ‘BurstLength’ и может принимать значения 2,4,8,16,Page. По сути - это счётчик повторов. На всех исвестных мне виндах BL=8, тогда при 64-битной (8-байтной) шине получаем пакет в 64 байта.

Другими словами, при любых обстоятельствах (хоть запись, хоть чтение) процессор обменивается с памятью только 64-байтными кэш строками ‘Cache-Line’ в независимости от того, нужен ему байт или двойное слово. Он никогда не станет запрашивать шину ради одного байта, ведь шина – это общий ресурс, который может быть занят, например если кто-то в данный момент использует прямой обмен с памятью посредством DMA. Информацию о размере своей кэш-линейки можете почерпнуть из программы CPU-Z.

Основной проблемой DDR-SDRAM является время доступа к ней. Связано это с тем, что запоминающая матрица её ядра собрана на крошечных конденсаторах, время разряда которых физически не способно превысить частоту в 200 МГц. На более высоких частотах, кондёры просто не успевают полностью разряжаться, что приводит к искажению данных.

Но DRAM дешёвая и отказываться от неё пока рановато. Поэтому инженеры пошли другим путём, и ввели понятие 2n-prefetch (предвыборка). Суть фишки - в увеличении числа линий-чтения с матрицы. N считается тут степенью двойки. Например, для DDR2 n=2, или 2^2=4 параллельные линии, для DDR3 получаем уже 2^3=8 линий, для DDR4 соотвественно 16. Предвыбранные (prefetch) данные накапливаются в промежуточном буфере, который через мультиплексор MUX может сливать информацию с ядра, на любой частоте. Таким образом удалось решить проблему века, придерживаясь опорной частоты запоминающей матрицы в 200 МГц:

ddr.png


Вообще идея использовать конденсаторы для хранения битов не совсем удачна, т.к. они имеют свойства со-временем разряжаться. Значит нужно периодически считывать с них заряд, и записывать его обратно. Этот процесс известен как ‘регенерация ячеек памяти’. До модулей DDR2 регенерацией строк занимался контроллёр-памяти, а начиная с DDR3 - функцию перенесли внутрь DRAM-чипов. Теперь проблема ушла на второй план и выполняется в фоне. Конроллёр просто выделяет чипам определённое время на регенерацию, которое (среди таймингов) числится в розысках под кличкой ‘tRP’:

ddr_0.png



1.4. Кэш-память процессора.

Другое дело кэш процессора, где в роли запоминающих элементов выступают не конденсаторы, а пара транзисторов, включённых по схеме триггера. Такой тип памяти получил название ‘статическая’ или SRAM. Тут не нужно регенерировать ячейки, на то она и статическая. Процессор получает доступ к ней мгновенно, т.к. его регистры собраны на таких-же триггерах. Ему без разницы от куда брать данные, с другого регистра или со-своего кэш – скорость практически одинакова, если не учитывать небольшие издержки на внутреннюю шину.

Процессор имеет трёхуровневую организацию кеш: L1, L2 и L3. Первые два уровня физически разделены пополам – половина для кода, половина - для данных. Кэш L3 является общим и имеет наибольшую ёмкость памяти. Внутри своего кэш, процессор хранит только действительно нужную информацию и ту, что может потребоваться в будущем (предварительная загрузка данных). Именно поэтому он читает из памяти не единичными байтами, а прихватывает с собой сразу и последующие 63. Практика доказала, что программисты пишут код последовательно и лишь иногда появляются циклы. Значит кэш-контроллёр действительно знает своё дело, раз читает инфу пачками.

Структура и работа кэш памяти - довольная обширная тема, которая потянет на отдельную статью. Только кэш поддерживается полностью на аппаратном уровне, и асм-программисту доступны лишь некоторые средства работы с ним - например полная его очистка, когда хотим получить время выполнения (профайл) определённого участка кода. Поэтому мы не будем копать в эту тему глубоко, а позже - двинемся дальше..
 
Последнее редактирование:

fuzzz

Green Team
03.02.2019
249
470
BIT
2
Не совсем понял про отладчик... Можно подробнее что за отладчик такой...
 

centr

Green Team
31.01.2017
408
477
BIT
0
Гугл конечно много чего расскажет, но лучше читать на месте и не прыгать с места на место, эта бегатня порядком отвлекает и сбивает мысли.
Лучше сделать небольшую сноску с описанием команд в спойлере, чем отправлять в гугль.
 

Marylin

Mod.Assembler
Red Team
05.06.2019
324
1 441
BIT
649
Можно подробнее что за отладчик такой...
Это встроенный в Win32 древний отладчик.
На Win64 его помоему нет (проверить не могу, у меня х32)

Лучше сделать небольшую сноску
Просто кому интересен асм, думаю как-минимум знаком уже с регистрами,
хотя согласен - ссылки отвлекают, и по-сути всю эту инфу можно найти в гугле.
 

centr

Green Team
31.01.2017
408
477
BIT
0
Просто кому интересен асм, думаю как-минимум знаком уже с регистрами,
хотя согласен - ссылки отвлекают, и по-сути всю эту инфу можно найти в гугле.
Честно, лет семь назад пытался вникнуть в тему асм, внимание заострил на tasm, но в данный момент из того что читал тогда, не помню ни чего, mov смещение, msg сообщение,jmp прыжок...
Остальное по нулям.

Если написано простым и понятным языком, описаны команды и приведены примеры, то учится гораздо легче, даже тем кто вообще не в теме асм может быть интересно.
 
  • Нравится
Реакции: dustver

fuzzz

Green Team
03.02.2019
249
470
BIT
2
Это встроенный в Win32 древний отладчик.
На Win64 его помоему нет (проверить не могу, у меня х32)


Просто кому интересен асм, думаю как-минимум знаком уже с регистрами,
хотя согласен - ссылки отвлекают, и по-сути всю эту инфу можно найти в гугле.
У меня Win10 х64 просто посмотрел нет такого отладчика вот это меня и сбило с толку. Потому как обычно у винды же WinDbg а тут консольный еще и с подсветкой. Это меня привлекло поэтому и интересуюсь что за отладчик такой...
 

CKAP

Green Team
10.06.2019
68
39
BIT
0
прошу строго не судить, т.к. с изложением своих мыслей всегда имел проблемы.

Да тебе\вам уже пора свою книгу писать, а не статьи..
В целом же все норм, это очень годный материал. Рад вашим строкам по данной теме.. Учу сабж сейчас по Ершову (ОЧЕНЬ МНОГО ОЧЕПЯТОК В КНИГЕ) , там вот этот дебугер кстати.

С чем лично я испытываю трудности при изучении АСМа, это понимания смещение, работа с памятью, и адресация.
По CPU боле менее все понятно.
 
  • Нравится
Реакции: Marylin

Marylin

Mod.Assembler
Red Team
05.06.2019
324
1 441
BIT
649
это очень годный материал.
спасибо.. значит не зря стараюсь.
это понимания смещение, работа с памятью, и адресация.
Когда мы говорим о смещении, то подразумеваем какую-то базу. Причём смещение может быть как в прямом, так и в обратном направлении от базы (если эта база не нулевая). Например известно, что по смещению 3Сh от начала исполняемого РЕ-файла (*.exe), лежит указатель на РЕ-заголовок (до него - это заглушка дос).

На скрине ниже, синим я обвёл этот указатель по-смещению 3Сh (см.адрес строки и столбца). По соглашению Интела 'BigEndian', если значение в памяти больше байта, то его нужно читать справа-налево. То-есть это значение на самом-деле будет не 0х80000000, а наоборот 0х00000080. Таким образом, по смещению 80h от базы (начала файла), я вижу выделенный красным РЕ-заголовок. Как-то так..

pe.png
 

PresetX

Green Team
18.01.2018
26
5
BIT
2
понимания смещение,..
На пальцах - mov ecx,[eax+4] смещение - цифры после плюса, адреса очень удобно хранить, отталкиваясь от базового, прибавляя для каждого нового 4 (если мы о четырехбайтной структуре).
Как-то так... Вот такого внятного ответа я ждал на свой вопрос пол месяца.
 
  • Нравится
Реакции: Crazy Jack и CKAP

ROP

Red Team
27.08.2019
327
663
BIT
149
Спасибо за эту замечательную статью, Marylin

Решил реверсом заняться. Нужно для начала ассемблер подтянуть. Ваши статьи хорошо помогают :)
 
  • Нравится
Реакции: fuzzz

Crazy Jack

Well-known member
08.07.2017
573
89
BIT
35
Все в кучу - и бублики и пирожки. ИМХО

На пальцах - mov ecx,[eax+4] смещение - цифры после плюса, адреса очень удобно хранить, отталкиваясь от базового, прибавляя для каждого нового 4 (если мы о четырехбайтной структуре).
Как-то так... Вот такого внятного ответа я ждал на свой вопрос пол месяца.
DWORD 4 bytes

Где про флаги?
Один из древнейших приемов основан на «поглощении» трассировочного прерывания отладчиком. Как известно, x86-процессоры имеют специальный trap-флаг (сокращенно TF). Когда он взведен, после выполнения каждой инструкции генерируется специальное отладочное прерывание, обрабатываемое отладчиком (если, конечно, он установлен и действительно отлаживает программу). В противном случае управление получает обработчик по умолчанию. В MS-DOS он представляет собой «холостую» заглушку, состоящую из одного лишь IRET, и выполнение программы не прерывается, а вот Windows возбуждает исключение, приводящее к появлению хорошо всем известного диалогового окна «программа совершила недопустимую операцию и будет закрыта».
 

SearcherSlava

Red Team
10.06.2017
943
1 261
BIT
206
  • Нравится
Реакции: ROP и Marylin
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!