- •Лабораторная работа №1
- •Знакомство с Assembler
- •Регистры процессора i8086
- •Представление данных
- •Представление команд
- •Метка: Мнемокод Операнды Комментарий
- •Адресация памяти
- •Запуск программы
- •Структура программы
- •Последовательность создания исполняемого файла
- •Отладка программы
- •Практические задания
- •Вопросы к защите
Представление данных
На самом нижнем уровне оперативную память можно рассматривать как массив битов. Один бит хранит значение 0 или 1. Но процессору неудобно работать с памятью на уровне битов, поэтому реально ОЗУ организовано как последовательность ячеек - байтов. Таким образом, наименьший доступный элемент памяти для процессора − это байт, а не бит.
В байте биты нумеруются справа налево от 0 до 7. Бит с номером ноль называется младшим, бит с номером семь – старшим. Каждому байту соответствует свой уникальный адрес, называемый физическим адресом.
Следующим по размеру элементарным понятием является слово. Слово состоит из двух байтов, младшего и старшего. Существуют также и двойное слово, и учетверенное слово (рис. 1).
Рис. 1. Представление данных
Интерпретация хранимого в памяти значения зависит от определенных условий, которые и придают ему смысл. Для примера допустим, что программа поместила десятичное число 65 в ячейку памяти по адресу 0. Теперь нулевой байт хранит последовательность битов 01000001, так как 65 в двоичной системе счисления это 01000001 (рис. 1). Между тем отладочная программа отразит его как 41, т.е. как шестнадцатеричное число (01000001 в шестнадцатеричной системе счисления это 41). Но если послать это число в память видеоадаптера как символ, то на экране появится буква А (в соответствие с кодировкой ASCII 01000001 соответствует символу А).
Так как информация хранится в памяти в двоичном виде, довольно часто приходится переводить двоичные числа в десятичные или шестнадцатеричные.
Чтобы перевести двоичное число в десятичное, просуммируйте десятичные эквиваленты всех позиций двоичного числа, в которых находится единица. Рассмотрим пример преобразования числа 00001001b:
Рис. 2. Преобразование двоичного числа в десятичное
|
В конце двоичных чисел принято добавлять «b», в конце шестнадцатеричных − «h», в конце десятичных ничего не добавляют. |
Большие двоичные числа почти невозможно прочитать, поэтому используют шестнадцатеричные числа, которые удобно преобразовывать и которые довольно хорошо воспринимаются при просмотре кода программы. Их используют и в языке ассемблера, и в отладочных программах для отображения двоичных данных. Каждое шестнадцатеричное число заменяет четыре двоичных бита, а два шестнадцатеричных числа представляют байт.
Рассмотрим пример преобразования двоичного числа 000101100000011110010100b:
Рис. 3. Преобразование двоичного числа в шестнадцатеричное
Каждая позиция шестнадцатеричного числа представляет степень числа 16, что используется при вычислении десятичного значения числа. Для преобразования шестнадцатеричного значения в десятичное необходимо умножить значение каждого разряда на соответствующий эквивалент, а потом их просуммировать. Рассмотрим пример преобразования шестнадцатеричного числа 3BA4h:
Рис. 4. Преобразование шестнадцатеричного числа в десятичное
Выше были рассмотрено преобразование двоичных чисел без знака. Такие числа используют все отведенные им биты для получения значения. Если на число без знака отводится один байт, то максимальное в этом случае значение будет равно 255 (28), если слово, то − 65535 (216).
Байт со знаком для получения значения использует только семь битов, так как старший бит зарезервирован для знака, при этом 0 соответствует положительному числу, а 1 − отрицательному, например:
знаковый
бит
Рис. 5. Отображение положительного и отрицательного числа
Чтобы не усложнять процессор, отдельный блок для реализации операции вычитания не делают; эту операцию выполняет также блок суммирования. Перед суммированием отрицательные числа преобразовывают в дополнительные. Это такое число, которое в сумме с исходным дает ноль. Например, десятичное число -10 будет дополнением к 10, так как 10+(-10)=0. Таким образом, вместо операции вычитания А-В процессор суммирует с положительным числом А дополнительное к В: А+(-В). Например, вместо того чтобы вычесть 10 из 20, процессор просто складывает число 10, записанное в дополнительном коде, и 20.
Чтобы получить число в дополнительном коде необходимо сначала инвертировать все биты (поменять нули на единицы и наоборот), а затем прибавить 1:
исходное число 00001010 10
инвертировать биты 11110101 инверсированное число
добавить 1 11110110 -10
Число со знаком из п разрядов может использовать только (п-1) бит для получения значения (см. табл. 1). Например, знаковый байт использует только семь битов. Тогда максимальное число, которое он может хранить равно 127 (27), а минимальное, записанное в дополнительном коде, равно (-128).
Таблица 1. Целые числа со знаком и без знака
Тип хранения |
Биты |
Диапазон |
байт со знаком |
7 |
от -127 до 128 |
байт без знака |
8 |
от 0 до 255 |
слово со знаком |
15 |
от -32768 до 32767 |
слов без знака |
16 |
от 0 до 65536 |
двойное слово со знаком |
31 |
от -2147483648 до 2147483647 |
двойное слово без знака |
32 |
от 0 до 4294967296 |
учетверенное слово со знаком |
63 |
от -9223372036854775808 до 9223372036854775807 |
учетверенное слово без знака |
64 |
от 0 до 18446744073709551616 |
Для хранения символьной информации используется схема кодирования символов, которая позволяет преобразовывать символы в числа и наоборот. Наиболее известная из них − ASCII (читается как «аски»), в которой каждому символу присваевается уникальный код, включая контрольные символы, используемые при печати и передачи данных между компьютерами.
Стандартный набор символов ASCII использует только 7 битов для каждого символа. Значения от 0 до 31 заняты служебными кодами, используемыми при печати, передачи информации и выводе на экран. В обычном режиме они не отображаются на экране (см. Приложение 1).
Добавление 8-го разряда позволяет увеличить количество кодов таблицы ASCII до 255. Коды от 128 до 255 представляют собой расширение таблицы ASCII. Эти коды используются для кодирования символов национальных алфавитов, а также символов псевдографики, которые можно использовать, например, для оформления в тексте различных рамок и текстовых таблиц. В Приложении 2 приведена Кодовая таблица 866 – MS-DOS, которой мы и будем пользоваться.
Строка символов размещается в соседних байтах памяти: код первого символа записывается в первом байте, код второго символа − во втором байте и т.д. Например, числовым кодам строки «АВС123» будет соответствовать последовательность значений 41h, 42h, 43h, 31h, 32h и 33h.
Теперь коротко рассмотрим, как в ассемблере выделяется память под переменные. Начнем с выделения самого маленького участка − байта (его вполне достаточно для хранения небольшого числа или одного символа). Выделяется байт с помощью специальной команды компилятору (иначе директивы) db, которая расшифровывается как define byte − определить байт. Например, строка
a db -122
выделяет один байт под переменную а и, кроме этого, помещает в эту ячейку памяти число (-122).
Строка
b db ‘*’
выделяет один байт под переменную b и помещает в эту ячейку памяти символ «*». Заметьте, что сам символ помещают в одинарные или двойные кавычки. Так как каждый символ имеет свой код, то директива
b db 02Ah
полностью эквивалентна предыдущему примеру (см. Приложение 1).
Для выделения памяти под строку так же используют директиву db
string db ‘abcd’
В этом случае будет выделено столько байт памяти, сколько символов указано в строке. Запись
string db ‘a’,‘b’,‘с’,‘d’
полностью эквивалентна предыдущему примеру.
Если же строка состоит из повторяющейся последовательности символов, например, «abcdabcdabcd», то можно воспользоваться конструкцией повторения dup:
string db 3 dup (‘a’,‘b’,‘с’,‘d’)
Если же требуется просто выделить байт под переменную и ничего в этот байт не записывать, то вместо значения указывается знак вопроса:
с db ?
аналогичным образом выделяется место и под строку
string db ?,?,?,?
Последний пример можно записать короче:
string db 4 dup (?)
Для выделения под переменную большего места − слова, двойного или учетверенного слова, используют соответственно директивы dw, dd и dq. Например,
d dw -1
e dd -1
теперь под переменную d выделено два байта, а под переменную e − восемь.
|
Имя переменной на самом деле указывает лишь на адрес ячейки, в которой хранится значение. Причем адресом строки считается адрес ее первого байта. |
