Материал: TextmetukSPO

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

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

MOV [имя_области + порядковый_номер_байта], значение байта

Например, заменить на символ @ шестой байт области с именем area, запишется на ассемблере как

MOV [area+4], '@'

Здесь следует обратить внимание на два важных момента. Первым в общечеловеческом понимании нумерации байтом этой области будет байт, обозначаемый как [area+0] или просто как [area]. Это "самый первый" или, точнее, начальный ее байт. Следующим по порядку – уже не начальным байтом – будет байт, обозначаемый как [area+1]. Поэтому [area+4] – это действительно пятый байт, поскольку для нумерации байтов используется в качестве базы отсчета не единица, а нулевое значение. Практически ситуация полностью соответствует использованию индексированных переменных, называемых также элементами одномерного массива в языке Си. Напомним, что после описания в этом языке имени area как массива, запись area[0] обозначает первый его элемент, запись area[1] – второй, и, в общем случае, area[n] обозначает (n+1)-й элемент этого массива.

Источник указанной особенности, "неудобной" для начинающих программистов, кроется как раз во внутреннем уровне программирования на машинных кодах и языке ассемблера. Он вытекает из того, что в машинных командах используется не составная запись, подобная [имя_области + порядковый_номер_байта], а уже приведенная служебной программой компилятора запись, которая на ассемблере или дизассемблере имеет вид [смещение]. Здесь элемент смещение является результатом выполнения промежуточных операций по вычислению действительного или эффективного (в зависимости от частной инженерной терминологии) адреса. Это смещение задает число байтов, на которое отстоит от начала сегмента данных элемент, подвергаемый операции в команде, использующей такой операнд. Каждое имя для области данных имеет свое значение, вычисляемое транслятором, и равное его смещению относительно начала сегмента области данных. Переход от [имя_области + порядковый_номер_байта] к форме [смещение] осуществляет транслятор путем сложения значения имени имя_области со значением порядковый_номер_байта. Поэтому [area+0] отвечает тому же смещению, что и начало области area, т.е. начальному (первому) байту. Значение вычисляемого смещения от записи [area+4] соответствует месту, на четыре позиции удаленному от начала области данных area, и это в обычной нумерации оказывается как раз пятый байт.

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

Второй, более мелкой особенностью, записи на ассемблере команды MOV [area+4], '@'

6

является необходимость включения в апострофы символа, который требуется переслать этой командой. Эта особенность может быть привычной для программирующего на языках высокого уровня. Но все же следует обратить внимание, что команда MOV [area+4], '7' помещает в восьмой байт области area символ цифры 7, а команда MOV [area+4], 7 помещает в восьмой байт этой области значение числа 7. Если обратиться к таблицам кодировки алфавитно-цифровых символов для используемого семейства компьютеров, а именно к таблицам кодировки ASCII, то можно увидеть, что шестнадцатеричным кодом цифры 7 будет код 37H, а для числа 7 соответствующий шестнадцатеричный код будет просто 07H. Таким образом, различие существенно не только по форме записи, но и по результату использования, от которого, как правило, будет зависеть дальнейшее поведение программы.

При программировании на языке ассемблера совершенно необходимо учитывать сегментную структуру программы, соотносимую реальной внутренней структуре исполняемых файлов современных операционных систем. Лишь упрощенное программирование для старой ОС MS-DOS позволяет ограничиваться одним сегментом. Во всех остальных используемых ОС требуется, как минимум, указывать отдельно сегмент данных и сегмент команд. Для этих целей предназначена директива ассемблера SEGMENT, имеющая в простейших случаях только один операнд – имя сегмента. По причине установления связей с другими компонентами системы программирования на этапе компоновки, в качестве стандартного имени для сегмента команд в Linux принято имя .text, включающее в качестве начального символа "точку" как специальный символ. Для сегмента данных в качестве стандартного принято имя .data. В этой же ОС для системного компоновщика, называемого ld, необходимо указать точку входа в выполняемую программу. С этой целью первая исполняемая команда, не обязательно первая по порядку записи, должна быть снабжена стандартной меткой _start, где символ подчеркивания входит в состав имени. Кроме того, это имя должно быть указано как доступное со стороны других программ, в частности, запускающей на выполнения, путем указания в качестве операнда в составе директивы GLOBAL.

Следует обратить особое внимание, что в директивах ассемблера, в частности, GLOBAL и SEGMENT, операнд должен отделяться от мнемокода директивы одним или более пробелом. Аналогичное требование относится и к командам. В них совершенно необходимо пробелом или пробелами отделять мнемокод и операнды. Если в языках высоко уровня разделителями содержательных частей операторов (обычно называемые в методах трансляции лексемами) могут служить вспомогательных символы – точки, знаки операций и т.п., то для сложившегося стиля построения и использования языков ассемблера это соглашение не всегда действует. Следует взять за правило, всегда разделять мнемокоды и операторную часть команд и директив ассемблера пробелами. Отклонение от указанного правила трансляторами нередко не контролируется и, впоследствии, приводит к неочевидным ошибкам поведения программ.

Весь лабораторный цикл, в той его части, где используется программирование на ассемблере, предполагает применения свободно распространяемого инструментального пакета программ nasm. Этот пакет включает как собственно компилятор, так и вспомогательный компоновщик alink.exe для операционных систем

7

Microsoft. Этот же компилятор входит в состав большинства инсталляционных пакетов Linux и во все, предполагающие профессиональное использование.

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

nasm –h

в командной строке. Дополнительная информация получается путем модификации опции согласно с условиями, выводимыми в первом варианте справочной информации.

Для Windows этот транслятор имеет модификацию имени в виде nasmw.exe. Все эти компиляторы являются многофункциональными и поддерживают форматы объектных файлов нескольких типов, пригодные для нескольких операционных систем. Обычно для "своей собственной" системы компилятор как исполняемый файл обеспечивает формат по умолчанию. В общем случае, этот формат задается опцией –f. Основными форматами, записываемыми символически в составе опции, для данного цикла лабораторных работ являются bin, obj, win32, elf. Первый из них производит безформатные односегментные файлы для операционной системы MS-DOS, а последний – для Linux. Кроме того, целесообразно использовать опцию принудительного задания имени результирующего файла, поскольку его именование по умолчанию имеет свои недостатки. Эта опция задается ключом –o, за которым должно следовать собственно название создаваемого файла. Для операционных систем Microsoft это название следует иметь расширение com (допустимо и использование расширения exe, но по традиции в MS-DOS исполняемые односегментные файлы должны иметь расширение именно com).

Таким образом, полная строка вызова транслятора в командной строке для исходного файла prog.asm будет записываться для MS-DOS как

nasmw –f bin -o prog.com prog.asm

В этой ОС для односегментной программы может не использоваться настройка компоновщиком и поэтому в нашем варианте этот вызов непосредственно дает исполняемый файл типа com.

Для Linux запись вызова компилятора в командной строке для аналогичного исходного файла с именем prog.asm будет иметь вид

nasm –f elf -o prog.o prog.asm

Результатом работы транслятора при отсутствии ошибок будет объектный файл prog.o, который необходимо превратить в исполняемый файл вызовом компоновщика в виде текста командной стоки

ld -o prog.exe prog.o

Если разработчику удобнее запускать исполняемый файл не через файловый менеджер типа MidnightCommander или подобный ему, то непосредственно в командной строке требуется задавать вызов в виде

./prog.exe

(Вначале точка, обозначающая текущий каталог, затем разделитель для указания далее имени исполняемого файла, и только потом собственное имя этого файла.)

Последнее, на что следует обратить внимание при выполнении работы, это запись инициализированных данных (исходных данных). Для формирования

8

отдельных информационных объектов в качестве простейших кирпичиков описания используются директивы DB, DW, DD. Первая формирует элементы размером в байт, вторая – размером в 16-битное слово, а последняя 32-битные элементы. При этом следует иметь в виду, что при задании элементов описания в виде шестнадцатеричного кода младшие цифры этого описания задают значения младших байтов области данных. Таким образом, описание

prim DD 123456H

поместит в начало области данных, обозначаемой именем prim, байт со значением 56H, в следующий байт поместиться значение 34H, а в старший байт, т.е. байт, который в программе можно обозначить как [prim+3], нулевое значение.

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

symmm DD 'abc'

в первый (начальный) байт области symmm запишет символ 'a', далее - символ 'b', а в последний байт этой области занесется нулевое значение.

Задание. Разработать на языке ассемблера программу для операционной системы Linux, которая должна выводить приглашение для ввода текста, вводить произвольный текст со стандартного ввода, изменять второй из введенных символов на восклицательный знак и выводить полученный текст на экран. Затем разработать на языке ассемблера программу для операционной системы MS-DOS, которая выводит четыре строки текста, причем первая и четвертые строки завершаются управляющими символами 13,10, вторая - только управляющим символом 13, а вторая строка завершается только управляющим символом 10. Объяснить результаты работы программы. Ввод и вывод обеспечить путем использования программных прерываний с соответствующим номером и помещением аргументов в требуемые для этого регистры.

Контрольные вопросы.

1.Как запустить на выполнение односегментную программу для MS-DOS, если в nasmw использовать формат по умолчанию?

2.Что получится, если при вызове системной функции записи на экран в MSDOS номер функции поместить в регистр EAX, а не в AH ?

3.Перепишите обращение к функциям MS-DOS через помещение аргументов исключительно в 32-битные регистры, не использую при этом 8-ми и 16-битные регистры.

4.Что выведет на экран программа, которая заносит в регистр ECX адрес области obl, в сегменте данных область описана как

obl DD 'A', 'B', 'C'

и запрашивается вывод трех символов.

Лабораторная работа №2

9

Содержание работы. Изучение ассемблерных средств условных и безусловных переходов в программе.

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

В простейшем случае, часть условие может формироваться одной отдельной командой, которая в мнемокоде ассемблеров обозначают обычно CMP. Эта команда имеет два операнда, которые сравниваются. Результат сравнения фиксируется в специальном регистре, который в архитектуре IA32 называется Eflags. Он содержит набор отдельных битов, называемых флагами, каждый из которых фиксирует результат сравнения или другой операции, устанавливающей эти флаги. Существуют отдельный флаг ZF для фиксации равенства нулю, что при сравнении равносильно равенстве сравниваемых операндов. Имеется отдельный флаг NF для отрицательности, равносильной тому, что первый из сравниваемых операндов меньше второго. Используется еще целый набор флагов, в частности, флаг CF фиксации наличия переноса при выполнении операции и т.д. Детальное знание этих флагов не требуется для современных программистов на ассемблере, поскольку их содержательное использование опирается на мнемонику команд

условного перехода.

Эти команды имеют в ассемблерах, сложившихся для архитектуры IA32, обозначение вида Jcc, где cc обозначает, в свою очередь, мнемонику кода условия (Condition Code). Например, команда JE, кратко обозначающая условный переход по условию равенства (equal), в фрагменте программы

CMP EAX, EDX JE metka1

обеспечивает переход к выполнению команды программы, помеченной меткой metka1, если перед выполнением команды JE metka1 оказывается, что содержимое регистров EAX и EDX равны. Само сравнение при этом выполняется командой CMP EAX, EDX, предшествующей команде условного перехода. Если же при выполнении программу содержимое этих регистров на указанный момент не равно, то процессор выполняет команду, непосредственно следующую в программе за данной командой условного перехода. Никакого "перехода" при этом не происходит, а выполняется естественная линейная последовательности команд, следующих в памяти компьютера одна за другой, как последовательность машинных кодов в аппаратной памяти компьютера.

Таким образом, команды условного перехода выполняют или не выполняют переход на указанную в них метку в зависимости от того, соответствует или нет указанное в них условие условию, зафиксированному флажками в регистре флагов.

Не всегда требуется явно выполнять команду CMP сравнения, поскольку большинство команд, преобразующих информацию, одновременно с этим форми-

10

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