Материал: 775

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

•(sp) = (sp) - 2; значение sp уменьшается на 2;

•значение из источника записывается по адресу, указываемому парой

ss:sp.

 

Оперативная память

Оперативная память

 

 

0000:

 

0000:

0000

 

0000

 

 

 

 

 

Сегмент стека

 

 

Сегмент стека

ss:

 

 

 

sp

Операнд

sр

 

 

 

Вершина стека

 

 

Старая вершина стека

 

 

 

 

ffff

Дно стека

ss:

Дно стека

 

 

 

ffff

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Старшие адреса ОП

 

 

Старшие адреса ОП

 

 

а) до команды

 

 

б) после команды

 

 

push <операнд>

 

 

push <операнд>

Рис. 4.2. Принцип работы команды push

pop назначение – запись значения из вершины стека по месту, указанному операндом назначения. Значение при этом “снимается” с вершины стека.

Алгоритм работы команды pop обратен алгоритму команды push:

•запись содержимого вершины стека по месту, указанному операндом назначения;

•(sp) = (sp) + 2; увеличение значения sp.

46

5. ТИПИЧНЫЕ ОШИБКИ ПРИ ВЫПОЛНЕНИИ РАБОТЫ

5.1.Перечень часто встречающихся ошибок

5.1.1.В перечень таких ошибок входят: те же, что и в первой лабораторной работе (см. уч. пос., ч. 1):

–открытая процедура или открытый сегмент;

–программист забывает о возврате в DOS;

–программист забывает о стеке или резервирует маленький стек;

–вызывает процедуру, которая портит содержимое нужных регистров;

–неопределенные символические имена;

–повторное определение символического имени;

–неправильный порядок операндов;

–неправильное использование операндов;

–потеря содержимого регистра при умножении;

–не подготовлены регистры при делении;

–неправильное использование регистра после деления;

–потеря содержимого регистра при делении;

–неправильное использование регистров при преобразовании байта в слово и слова в двойное слово в командах cbw и cwd;

–применение команд преобразования cbw и cwd к беззнаковым данным;

–изменение отдельными инструкциями флага переноса;

–программист долго не использует состояние флагов;

–ошибки при использовании регистров:

а) 8- и 16-разрядные регистры для записи двух операндов одной команды;

б) 8-разрядный регистр указывается для работы со стеком; в) сегментные регистры прямо используются в арифметических

вычислениях, логических операциях или для непосредственной передачи данных;

г) сегментные регистры могут использоваться либо как источники операндов, либо как приемники операндов, но никак не одновременно;

– выход из диапазона адресов.

5.1.2. Кроме того, входят следующие ошибки:

–программист забывает об инструкции ret [4, с.100];

–генерация неверного типа возврата [4, с.101];

–ошибки при использовании условных переходов [4, с.106];

47

–перепутаны операнды в памяти и непосредственные операнды

[4, с.117];

–границы сегментов [4, с.118].

В каждом языке имеется свое множество ошибок, которые обычно очень легко сделать, но не всегда просто обнаружить. Не является исключением и язык ассемблера. Типичные ошибки, которые допускаются при программировании на ассемблере, и рекомендации, как можно их избежать, приведены ниже. Источники данной информации: [1], [4], [5], [6].

5.2. Открытая процедура или открытый сегмент [5, с.120–121]

Для каждой директивы proc должна быть записана соответствующая директива endp. Если директива endp пропущена или имя процедуры в записи endp записано неверно, ассемблер генерирует предупреждающее сообщение, что процедура не закрыта надлежащим образом. Точно так же директива ends должна быть задана для каждой директивы segment. Если директива ends пропущена или имя сегмента в ней указано неверно, генерируется предупреждающее сообщение, что сегмент открыт. Наиболее вероятной причиной ошибки является неверная запись имени сегмента или процедуры.

5.3. Программист забывает о возврате в DOS

Имеется несколько вариантов возврата в DOS. Правильно завершать работу будет, например, программа, использующая команду ret или функцию 4Ch (см. уч. пос., ч. 1).

5.4. Программист забывает о стеке или резервирует маленький стек

В большинстве программ для резервирования пространства для стека должна присутствовать директива определения сегмента стека (стандартная или упрощенная), и для любой программы должно быть зарезервировано достаточное пространство, чтобы его хватило для максимальных потребностей в программе – например, директивой db

(см. уч. пос., ч. 3).

Обычно выделяют стек размером 512 байтов.

Не требуется выделять стек в программах, которые предполагается преобразовать в файлы типа .com (см. уч. пос., ч. 3).

48

5.5. Вызов подпрограммы, которая портит содержимое нужных регистров

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

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

5.6. Неопределенные символические имена [5, с.121–122]

Неопределенные символические имена представляют собой тип ошибок, которые наиболее часто встречаются при программировании. ассемблер генерирует сообщение о такой ошибке, если имя не определено в поле метки какой-либо строки ассемблерной программы. Если имя определено в другой программе, то его следует определить как внешнее имя директивой extrn (external – внешний). Неправильная запись имени является наиболее вероятной причиной такой ошибки, особенно в тех случаях, когда используемые шестнадцатеричные константы записываются без начальной цифры (см. уч. пос., ч. 1).

5.7. Повторное определение символического имени [5, с.122–123]

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

5.8. Неправильный порядок операндов

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

mov ax,bx

рассматривать как ax := bx

5.9. Неправильное использование операндов

49

Вязыке ассемблера первый операнд всегда используется в качестве приемника (кроме синтаксиса АТ&T для UNIX и Linux, см. уч. пос., ч. 12). Операнд может быть записан в регистре общего назначения, регистре сегмента или ячейке памяти. При использовании непосредственных данных в качестве операнда-приемника

cmp З,al ; неправильная запись cmp al,3 ; правильная запись генерируется сообщение об ошибке.

5.10.Потеря содержимого регистра при умножении

Всинтаксисе инструкций mul и imul явно указываются только один из операндов и размер, а регистры, используемые в качестве операндаприемника, просто подразумеваются. Это приводит к тому, что легко можно упустить из виду использование какого-либо неявного регистра. Например, программист знает, что результат перемножения 16разрядного значения на 16-разрядную величину поместится в регистр ax,

ине учитывает, что содержимое регистра dx теряется Поэтому всегда нужно помнить о том, что при использовании инструкций mul и imul изменяется (не сохраняется) содержимое не только регистров al, ax или eax, но также и ah, dx или edx.

5.11. Не подготовлены регистры при делении

Распространенной ошибкой для случаев, когда делимое по размеру совпадает с делителем и размещено в al, ax или eax, является то, что программист не обнуляет регистры ah, dx, edx (см. уч. пос., ч. 1).

5.12. Неправильное использование регистра после деления

Не учитывается, что регистры ah и dx содержат остаток, и используют их в качестве старших разрядов частного (см. уч. пос., ч. 1).

Пример ошибочного использования регистра edx после деления учетверенного слова на двойное слово приведен в уч. пос., ч. 7.

5.13. Потеря содержимого регистра при делении

Потеря содержимого регистра при делении заключается в том, что теряется значение, помещенное в регистр до операции деления (значение регистров al, ah , ax, dx, eax, edx, помещенное в регистр до операции деления, теряется, т.к. в регистр будет помещено частное (в регистры al, ax, eax) или остаток от деления (в регистры ah , dx, edx), см. уч. пос., ч. 1 и 7.

50

Источник: https://studfile.net/preview/16406832/