Дневники чайника. Чтива 0, виток0

Вступление в суть.
День первый

Как бы нам начать, чтобы поняли даже чайники...

Персональный компьютер для выполнения приложений использует центральный процессор (иногда не один). Допустим, процессоры от i80386 до Core2, от AMD K5 до FX и т.п. Все эти процессоры позволяют выполнять одни и те же приложения (не считая исключений). Меня заинтересовал вопрос, как это получается?

Все перечисленные процессоры совместимы с архитектурой IA-32 (архитектура Интел 32бита). Архитектура - это прежде всего набор и формат команд данного процессора. Команды процессора иногда называют инструкциями.

Ещё я узнал, что каждая команда процессора имеет два представления:
- В виде машинной команды (цифровое представление).

Процессору подаются электрические сигналы, которые мы представляем как закодированные цифры.
- И в виде команды Ассемблера.

Поскольку человек не привык читать сплошные цифры, каждая команда имеет своё имя (имена) и формат.

Вот тут-то и начинается Ассемблер.

Это очень простой язык программирования, но проблема в том, что изучать его можно только узнав некоторые основы.

Кроме того, нужно принять несколько общих (для наших уроков) определений, которые я уложил в первую главу витка1.

Не читайте её сразу, если вы не любите рассказов о том, чего ещё не щупали!

Советую сделать так: прочесть виток0, потом прочесть его ещё раз, и когда вы почувствуете нужду (если вы её почувствуете), читайте определения со знанием дела.

Речь пойдет только об IA-32-совместимых компьютерах. И дело будет идти по направлению к Win7.

Ну что ж, теперь можно начать рассказ о плоской земле (без всяких там китов и мути :).

Первый вопрос, на который нужно найти хотя бы поверхностный ответ, это...
А что такое программа?

По-научному, ответ звучит слишком сложно и что главное - обобщённо.

Если говорить уж совсем детским языком, то программы для Intel-совместимого компьютера есть те циферки, которые получает процессор, чтобы выполнить заложенное в них.

Но вот вопрос, из чего состоят эти циферки?

Они состоят из машинных команд и данных, именно их исследование будет главной целью нашего путешествия.

Так выглядит запись типичной команды Ассемблера:

mov  EAX,12345678

Mov - это имя команды копирования. EAX - регистр процессора (в некотором роде переменная). А "12345678" - число (значение в команде).

Всё вместе мы называем командой Ассемблера.

Нулевой день путешествия

Что поражает - процессор выполняет миллиарды команд в секунду.

Команд в языке Ассемблер довольно много, но не бойтесь, в основном они очень просты. И большая часть кода программ построена на основных командах, их можно пересчитать по пальцам.

Юнга, приступим к практике.

В моих статьях практика всегда будет перед теорией.

Интересно то, что исполняемый файл (com или даже exe) можно писать в простом текстовом редакторе, вот сейчас и попробуем.

Эксперимент 00 (prax00.com)

Создайте файл (в FAR'e - Shift+F4). Дайте этому файлу любое имя с расширением "com" (простой тип исполняемых файлов). Допустим, файл будет называться prax00.com.

В этом файле можно напечатать несколько латинских ПРОПИСНЫХ букв "A" или русских ПРОПИСНЫХ букв "P". Или и то и другое, можно вперемешку.

Только русские "Р" должны быть в кодировке DOS. (в редакторе FAR'а нажмите несколько раз F8, когда сверху увидите 866 - это и означает, что включена кодировка IBM ASCII).

Всё должно быть без пробелов и Enter'ов - только английская буква "ЭЙ" и русская "ЭР". Ну, можете ещё для разнообразия накидать других латинских букв. :)

Сохраните файл (в FAR'e - F2).

! Не запускайте пока этот пример.

Единственное, что отличает prax00.com в данный момент от настоящей программы, - это отсутствие команды завершения программы. Её-то мы сейчас и добавим.

Нужно ввести два "волшебных" символа - двойную рамку и обычный пробел.

Как это сделать? Есть несколько способов:
Способ I. Можно просто ввести код символа с клавиатуры (Gambit, спасибо за идею). Чтобы получить символ двойной рамки, нажмите Alt, на калькуляторном блоке клавиатуры наберите "205" и затем отпустите Alt, должен появится символ похожий на "=".
Способ II. По F8 в Far'e переключитесь в кодировку 1251 и добавьте ПРОПИСНУЮ русскую "Н" (она в кодировке Windows1251 имеет тот же код 205).
Способ III (самый важный). Закройте редактор Far'a и откройте этот файл в Hiew'e (в командной строке наберите "Hiew32 prax00.com") или просто выберите файл в меню Hiew'a). Сейчас вы видите обычные буквы, но если нажмёте "F4" (Mode), то увидите байты в hex-виде. Примерно так это должно выглядеть:

00000000: 90 41 90 41-90 90 41 41-42 42 42 | РAРAРРAABBB

Переставьте курсор в конец кода и нажмите F3 (редактировать). Введите один байт "CD" и сохраните изменения в файл (F9).

Ну а с пробелом, надеюсь, вы и сами разберётесь =). Он должен быть сразу после символа двойной рамки (он же русская ПРОПИСНАЯ "Н", он же байт CD). Всё что будет после не имеет никакого значения, если хотите проверить, можете добавить туда свою подпись.

Вот вы и написали первую программу. Запустите её...

А чего вы хотели от нескольких букв?!

Если всё было сделано верно, то сообщения об ошибке появиться не должно. Но и интересного ничего произойти не может. Это пустышка.

Замечание: на Windows версий x64 (7/Vista/Server/XP) для запуска/отладки этого и всех последующих com-примеров нужна эмуляция DOS (читайте главу "На дорожку").

Давайте разбирать нашу белиберду по байтикам.

Опять откройте её в Hiew'e. Теперь нам нужно переключиться в режим дизассемблера (F4 два раза).

Код этой программы в дизассемблерном виде должен быть примерно таким:

prax00.com

Адреса    Маш.команды       Команды Асма     
          Байты             Имена    Операнды
00000000: 90                nop
00000001: 41                inc      cx
00000002: 90                nop
00000003: 41                inc      cx
00000004: 90                nop
00000005: 90                nop
00000006: 41                inc      cx
00000007: 41                inc      cx
00000008: 42                inc      dx
00000009: 42                inc      dx
0000000A: 42                inc      dx
0000000B: CD20              int      020

Позже мы всё разберём по винтикам.

Сейчас здесь есть только одна "полезная" команда "int 20".

0000000B: CD20           int     020

Для начала достаточно знать, что любая программа должна иметь завершающий код. Команда Ассемблера Int 20 как раз и завершает выполнение программы (в DOS-приложениях). Мы ещё не раз вернёмся к этому вопросу.

Не удивляйтесь, что я попросил набирать именно прописные буквы и обязательно в кодировке DOS. Дело в том, что для компьютера нет разницы: буква или команда, и то и другое - это всего лишь цифры.

Процессор воспринимает вовсе не русскую прописную букву "Р", а команду "nop". И то, что вы видели как латинскую "A", для него - это машинная команда, которая переводится в команду Асма "inc CX".

Я надеюсь, вы поняли, что буквы здесь вообще не причём. Когда вы в редакторе печатаете символы, в файл записываются цифровые значения, так, в кодировке IBM-ASCII русская буква "Р" имеет шестнадцатиричное значение 90 (hex-значение).

90hex (или 90h) - это цифровой код операции (опкод) команды NOP. Так что же делает "nop", спросите вы.

НИЧЕГО!
NOP - (No oPeration - нет операции)

Суть этой команды в ничегонеделаньи. Это очень полезная команда, ею можно пользоваться в разных ситуациях, вы сами потом поймёте, что она нужна.

А что такое inc CX?
Inc - это команда, которая увеличивает значение на 1 (INCrement - инкремент)

CX - регистр процессора (как я уже писал, в некотором роде переменная).

Всё, что я здесь рассказал, должно быть, очень трудно для первого знакомства с Ассемблером, но постарайтесь не думать о сложном и непонятном.


Единственный опыт, который вы обязательно должны извлечь из этого примера:
Нет различия между данными (то есть буквой) и кодом программы (то есть командами). Данные процессор не станет выполнять, только если получит специальный код перепрыгнуть через них или код прекратить программу вообще. А так различий нет, цифры они и есть цифры. Никто вас здесь не остановит, если вы захотите выполнять тот или иной участок кода или данных!


Точно таким же образом, как мы писали prax00.com, можно написать любую программу, только на это могут уйти годы. Мы же с вами со следующей главы, начнём осваивать более дружелюбные методы программирования. :)

Предполагаю кучу детских "почему" типа:
Почему нулей столько в адресе?
А почему тогда в настоящих программах обычно сначала идут буквы "MZ", потом некоторое количество закорючек и текст "This program cannot be run in DOS mode". MZ - это же буквы, а не команды, ведь так?

Нулей столько в адресе, потому что адресация памяти сейчас (win9x-XP) стала 32-битная, или, по-другому сказать, 4-байтная (подробнее позже). А MZ - это действительно данные, особый знак для того, чтоб ОСь точно знала, что это exe-программа, и сформировала её запуск в оперативной памяти так, как этого требует содержимое. У com-программ таких сложностей нет, они выполняются с младшего байта. Именно поэтому наши первые эксперименты будут с ком-файлами. Они ничем не хуже exe, есть, правда, несколько ограничений, таких, как размер программы 64Kb. Но это на самом деле очень много для Ассемблера. Очень много.

Можно, конечно, сразу отвечать на все такие вопросы, но их список будет расти, как снежный ком, с каждым новым ответом. В конце концов мы упрёмся в это:
90 здесь вовсе не девяносто, а сто сорок четыре. И CD20 означают вовсе не буквы CD и число 20.

Так что главный вопрос на сегодня - что такое hex и что такое байты?

Все учебники и уроки по ассемблеру начинаются с одной и той же темы. Системы счисления.

Bitfry

<<предыдущая глава     следующая глава>>

Вернуться на главную



- В колонке адресов Hiew для файлов 32- и 64-битных запускаемых форматов по умолчанию показывает виртуальное смещение, оно не соответствует номеру байта в файле. Но для других типов файлов в Hiew'e номер байта - это то, что мы видим в колонке адресов.

Что такое смещение, вы узнаете в следующем витке ;).

Hosted by uCoz