Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ForSPOmetuk

.pdf
Скачиваний:
9
Добавлен:
06.02.2018
Размер:
199.58 Кб
Скачать

МИНИСТЕРСТВО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ Омский государственный технический университет

А.Н. ФЛОРЕНСОВ

ЛАБОРАТОРНЫЙ ПРАКТИКУМ ПО СПО

Методические указания

ОМСК 2013

1

УДК 681.3

ББК 32.973.73

Ф 73

Рецензент:

Составитель: Флоренсов А.Н.

Ф 73 Лабораторный практикум по СПО.

Метод. указ. – Омск: Изд-во ОмГТУ, 2013. – 32 с.

Предназначены для профессиональной подготовки бакалавров направления «Информатика и вычислительная техника» по дисциплине "Системное программное обеспечение".

Подготовлено кафедрой «Информатика и вычислительная техника» и одобрено редакци- онно-издательским советом ОмГТУ.

2

Лабораторная работа №1.

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

Предварительные сведения. Некоторые операционные системы, более дружественные к профессиональному разработчику, чем другие, позволяют ему доступ к системным функциям API через механизм программных прерываний. Этот вариант доступа практически доступен только в программировании на уровне языка ассемблера. Вместо вызова системной функции по имени, как в случае общего доступа к API функциям, здесь используется команда с мнемокодом INT, имеющая

вкачестве аргумента единственный операнд – номер прерывания. Это значение для архитектуры IA32 должно находиться в пределах от 0 до 255, причем конкретное значение выбрано разработчиками ОС. Сложившейся практикой в этой области разработок является использование общего номера прерывания (как бы общего номера входа), а детализация – какая именно функция API запрашивается - задается программистом в регистре.

Для ОС Linux в качестве указанного номера выбран 80H, а в однозадачной ОС MS-DOS, входящей в состав современных ОС от Microsoft, для большинства системных функций должен быть номер 21H. Указанные константы заданы в шестнадцатеричной системе, в форме принятой для большинства языков ассемблера с помощью префикса, который задается латинской буквой 'H'. Практической альтернативой такой записи является задание указанных констант в десятичной форме, что дает для них записи 128 и 33, соответственно. Следует учитывать, что в профессиональном программировании на ассемблере используется преимущественно шестнадцатеричная запись констант, что обусловлено выдачей системными программами дизассемблеров большей части своей информации именно в этой форме, поскольку она лучше соответствует побайтовому размещению информации в ячейках машинной памяти.

ВОС Linux номер системной функции должен быть помещен в регистр EAX, а

вMS-DOS – в регистр AH. Никакого семантического контроля над программистом средства программирования на ассемблере в большинстве ситуаций не имеют, поэтому следует быть особенно внимательным при задании подобной информации.

ВОС Linux номерами системных функций write, read и exit, служат, соответственно, 4, 3 и 1. Более обширный список системных функций вместе с их номерами, обеспечивающими доступ через программное прерывание INT 80H, дает файл unistd.h, размещаемый обычно в каталоге /usr/include/asm. Для 64-битных систем эта информация находится в файле unistd_32.h

ВОС MS-DOS номерами системных функций write, read и exit, служат, соответственно, 40H, 3fH и 2EH. Из-за практической неупотребительности этой ОС где-либо, кроме традиционного преподавания программирования на ассемблере в области операционных систем от Microsoft, другие системные функции MS-DOS заметного интереса для обучения уже не представляют и не приводятся.

3

Аргументы системных функций перед выполнением команды программного прерывания помещаются в регистры. Операционная система Linux использует систематический подход в таком размещении исходной информации. Согласно ему, информация задающая аргументы вызова системной функции, соответствующие прототипу функции на языке Си, помещается последовательно в регистры EBX, ECX, EDX, ESI, EDI. Причем для первого аргумента она помещается в регистр EBX, для второго аргумента - в регистр ECX, для третьего - в регистр EDX и т.д.

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

При вызове в ОС MS-DOS функций write, read, которые используют номера 40H, 3f H, значение хэндла должно быть помещено в регистр BX. Регистр DX служит при этом для передачи адреса буфера ввода или вывода, откуда выводятся или куда читаются данные. Регистр CX служит для передачи в системную функцию числа записываемых байтов или максимальное число запрашиваемых для ввода.

Прочитанное число символов при вводе системной функцией чтения (по значению хэндла открытого файла) помещается в Linux в регистр EAX, а в MS-DOS помещается в регистр AX.

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

MOV регистр, имя_области_данных

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

имя_области_данных + число.

Такая запись, по смыслу использования и по интерпретации компилятора с последующим выполнением в процессоре компьютера, задает место в памяти компьютера, которое на столько байтов находится дальше начала указанной в ней области данных, каково значение элемента число в ней. Так запись txt+5 обозначает место в области txt, отстоявшем от начала области на пять байтов.

Обращение к системной функции write в ОС Linux для записи пяти символов из области данных txt в стандартный вывод (т.е. в простейшем случае, на экран), бу-

4

дет таким образом записываться в виде фрагмента ассемблерной программы в виде

MOV EAX, 4

MOV EBX, 1 MOV ECX, txt MOV EDX, 5 INT 80H

Здесь в качестве хэндла стандартого вывода использовано постоянное для Unix подобных систем значение 1.

Аналогичное обращение к системной функции для вывода на экран в ОС MSDOS запишется в виде

MOV AH, 40H MOV BX, 1 MOV DX, txt MOV CX, 5 INT 21H

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

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

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

MOV [area+4], '@'

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

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

[имя_области + порядковый_номер_байта], а уже приведенная служебной программой компилятора запись, которая на ассем-

блере или дизассемблере имеет вид [смещение]. Здесь элемент смещение является результатом выполнения промежуточных операций по вычислению действительного или эффективного (в зависимости от частной инженерной терминологии) адреса. Это смещение задает число байтов, на которое отстоит от начала сегмента

5

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

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

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

является необходимость включения в апострофы символа, который требуется переслать этой командой. Эта особенность может быть привычной для программирующего на языках высокого уровня. Но все же следует обратить внимание, что команда 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.

6

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

Для Windows этот транслятор имеет модификацию имени в виде nasm.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

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

nasm в виде

–f elf64, задавая вызов компилятора для файла с именем prog.asm в

виде

 

nasm –f

elf64 -o prog.o prog.asm

Компоновщик вызывается при этом в прежней форме, обеспечивающей по умолчанию создание 64-битного исполняемого файла.

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

компилятора nasm в виде

–f elf32, задавая вызов компилятора для файла с

именем prog.asm в виде

 

nasm –f elf32 -o prog.o

prog.asm

Для возможности выполнения 32-битного исполняемого файла в 64-битной версии Linux при этом компоновщик вызывается с дополнительной опцией в виде

7

ld -m elf_i386 -o prog.exe prog.o

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

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

./prog.exe

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

Задание. Разработать на языке ассемблера программу для операционной системы 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

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

8

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

В простейшем случае, часть условие может формироваться одной отдельной командой, которая в мнемокоде ассемблеров обозначают обычно 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 сравнения, поскольку большинство команд, преобразующих информацию, одновременно с этим формируют и код условия. В частности, такими командам являются команды сложения, вычитания и логические команды. Именно после арифметических команд обычно используются мнемокоды JZ, JNZ, в то время как после команды сравнения более естественным является применение команд JE, JNE.

9

Для выполнения не следующей по записи в программе команды, а некоторой другой команды, отмеченной некоторой меткой, предназначена команда

JMP метка

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

Следует обратить особое внимание, что при использовании ассемблера nasm прямой способ адресации обязательно требует символов '[' и ']' в записи операнда.

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

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

1.Придумайте пример применения команд JB и JA для байтовых числовых данных, в котором использование соответствующих команд JL и JG приводит к ошибке.

2.Объясните, когда будет правильным использование команд условного перехода JE метка, а когда правильным будет использование подобных команд в форме JE NEAR метка.

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

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

Содержание работы. Изучение организации подпрограмм на уровне ассемблера и особенностей использования команд умножения и деления.

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

Сама подпрограмма на языке nasm оформляется очень просто. Она должна начинаться с метки, обозначающей первую команду подпрограммы, и ее действия должны завершаться командой RET. Команда RET обеспечивает возвращение действий выполнения программы, традиционно называемое возвратом управления, к тому месту, откуда была вызвана подпрограмма.

10

Соседние файлы в предмете Операционные системы