Ассемблер для процессоров Intel Pentium
Шрифт:
Флаги состояния также используются при анализе операций, результатами которых являются беззнаковые целые числа, целые числа со знаком и упакованные (BCD) целые числа. Если результатом операции является беззнаковое целое число, то установка флага переноса CF в 1 (перенос или заем) свидетельствует о выходе за пределы допустимого диапазона. Если результатом операции является целое число со знаком (двоичное дополнение числа), то об этом свидетельствует установка в 1 флага переполнения OF.
В случае если результат операции интерпретируется как число в формате BCD, то установка флага AF свидетельствует о возникновении переноса или заема. Флаг SF
При выполнении операций целочисленной арифметики с повышенной точностью флаг переноса CF используется командами adc (сложение с переносом) и sbb (вычитание с заемом) для того, чтобы учитывать перенос при переходе к следующей операции сложения или вычитания.
Флаги состояния используются командами условного перехода jCC (CC – код условия: eq, le, It, ne и т. д.), командами setСС, ТоорСС и cmovCC.
Флаги состояния процессора могут быть помещены в стек и извлечены из стека командами pushf, pushfd, popf, popfd. Кроме того, флаги могут быть загружены в старшую половину регистра АХ или извлечены из старшей половины при помощи команды lahf или sahf.
Перейдем к описанию регистра EIP – он содержит смещение в программном сегменте следующей выполняемой команды. Если в программе встречаются команды jCC, call, ret или iret, то содержимое регистра EIP может измениться произвольным образом – смещение следующей команды может быть как положительным, так и отрицательным. Содержимое регистра-указателя следующей команды не может быть изменено какой-либо инструкцией напрямую, хотя можно получить его содержимое, если выполнить команду call, а затем прочитать указатель на следующую команду, находящийся в стеке.
Регистр EIP можно модифицировать, опять-таки не прямо, а через стек, заменив адрес следующей команды. Естественно, перед этим следует выполнить команду call.
Прежде чем приступить к анализу команд ассемблера и способов обработки данных, нам необходимо рассмотреть модели памяти, с которыми может работать процессор. Модель памяти определяет способ организации программ и данных в памяти компьютера. В 32-разрядной архитектуре процессора Intel Pentium используются три модели памяти:
– плоская, или линейная, модель памяти (flat memory model) – память представляет собой непрерывное пространство адресов. Такое пространство адресов называется линейным. Программный код, данные, область стека располагаются в этом пространстве адресов. Адресное пространство в этой модели адресуется побайтно, а диапазон адресов равен 232. Схематично эта модель памяти показана на рис. 3.9;
Рис. 3.9. Линейная модель памяти
– сегментированная модель памяти (segmented memory model) – память состоит из трех отдельных пространств адресов, которые называются сегментами. При этом программный код, данные и стек размещаются в отдельных сегментах памяти. Для того чтобы обратиться к байту в памяти, программа формирует логический адрес, состоящий из адреса сегмента (селектора сегмента) и смещения. Программы, выполняющиеся в 32-разрядном режиме, могут использовать до 16 383 сегментов разного размера, каждый из которых может иметь размер 232 байт. Схема адресации для сегментированной модели памяти показана на рис. 3.10.
Рис. 3.10. Сегментированная модель памяти
Механизм преобразования адресов при использовании сегментированной
– модель реального режима адресации (real-address mode memory model) – это модель памяти, используемая в процессорах 8086. Данная модель памяти поддерживается для того, чтобы обеспечить совместимость с ранее разработанными 16-разрядными приложениями. В этой модели применяется механизм сегментации, причем максимальный размер сегмента не превышает 64 Кбайт. Максимальный размер линейного адресного пространства, доступного в этом режиме, равен 220 байт.
При разработке 32-разрядных программ на языке ассемблера обычно используется линейная, или плоская, модель памяти. Все примеры 32-разрядных процедур, приведенные в этой и последующих главах, разработаны с использованием этой модели. При 32-разрядной адресации операндов логический адрес состоит из 16-разрядного селектора сегмента и 32-разрядного смещения. При 16-разрядной адресации логический адрес состоит из 16-разрядного селектора сегмента и 16-разрядного смещения.
При выполнении любой программы процессор обращается к памяти, в которой хранятся команды и данные. Для доступа к данным необходимо каким-то образом определять их адрес в памяти. Способ формирования адреса операнда или метки перехода на другую команду называется режимом адресации, или адресацией.
Инструкции ассемблера включают самые разнообразные команды, работающие как с операндами, так и без них. Некоторые команды требуют явного указания операндов, в то время как другие используют операнды по умолчанию. Данные операнда-источника могут находиться в регистре, памяти, в порту ввода-вывода или задаваться непосредственно в инструкции. Операнд-приемник может располагаться в оперативной памяти, в регистре или быть портом ввода-вывода.
Для четкого понимания того, как осуществляется адресация данных, проанализируем способ образования адреса операнда. Адрес операнда формируется по схеме сегментхмещение. В зависимости от используемой модели памяти адрес переменной в памяти может формироваться как 16 : 16 или 16 : 32. Смещение операнда называется его эффективным или исполнительным адресом (Effective Address, EA).
Селектор сегмента можно указать явным или неявным образом. Обычно селектор сегмента загружается в сегментный регистр, а сам регистр выбирается в зависимости от типа выполняемой операции, как показано в табл. 3.2.
Таблица 3.2. Критерии выбора сегментного регистра
Процессор автоматически выбирает сегмент в соответствии с условиями, описанными в табл. 3.2. При сохранении операнда в памяти или загрузке из памяти в качестве сегментного регистра по умолчанию используется DS, но можно и явным образом указать сегментный регистр, применяемый в операции.
Пусть, например, требуется сохранить содержимое регистра ЕАХ в памяти, адресуемой сегментным регистром ES и смещением, находящимся в регистре ЕВХ. В этом случае можно использовать команду