ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ АССЕМБЛЕРА
ПОД MS-DOS

1998 год
Новиков Максим Глебович.

Глава 5. Шестнадцатеричная система счисления

Шестнадцатеричная система счисления — это система, где десяток состоит, как ты уже, наверно, догадался, из 16 цифр. Недостающие цифровые знаки обозначаются первыми символами латинского алфавита. Вот что из себя представляет шестнадцатеричный счет: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11… Мы видим, что в этом десятке 16 одиночных цифр! «Зачем же нужно такое извращение?» — спросишь ты.

На прошлом занятии мы узнали, что по аппаратным причинам компьютер понимает только двоичные числа. Но они неудобны для записи на бумаге — слишком длинные. И тут на помощь приходит шестнадцатеричная система. Максимальное двоичное число, которое можно изобразить четырьмя знаками (пол байта) — это 1111 (десятичное 15). Максимальное шестнадцатеричное число, которое можно изобразить одним знаком — F (тоже десятичное 15). Отсюда следует, что шестнадцатеричная система компактнее двоичной ровно в 4 раза! Если бы мы использовали десятичную систему, то не достигли бы во первых такой компактности, а во вторых нам было бы значительно труднее переводить числа из нее в двоичную и наоборот.

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

Удобность 16-ричной системы я докажу на примере:

Запомним соответствие шестнадцатеричного десятка с двоичными числами:

Шестнадцатеричная Двоичная Десятичная
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
A 1010 10
B 1011 11
C 1100 12
D 1101 13
E 1110 14
F 1111 15

Теперь берем двоичное число любой длины (101001101101001010010100101010001011111101), и разбив его справа налево на четверки, быстро переводим в шестнадцатеричное:

10 1001 1011 0100 1010 0101 0010 1010 0010 1111 1101
2 9 B 4 A 5 2 A 2 F E

В итоге получилось шестнадцатеричное 29B4A52A2FE. Легко перевести это число и назад, в двоичное. Тем же способом. А теперь представь, как бы мы мучились, чтобы осуществлять переводы с десятичной (или любой другой) системой!

Теперь о записи шестнадцатеричных чисел. В шестнадцатеричном числе может не встретиться среди его знаков букв. Как же отличить его тогда от десятичного? При записи шестнадцатеричных чисел применяется два правила. Первое — на конце шестнадцатеричного числа ставится буква «h». Второе — если шестнадцатеричное число начинается с буквы, впереди ставится цифра «0».

Применяется шестнадцатеричная система довольно широко. Так, адреса памяти в компьютере нумеруются именно в шестнадцатеричной системе, поскольку сам компьютер может их нумеровать только в двоичной, а нам удобнее представлять двоичные числа именно в шестнадцатеричном виде.

Вот, пожалуй, и все, что мы должны знать о шестнадцатеричной системе счисления.

Глава 6. Программные процессы внутри компьютера

Я уже говорил, что компьютер работает только благодаря программам, команды которых выполняет процессор. Мы уже знаем, что программы хранятся в памяти. Эту память называют ОЗУ (Оперативное Запоминающее Устройство) или RAM (Random Access Memory [Память с Произвольным Доступом]). Процессор, взаимодействуя с этой памятью, не только считывает оттуда команды, но и записывает туда промежуточные данные. То, что процессор может записывать данные в память, открывает дополнительные возможности находящимся там программам видоизменять самих себя, перезаписывать себя на другие адреса, и т.п.

Но как же попадает программа в эту память? Ведь при выключенном питании память пуста, поскольку она попросту обесточена, и не может ничего хранить! В ней после включения компьютера по всем адресам сплошные нули!

Это так, но… часть адресов памяти сделана энергонезависимой, и программы, находящиеся там, не стираются при выключении питания. Они «прошиваются» в микросхемы один раз на заводе, и остаются там навечно… до первой ядерной войны… Поэтому при включении питания процессор автоматически обращается сразу к тем адресам, и начинает выполнение «прошитых» там команд. Программа, содержащая эти команды, называется BIOS (Basic Input/Output System [Основная Система Ввода/Вывода]), а память, хранящая ее, называется ПЗУ (Постоянное Запоминающее Устройство) или ROM (Read Only Memory [Память только для чтения]). Записать в эту память процессор ничего не может, а значит эта программа является нестираемой, и ее невозможно повредить. Таким образом вся память выглядит примерно так:

RAM BIOS Обычная RAM (ОЗУ) RAM экрана ROM BIOS (ПЗУ) Дополнительная RAM (ОЗУ)
0 000534h 0A0000h 0C0000h 100000h и выше

Мы уже знаем, что за адресацию отвечает двухбайтовый регистр IP, который может адресовать 0FFFFh байт памяти. Вся память же гораздо больше этого числа. Как же быть? Все очень просто. Процессор может видеть память как бы с двух разных расстояний: издалека — в виде отдельных 16-байтовых блоков, и изблизи, в виде отдельных байт. Для нумерации байт он использует, как мы уже знаем, регистр IP, а для нумерации 16-байтовых блоков — другой регистр — CS. Таким образом, полный адрес складывается из адреса блока и адреса байта. Как это происходит мы узнаем чуть позже, когда познакомимся с сегментами — 64-килобайтными блоками памяти, в пределах которых возможно осуществлять адресацию только посредством одного регистра IP. Нас мало будет интересовать регистр CS, адресующий сам сегмент, поскольку при программировании мы ограничимся одним сегментом.

Итак, задача программы BIOS примерно такая же, как у стартера автомобиля — запустить все остальное. BIOS заставляет процессор обратиться к специальному устройству постоянной памяти — жесткому диску. В этом устройстве информация хранится не в виде электрических импульсов, а в виде намагниченных областей на поверхности специального магнитного диска. Плюс этой памяти в том, что она хранит в сотни раз больше информации, не обнуляется при выключении питания, и позволяет стирать и перезаписывать информацию, а минус заключается в крайне медленной ее работе (в устройстве применены механические части, такие как привод считывающих головок и раскручивающиеся магнитные диски).

На жестком диске записано много разных программ, но самая главная программа, без которой не могут работать другие программы — это операционная система. Поэтому первым делом с помощью программ BIOS процессор копирует ее в память (в обычную RAM), и переходит на выполнение ее команд. На экране возникают окошки Windows или черный экран с командной строкой DOS…

Глава 7. Подпрограммы, прерывания, использование подпрограмм DOS и BIOS

Каждая программа состоит из более мелких подпрограмм, выполняющих какую-то определенную функцию (например, вывод символа на экран, считывание программы в память, и т.д.) Основная программа вызывает ту или иную свою подпрограмму для выполнения того или иного действия. Детально это происходит так: процессор встречает команду вызова подпрограммы, после чего считывает второй байт команды, являющийся начальным адресом подпрограммы, и запомнив адрес следующей команды, переходит на выполнение команд подпрограммы. Подпрограмма всегда заканчивается командой возврата из подпрограммы. Процессор после получения этой команды вспоминает запомненный адрес, и снова возвращается к нему, продолжая выполнение основной программы.

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

Такие подпрограммы называются прерываниями. Во время выполнения программы операционная система не удаляется из памяти, что и дает возможность другим программам пользоваться ее подпрограммами.

Кроме прерываний операционной системы существуют еще прерывания BIOS (ведь BIOS тоже находится в памяти, поскольку прошита там навечно). Причем прерываниями BIOS пользуется даже сама операционная система.

Таким образом, мы получаем довольно замечательную картину: большинство основных действий мы можем осуществить в своей программе, даже не выписывая десятки и сотни команд процессору, а просто вызвав соответствующее прерывание BIOS или DOS. Так мы и будем поступать на первых порах, пока нам не понадобится осуществлять различные извраты… :)

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

В процессоре, кроме пары адресных регистров (CS:IP), о которых я рассказывал выше, существует еще несколько регистров. По сути это области памяти, которые мы можем использовать в качестве переменных, то есть хранить там какие-то значения. Вот с помощью них и осуществляется передача параметров в подпрограмму. Сначала познакомимся с самыми главными регистрами. Их четыре AX, BX, CX и DX. С остальными мы познакомимся позже по мере необходимости.

Все четыре регистра имеют одинаковый размер — 16 бит (2 байта). В современных компьютерах эти регистры расширены до 32 бит, и называются EAX, EBX, ECX и EDX, но вся их ширина нам пока не понадобится, поэтому будем обращаться только к их 16-битным половинкам, используя их старые имена.

В свою очередь эти половинки состоят из двух частей, старшей — левой, и младшей — правой. Размер каждой — 8 бит, то есть 1 байт. К этим частям тоже можно обращаться по их именам. Старшая часть обозначается буквой «H» вместо «X» в названии регистра , младшая — «L». Например AX состоит из AH и AL, BX из BH и BL и т.д.

Половинки этих половинок размером в 4 бита называются тетрадами, но они уже не имеют собственных имен, и непосредственно к ним обратиться нельзя. Замечу, что также нельзя обратиться к старшей (левой) половине регистров типа EAX, но об этом позже.

Таким образом, перед вызовом прерывания (то есть подпрограммы) вывода символа на экран, нам надо сначала занести его код в определенный регистр, из которого в самой подпрограмме будет осуществлено чтение этого кода, после чего осуществить вызов прерывания. Аналогичным образом используются и другие прерывания, причем число используемых для передачи данных регистров может быть разным. Иногда, когда размера регистров не хватает, данные передаются через определенные участки памяти, а в регистрах просто указываются их адреса.

И еще один момент. Откуда такое странное название у обычной подпрограммы — «прерывание»? Иногда оно сбивает с толку. Ничего загадочного тут нет: процессор как бы прерывает выполнение основной программы, и переходит на выполнение подпрограммы. Отсюда и название, хотя практически это безусловный переход на другой адрес с последующим возвращением назад.

На этом мы пока закончим. За эти три занятия ты приобрел базовые знания, которые достаточны для того, чтобы вплотную заняться изучением программирования. На следующем занятии мы разберем механику написанной тобой на первом занятии программы, и продолжим изучение программирования на примере другой более сложной программы.

[Вернуться в начало]
Главы 3–4
Глава 8 [Оставить отзыв в гостевой]
Hosted by uCoz